Ejemplo n.º 1
0
        /// <summary>This method does all of the work of running a bidirectional search except for ensuring that searching
        /// bidirectionally is safe and starting the limiter, if any.
        /// </summary>
        protected SearchResult FinishBidirectionalSearch(StateType initialState, SearchLimiter limiter,
                                                         out Node <StateType, ActionType> solution)
        {
            solution = new Node <StateType, ActionType>();

            // the queues into which nodes will be placed
            IQueue <Node <StateType, ActionType> > leftFringe, rightFringe;
            // dictionaries keeping track of states that have been visited before, and the best paths to them.
            Dictionary <StateType, Node <StateType, ActionType> > leftStates, rightStates;

            // initialize the search
            leftFringe  = CreateQueue();
            rightFringe = CreateQueue();
            leftStates  = new Dictionary <StateType, Node <StateType, ActionType> >();
            rightStates = EliminateDuplicateStates ? new Dictionary <StateType, Node <StateType, ActionType> >() : null;

            leftFringe.Enqueue(MakeNode(initialState));
            foreach (StateType goalState in BidiProblem.GetGoalStates())
            {
                rightFringe.Enqueue(MakeNode(goalState));
            }

            bool limitHit = false;                                  // keeps track of whether the search has hit some limit preventing it from exploring further

            while (leftFringe.Count != 0 && rightFringe.Count != 0) // while there are still nodes in both open lists
            {
                if (limiter != null && limiter.LimitReached)
                {
                    limitHit = true;
                    break;
                }

                // get a node from the forward search
                Node <StateType, ActionType> leftNode = leftFringe.Dequeue();
                if (Problem.IsGoal(leftNode.State)) // if it's a goal, we've found a forward-only solution, so return it
                {
                    solution = leftNode;
                    return(SearchResult.Success);
                }

                // this proceeds much like standard search...
                if (EliminateDuplicateStates)
                {
                    limitHit |= TryEnqueueNodes(leftFringe, leftNode, leftStates, false);
                }
                else if (leftNode.Depth >= DepthLimit)
                {
                    limitHit = true;
                }
                else
                {
                    foreach (Node <StateType, ActionType> child in GetNodes(leftNode, null, false))
                    {
                        leftFringe.Enqueue(child);

                        Node <StateType, ActionType> existingChild;
                        if (!leftStates.TryGetValue(child.State, out existingChild) || IsNodeBetter(child, existingChild))
                        {
                            leftStates[child.State] = child;
                        }
                    }
                }

                // now take a node from the reverse search
                Node <StateType, ActionType> rightNode = rightFringe.Dequeue();
                // if it has been visited by the forward search, we've found a link between the two
                if (leftStates.TryGetValue(rightNode.State, out leftNode))
                {
                    solution = BuildBidirectionalSolution(leftNode, rightNode); // convert it into a forward-only solution
                    return(SearchResult.Success);                               // and return it
                }

                limitHit |= TryEnqueueNodes(rightFringe, rightNode, rightStates, true);
            }

            // if it gets here, we couldn't find a solution
            return(limitHit ? SearchResult.LimitReached : SearchResult.Failed);
        }