Ejemplo n.º 1
0
        /// <summary>
        /// Perform a Breadth First Search on the graph, given a station to start at, and a destination. This function will always find a path
        /// (and currently prints it out to the console and returns true) if the graph is connected, however, the path is not (guaranteed to be)
        /// optimal.
        /// 
        /// Because Breadth First Search is primarily a search algorithm, and not a path finding algorithm, some extra functionality has been added
        /// to the graph, namely the wrapping of GraphNode objects in PathNode objects, which contain a linked-list style reference from a node to
        /// it's previous node, to enable a backtrace once the destination is found. This backtrace returns the path taken to the node that is found
        /// and is the desired output of this function. The return value needs to adjusted a JSON object that contains this path.
        /// </summary>
        /// <param name="start">The station to start at.</param>
        /// <param name="end">The station to end at.</param>
        /// <returns>At this stage, true = found, false = not found (and generally means an error has occurred, probably in the creation
        /// of the graph structure, and probably with the format of the input data).</returns>
        public bool BFS(Station start, Station end)
        {
            // this dictionary contains PathNode pairs, a node and it's previous node, to determine the path
            // a PathNode contains a GraphNode and the name of the line that was used when passing the node.
            Dictionary<PathNode, PathNode> path = new Dictionary<PathNode, PathNode>();

            // FIRST CHECK IF THE start NODE EXISTS
            GraphNode root = null;
            bool found = false;
            foreach (GraphNode n in graph) // first check if the station is in the graph
            {
                if (n.name == start.Name)
                {
                    root = n; // store this node as the root node to begin BFS with
                    found = true; // the station does exist
                }
            }
            if (found == false) // the station does NOT exist, return
                return false;
            // END CHECK IF start NODE EXISTS

            // BFS PROPER
            Queue<PathNode> queue = new Queue<PathNode>(); // pathnode stores the line as well as the node
            List<string> visited = new List<string>(); // this list contains the name of ALL nodes that have been visited.

            queue.Enqueue(new PathNode(root.name, "", root)); // enqueue the root node (starting point)
            visited.Add(root.name); // and mark it as visited (this list keeps track of visited nodes so they don't get visited again)
            path.Add(new PathNode(root.name, "", root), null); // no line given to PathNode just yet

            while (queue.Count > 0) // while the queue is not empty, we still have nodes to check
            {
                PathNode check = queue.Dequeue(); // dequeue the next node

                if (check.node.name == end.Name) // if this is the end node, we are done
                {
                    //Console.WriteLine("FOUND IT!! Start {0} End {1}\n", start.Name, end.Name); // print a message

                    PathNode curr = check, prev; // set curr to the node we found and init prev to null
                    List<string> list_path = new List<string>(); // this list contains the path
                    list_path.Add(curr.line + " - " + curr.station); // add the node we just found as the end of the path
                    while (curr.node != root) // while we are not back at the first node
                    {
                        if (path.TryGetValue(curr, out prev) == true) // found a value matching the key
                        {
                            list_path.Add(curr.line + " - " + prev.station); // add the previous node to the path
                            curr = prev; // set current node to previous node and repeat
                        }
                        else
                        {
                            Console.WriteLine("Couldn't find the prev pathnode, path broken."); // uh oh
                            //return false; // we should return if this happens, there's no way to show the path, it shouldn't happen though
                            break; // finished, we're doomed
                        }
                    }
                    //print the path to console
                    //Console.WriteLine();
                    list_path.Reverse(); // the nodes are back to front, reverse them
                    foreach (string s in list_path)
                    {
                        Console.WriteLine("Path: {0}", s); // print each 'line - station' in the path
                    }
                    return true;
                }

                // This part is the main BFS loop, it just keeps going until we find the destination
                // FIND ALL NODES THAT THIS NODE CONNECTS TO AND ADD THEM TO THE QUEUE
                string[] lines = check.node.adjacency_list.Keys.ToArray<string>(); // get all the lines that this node is part of
                foreach (string line in lines)
                {
                    Dictionary<string, Station> adj = check.node.adjacency_list[line]; // grab the next/prev dict
                    foreach (KeyValuePair<string, Station> pair in adj) // for next, and prev
                    {
                        if (pair.Value != null) // either next or prev exists
                        {
                            foreach (GraphNode n in graph) // find the station in the graph (this sucks, I have to search the whole graph to find the node again)
                            {
                                if (n.name == pair.Value.Name && visited.Contains(n.name) == false) // if the node name matches the next/prev name we are checking AND we haven't visited it before
                                {
                                    PathNode to_queue = new PathNode(n.name, line, n); // create a new PathNode with the node name, line and a copy of the GraphNode
                                    queue.Enqueue(to_queue); // enqueue it
                                    visited.Add(n.name); // mark it as visited
                                    found = true; // flag the station does exist
                                    path.Add(to_queue, check); // add the node, and it's previous node to the path so we can retrace steps at the end
                                }
                            }
                            if (found == false) // the station does NOT exist, return false (this is bad and shouldn't happen, means we have bad references)
                                return false;
                        }
                    }
                }
            }
            return false; // not found, again, shouldn't happen if we are searching for a station that exists
        }
Ejemplo n.º 2
0
        public List<string> lines; // what lines is this station part of (ie a train line and a bus route)

        #endregion Fields

        #region Constructors

        public GraphNode(Station station, string line, Station next, Station prev)
        {
            name = station.Name; // set the name of the node to the name of the station
            lines = new List<string>(); // this list is kinda redundant, but you can see what lines exist in the graph if you access it
            lines.Add(line); // add this line/route to the list of lines/routes that this station is part of
            adjacency_list = new Dictionary<string, Dictionary<string, Station>>(); // <line, <next/prev, station>>
            Dictionary<string, Station> adj = new Dictionary<string, Station>(); // <next = Station, prev = Station>
            adj.Add("next", next); // "next" = Station next
            adj.Add("prev", prev); // "prev" = Station prev
            adjacency_list.Add(line, adj);
        }