Example #1
0
        /// <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}'.");
        }