Best route: 7, 5, 6, 2, 10, 4
Tastiness metric: 2.8945153290979557
Total distance travelled: 33.51165531060739
Total tastiness: 97
I computed the distances between each node once and stored the results in a two dimensional array [to, from].
I used a simple approach to traversal by treating decimal integers as expressions of the routes and just iterating through them from 0 to 98765432, skipping any with repeated digits, and adding a leading 0 where appropriate. (0 = node ten.)
using System.Drawing;
var crawler = new TacoCrawler();
crawler.ShowBestCrawl();
public class TacoCrawler
{
readonly int[] _tastinessArray;
readonly double[,] _distances;
int _bestTotalTastiness = 0;
double _bestMetric = 0;
string _bestRoute = "";
double _bestRouteDistance = 0;
public TacoCrawler()
{
_tastinessArray = InitializeTastinesses();
_distances = InitializeDistances();
}
public void ShowBestCrawl()
{
var startedAt = DateTime.Now;
for (var n = 0; n < 100000000; n++) // Iterate through every route expressed as a number with up to eight digits. Filter out any with the same digit twice.
{
var routeString = n.ToString();
if (!CheckForRepeatedDigits(routeString))
{
ComputeTastiness(routeString);
if (n < 10000000 && !routeString.Contains('0')) // If the route doesn't contain 0 (node 10) and includes fewer than 8 nodes, also check starting from 0 .
{
routeString = "0" + routeString;
ComputeTastiness(routeString);
}
}
}
var finishedAt = DateTime.Now;
var timeTaken = finishedAt - startedAt;
Console.WriteLine("Best route: " + PrettifyRouteString(_bestRoute));
Console.WriteLine("Tastiness metric: " + _bestMetric.ToString());
Console.WriteLine("Total distance travelled: " + _bestRouteDistance.ToString());
Console.WriteLine("Total tastiness: " + _bestTotalTastiness.ToString());
Console.WriteLine("Computation time (s): " + timeTaken.Seconds);
}
static double GetDistanceBetweenPoints(Point p1, Point p2)
{
return Math.Sqrt((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));
}
// Check if the string contains more than one instance of any character.
static bool CheckForRepeatedDigits(string iString)
{
for (var j = 0; j < iString.Length - 1; j++)
{
if (iString[(j + 1)..].Contains(iString[j]))
{
return true;
}
}
return false;
}
static string PrettifyRouteString(string route)
{
var prettyRoute = route[..1];
for (var i = 1; i < route.Length; i++)
{
prettyRoute += ", " + route[i];
}
prettyRoute = prettyRoute.Replace("0", "10");
return prettyRoute;
}
// Compute the distances between each node and store the results in a 2d array [from,to]. An additional element in the to category is used to store the distance between the node and the origin.
static double[,] InitializeDistances()
{
var locations = InitializeLocations();
var distances = new double[10, 11];
for (var from = 0; from < 10; from++)
{
for (var to = 0; to < 10; to++)
{
distances[from, to] = GetDistanceBetweenPoints(locations[from], locations[to]);
}
distances[from, 10] = GetDistanceBetweenPoints(locations[from], new Point(0, 0));
}
return distances;
}
static int[] InitializeTastinesses()
{
var tastinessArray = new int[]
{
18, // 10 = 0
7,
17,
8,
30,
12,
15,
5,
12,
3
};
return tastinessArray;
}
static Point[] InitializeLocations()
{
var locationArray = new Point[]
{
new Point(14, 13),
new Point(2, 8),
new Point(15, 3),
new Point(6, 6),
new Point(20, 15),
new Point(11, 2),
new Point(14, 1),
new Point(7, 3),
new Point(1, 12),
new Point(3, 6)
};
return locationArray;
}
void ComputeTastiness(string routeString)
{
// Get the distance to and tastiness of the first node.
var firstNode = int.Parse(routeString[0].ToString());
int currentRouteTotalTastiness = _tastinessArray[firstNode];
double currentRouteDistance = _distances[firstNode, 10];
// Get the distance to and tastiness of every subsequent node
for (var i = 0; i < routeString.Length - 1; i++)
{
var from = int.Parse(routeString[i].ToString());
var to = int.Parse(routeString[i + 1].ToString());
currentRouteDistance += _distances[from, to];
currentRouteTotalTastiness += _tastinessArray[to];
}
var totalTastinessMetric = currentRouteTotalTastiness / currentRouteDistance;
if (totalTastinessMetric > _bestMetric)
{
_bestMetric = totalTastinessMetric;
_bestRoute = routeString;
_bestRouteDistance = currentRouteDistance;
_bestTotalTastiness = currentRouteTotalTastiness;
}
}
}