/// <summary> /// Finds the shortest possible <see cref="ITrip"/> between two <see cref="ITown"/>s. /// </summary> /// <param name="railwaySystem">An instance of <see cref="IRailwaySystem"/>.</param> /// <param name="from">The <see cref="ITown"/> from where the trip begins.</param> /// <param name="to">The <see cref="ITown"/> to where the trip ends.</param> /// <exception cref="InvalidRouteException">Thrown whenever no <see cref="ITrip"/> between the two <see cref="ITown"/>s exists.</exception> /// <returns>The instance of the shortest <see cref="ITrip"/> found.</returns> public ITrip FindShortest(IRailwaySystem railwaySystem, ITown from, ITown to) { var shortestPath = new Dictionary <ITown, Route>(); var distances = new Dictionary <ITown, int>(); var actualTowns = railwaySystem.GetTowns() as List <ITown> ?? railwaySystem.GetTowns().ToList(); foreach (var town in actualTowns) { distances[town] = town.Equals(from) ? 0 : int.MaxValue; } if (from.CloneIfEquals(to, out var clonedFrom, $"{from.Name}_")) { actualTowns.Add(clonedFrom); distances[to] = int.MaxValue; distances[clonedFrom] = 0; } while (actualTowns.Count != 0) { // This is bad. Should use a Binary Heap instead, but .NET doesn't have one by default like Java's Priority Queue. var actualShortest = actualTowns.OrderBy(t => distances[t]).First(); actualTowns.Remove(actualShortest); if (distances[actualShortest] == int.MaxValue) { break; } if (actualShortest.Equals(to)) { var path = new Trip(from); while (shortestPath.ContainsKey(actualShortest)) { path.AddRoute(shortestPath[actualShortest]); actualShortest = shortestPath[actualShortest].From; } return(path); } foreach (var route in actualShortest.Routes) { var actualDistance = distances[actualShortest] + route.Distance; if (actualDistance >= distances[route.To]) { continue; } distances[route.To] = actualDistance; shortestPath[route.To] = route; } } throw new InvalidRouteException($"There's no such route from '{from}' to '{to}'."); }