/// <summary> /// Builds an <see cref="IPath"/> instance based on the provided <paramref name="railwaySystem"/> and <paramref name="townsNames"/>. /// </summary> /// <param name="railwaySystem">An instance of <see cref="RailwaySystem"/>.</param> /// <param name="townsNames">An <see cref="string"/> array with the sequence of towns that constitutes the <see cref="IPath"/>.</param> /// <returns>An instance of <see cref="IPath"/>.</returns> public IPath Build(IRailwaySystem railwaySystem, params string[] townsNames) { var path = new Path(); foreach (var townName in townsNames) { path.AddStop(railwaySystem.GetTownByName(townName)); } return(path); }
/// <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}'."); }
/// <summary> /// Writes the expected program outputs to the stdout. /// </summary> /// <param name="railwaySystem">An instance of <see cref="IRailwaySystem"/>.</param> private static void WriteOutput(IRailwaySystem railwaySystem) { var tripService = new TripService(); var pathBuilder = new PathBuilder(); Console.WriteLine(); SafeWriteOutput(1, () => tripService.ResolveDistance(pathBuilder.Build(railwaySystem, "A", "B", "C")).ToString()); SafeWriteOutput(2, () => tripService.ResolveDistance(pathBuilder.Build(railwaySystem, "A", "D")).ToString()); SafeWriteOutput(3, () => tripService.ResolveDistance(pathBuilder.Build(railwaySystem, "A", "D", "C")).ToString()); SafeWriteOutput(4, () => tripService.ResolveDistance(pathBuilder.Build(railwaySystem, "A", "E", "B", "C", "D")).ToString()); SafeWriteOutput(5, () => tripService.ResolveDistance(pathBuilder.Build(railwaySystem, "A", "E", "D")).ToString()); Console.WriteLine($"Output #6: {tripService.Search(railwaySystem.GetTownByName("C"), railwaySystem.GetTownByName("C"), trip => trip.Stops > 3).Count()}"); Console.WriteLine($"Output #7: {tripService.Search(railwaySystem.GetTownByName("A"), railwaySystem.GetTownByName("C"), trip => trip.Stops > 4, trip => trip.Stops == 4).Count()}"); SafeWriteOutput(8, () => tripService.FindShortest(railwaySystem, railwaySystem.GetTownByName("A"), railwaySystem.GetTownByName("C")).TotalDistance.ToString()); SafeWriteOutput(9, () => tripService.FindShortest(railwaySystem, railwaySystem.GetTownByName("B"), railwaySystem.GetTownByName("B")).TotalDistance.ToString()); Console.WriteLine($"Output #10: {tripService.Search(railwaySystem.GetTownByName("C"), railwaySystem.GetTownByName("C"), trip => trip.TotalDistance >= 30).Count()}"); Console.WriteLine(); }