コード例 #1
0
ファイル: Graph.cs プロジェクト: MaerF0x0/Trains-CSharp
 /// <summary>
 /// Get all exiting edges from startNode
 /// </summary>
 /// <param name="startNode"> Start node to find all edges from </param>
 /// <returns> an array of edges which are adjacent to the startNode</returns>
 public Edge[] GetAdjacentNodes(Node startNode)
 {
     return
         (from edge in Edges
          where edge.Start.NodeName == startNode.NodeName
          select edge).ToArray<Edge>();
 }
コード例 #2
0
ファイル: RouteFinder.cs プロジェクト: MaerF0x0/Trains-CSharp
        /// <summary>
        /// Finds all cycles starting (and ending) at Node start, with a maxLength over the cycle
        /// Because this does a very brute force approach, be smart about how large of a graph and maxLength given
        /// Runtime will be something like (big "O") O(NumEdges ^ (maxLength/MinLength))
        /// </summary>
        /// <param name="start"> Node start (and end) of the cycle. </param>
        /// <param name="maxLength"> int maximum length of the cycles to find </param>
        /// <returns> The number of cycles found </returns>
        public int CyclesShorterThan(Node start, int maxLength)
        {
            // This should use the bellman ford algorithm
            // But, given all edges are atleast 1 unit long, we can just get all 30/Min(Edge Lengths) step routes,
            // filtering out the ones which are longer thand 30 cost and those which dont end on the start node (non-cycles)
            // inefficient computationally, but saves coding time :)

            // Find the smallest edge
            var minEdge =
                (from edge in RouteMap.Edges
                 orderby edge.Distance
                 select edge.Distance).First();

            // Find all routes with a number of edges of maxLength/minEdge
            // ie, MaxLength = 25 and MinEdge = 5, we can find upto 5 stop routes.
            var routes = getSteps(start, maxLength / minEdge, false);

            // filter out the ones which dont end on our start (non-cycles)
            var cycles =
                (from route in routes
                 where route[route.Length - 1] == start.NodeName
                 where route.Length > 2 // Must have more than just the starting location
                 where RouteDistance(route) <= maxLength
                 select route).Distinct().ToList(); ;

            return cycles.Count;
        }
コード例 #3
0
        ///<summary>
        /// Takes a string to convert to a graph according to instructions
        /// Utilizes fluent interface
        ///</summary>
        ///<param name="input"> the source string to build the graph from</param>
        public GraphBuilder BuildFromString(string input)
        {
            // General pattern expected.
            string pattern = "([A-E][A-E][0-9]{1,9}(( )?,( )?)?)+";

            // Disregard Malformed input, you wiley recruiters you...
            Match match = Regex.Match(input, pattern);

            // If you're not being tricksy
            if (!match.Success)
            {
                Console.WriteLine("Malformed input detected. Aborting.");
                return null;
            }

            // Split on the comma
            pattern = "[\\s]*[,][\\s]*";
            String[] tokens = Regex.Split(input, pattern);

            Dictionary<char, Node> nodeDictionary = new Dictionary<char, Node>(tokens.Count());
            foreach (String token in tokens)
            {
                Node node1 = new Node(token[0]);
                Node node2 = new Node(token[1]);

                // Ensure we dont add nodes more than once.
                if (!nodeDictionary.ContainsKey(token[0]))
                {
                    nodeDictionary.Add(token[0], node1);
                }

                if (!nodeDictionary.ContainsKey(token[1]))
                {
                    nodeDictionary.Add(token[1], node2);
                }

                nodes = nodeDictionary.Values.ToList();
                // Dont have to check edges so stringently
                // Email said: "For a given route will never appear more than once, and Node1 will != Node2"
                edges.Add(new Edge(node1, node2, int.Parse(token.Substring(2))));
            }

            //Save the source of this graph.
            source = input;

            return this;
        }
コード例 #4
0
ファイル: RouteFinder.cs プロジェクト: MaerF0x0/Trains-CSharp
        /// <summary> 
        /// Returns a path starting at start, a maximum depth (number of stops) of maxDepth
        /// will only return strings of exactly maxDepth if exactLentgh is true
        ///</summary>
        /// 
        /// <param name="start"> The starting node for the route </param>
        /// <param name="maxDepth"> The maximum length (number of stops) of the route </param>
        /// <param name="exactLength"> return only exaclt maxDepth sized routes? </param>
        /// <returns> A list of routes that match the invoked criteria </returns>
        public List<string> getSteps(Node start, int maxDepth, bool exactLength)
        {
            // So far returning nothing.
            List<string> retVal = new List<string>();
            if (maxDepth == 0)
            {
                // Stop here and Return.
                retVal.Add(start.ToString());
                return retVal;
            }

            // Need to go deeper! get Adjacencies
            Edge[] adjacent = RouteMap.GetAdjacentNodes(start);
            foreach (Edge edge in adjacent)
            {
                // Step deeper to build the path
                List<string> subGraphs = getSteps(edge.End, maxDepth - 1, exactLength);

                // For each Subgraph, mark that we were "here"
                foreach (string graph in subGraphs)
                {
                    retVal.Add(start.NodeName + "-" + graph);
                }

                // Add this < maxDepth length path
                if (!exactLength)
                {
                    retVal.Add(edge.Start.NodeName.ToString());
                }
            }

            return retVal;
        }
コード例 #5
0
ファイル: Dijkstra.cs プロジェクト: MaerF0x0/Trains-CSharp
        /// <summary>
        /// Implements a modified Djikstra's Algorithm to find Min routes from Node start
        /// Also has the ability to search for a Cycle if bool findCycle is true
        /// </summary>
        /// <param name="start">Node to start search from, also the end node if finding cycles</param>
        /// <param name="findCycle"> Should we find cycles or just find all other nodes?</param>
        /// <returns> Returns a dictionary giving the distance and route from Start to the key in the dictionary</returns>
        public Dictionary<char, Tuple<int, string>> GetMinRoutes(Node start, bool findCycle)
        {
            // So that we dont count it a million times
            var count = graph.Nodes.Count;

            // We want to keep track of distances, which we've visited, routes. And eventually return a formated value
            Dictionary<char, int> distances = new Dictionary<char, int>(count);
            Dictionary<char, bool> visited = new Dictionary<char, bool>(count);
            Dictionary<char, string> routes = new Dictionary<char, string>(count);
            Dictionary<char, Tuple<int, string>> retVal = new Dictionary<char, Tuple<int, string>>(count);

            // Initialize to default values
            foreach (Node n in graph.Nodes)
            {
                distances.Add(n.NodeName, Int32.MaxValue);
                routes.Add(n.NodeName, start.NodeName.ToString());
            }

            // We're not coming back here, so assume distance of 0
            if (!findCycle)
            {
                distances[start.NodeName] = 0;
            }

            // Copy the Edges list so this function doesnt have side-effects
            var edges = graph.Edges.ToList();

            // Start from our start position.
            var current = start;

            // We want to visit every node if possible (see "break;" below)
            while (visited.Keys.Count < count)
            {
                // Skip adding the start node once, so that we'll return to it again.
                if (findCycle)
                {
                    // But from now on, track which we've visited
                    findCycle = false;
                }
                else
                {
                    visited.Add(current.NodeName, true);
                }

                // Check each edge for a better route
                foreach (Edge edge in graph.GetAdjacentNodes(current))
                {
                    // Never check this edge again.
                    edges.Remove(edge);

                    // If we dont have a route, or if we've found a better route
                    if (distances[edge.End.NodeName] == Int32.MaxValue
                        || distances[current.NodeName] + edge.Distance < distances[edge.End.NodeName])
                    {
                        if (current.NodeName == start.NodeName)
                        {
                            distances[edge.End.NodeName] = edge.Distance;
                        }
                        else
                        {
                            distances[edge.End.NodeName] = distances[current.NodeName] + edge.Distance;
                        }
                        routes[edge.End.NodeName] = routes[current.NodeName] + "-" + edge.End;
                    }
                }

                // Figure out all nodes which are adjacent to the currently visited nodes
                List<char> adjacencies = new List<char>();

                adjacencies = adjacencies.Union(
                        graph.GetAdjacentNodes(current)
                        .Select(edge => edge.End.NodeName)).ToList();

                foreach (char n in visited.Keys)
                {
                    adjacencies = adjacencies.Union(
                        graph.GetAdjacentNodes(new Node(n))
                        .Select(edge => edge.End.NodeName)).ToList();
                }

                // Select the node with the lowest distance, and hasnt been visited
                current =
                    (from KeyValuePair<char, int> pair in distances
                     where pair.Key != current.NodeName
                     where !visited.Keys.Contains(pair.Key)
                     where adjacencies.Contains(pair.Key)
                     orderby pair.Value
                     select new Node(pair.Key)).DefaultIfEmpty(null).First();

                // There are maybe nodes left, but they're not accessible
                if (current == null)
                {
                    break;
                }
            }

            // Build our return value.
            foreach (KeyValuePair<char, string> pair in routes)
            {
                retVal.Add(pair.Key, new Tuple<int, string>(distances[pair.Key], pair.Value));
            }

            return retVal;
        }
コード例 #6
0
ファイル: Edge.cs プロジェクト: MaerF0x0/Trains-CSharp
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="start">starting point of this directed edge</param>
 /// <param name="end">end point</param>
 /// <param name="distance">Distance or cost of this edge</param>
 public Edge(Node start, Node end, int distance)
 {
     Start = start;
     End = end;
     Distance = distance;
 }