private void OutputVerboseInfo(ISearchNode goalState, Stopwatch searchWatch, long step, ISearchNode current) { Console.SetCursorPosition(0, 0); Console.WriteLine("Open list: {0} ", openQueue.Count); Console.WriteLine("Closed list: {0} ", closedSet.Count); if (openQueue.Count > 0) { Console.WriteLine("First cost until now: {0} ", openQueue.First.Cost); Console.WriteLine("First tentative cost: {0} ", openQueue.First.Cost + openQueue.First.GetHeuristic(goalState)); } else { Console.WriteLine(); Console.WriteLine(); } Console.WriteLine($"Step: {step} "); Console.WriteLine("Time: {0}:{1}:{2}.{3} ", searchWatch.Elapsed.Hours, searchWatch.Elapsed.Minutes, searchWatch.Elapsed.Seconds, searchWatch.Elapsed.Milliseconds); Console.WriteLine("Closed/Open Ratio: " + 1.0f * closedSet.Count / openQueue.Count); Console.WriteLine(current.VerboseInfo); OnGeneralVerboseOutputPrinted(new SearchEventArgs { OpenQueue = openQueue, ClosedSet = closedSet, CurrentNode = current, GoalNode = goalState }); }
public void Evaluate(ISearchNode node) { LogFile.Debug("Evaluating node: {0}", node); InnerResult rootResult; var statehash = _game.CalculateHash(); var isNew = _searchResults.CreateOrGetExistingResult( statehash, node.Controller.IsMax, SearchDepth, out rootResult); if (isNew || !ParentResult.HasChildrenWithIndex(ResultIndex)) { ParentResult.AddChild(ResultIndex, rootResult); } if (isNew) { EvaluateBranches(node, rootResult); } else { SubTreesPrunned++; LogFile.Debug("state {0}, prunning node {1}", statehash, node); } // By evaluating each branch we have already traversed the // entire subtree, so we stop the game and yield control to // upper level. _game.Stop(); }
/// <summary> /// Adds the specified node to the open nodes collection. /// </summary> /// <param name="node">Node to be added.</param> /// <param name="gValue">Calculated distance from the start.</param> /// <param name="predecessor">Predecessor node.</param> /// <param name="appliedOperator">Predecessor operator.</param> protected override void AddToOpenNodes(ISearchNode node, int gValue, ISearchNode predecessor, IOperator appliedOperator) { if (gValue > LimitValue) { return; } NodeInfo nodeInfo; if (NodesInfo.TryGetValue(node, out nodeInfo)) { if (nodeInfo.GValue > gValue) { nodeInfo.GValue = gValue; nodeInfo.Predecessor = Tuple.Create(predecessor, appliedOperator); NodesInfo[node] = nodeInfo; double hValue = Heuristic.GetValue(node); OpenNodes.Add(gValue + hValue, node); } } else { double hValue = Heuristic.GetValue(node); double fValue = gValue + hValue; if (fValue > LimitValue) { LowestValueOverLimit = Math.Min(LowestValueOverLimit, fValue); return; } NodesInfo.Add(node, new NodeInfo(gValue, Tuple.Create(predecessor, appliedOperator))); OpenNodes.Add(fValue, node); } }
// Returns true if the search is to continue internal bool NodeLooking(BrowserFinder finder, ISearchNode node) { if (TraceUtil.If(this, TraceLevel.Verbose)) { Trace.WriteLine("node looking: " + node.GetType().Name + " " + finder.GetFullName()); } if (_cancelled) { return(false); } _lookingNodeCount++; // Show it as its found if ((_lookingNodeCount % 10) == 0) { _lookingLabel.Text = StringParser.Parse("${res:ComponentInspector.FindDialog.LookingAtLabel}"); _lookingNode.Text = finder.GetFullName(); Application.DoEvents(); } return(true); }
/// <summary> /// Constructs the solution plan from the given sequence of operators. /// </summary> /// <param name="initialState">Initial state of the plan.</param> /// <param name="operators">Sequence of grounded operators.</param> public SolutionPlan(ISearchNode initialState, IEnumerable <IOperator> operators) : base(operators) { if (initialState != null) { InitialState = initialState; } }
private int StartNewSearch(ISearchNode searchNode, SearchResults cachedResults) { AdjustPerformance(); ClearResultCache(); var parameters = new SearchParameters(CurrentDepth, CurrentTargetCount, _searchParameters.SearchPartitioningStrategy); CurrentSearch = new Search(parameters, searchNode.Controller, cachedResults, _game); SearchStarted(this, EventArgs.Empty); _game.Publish(new SearchStartedEvent(_searchParameters)); _nodeCount = 0; using (new SearchMonitor(this)) { LastSearchStatistics = CurrentSearch.Start(searchNode); } var result = CurrentSearch.Result; LastSearchStatistics.NodeCount = _nodeCount; UpdateSearchDurations(); _game.Publish(new SearchFinishedEvent()); SearchFinished(this, EventArgs.Empty); CurrentSearch = null; return(result); }
/// <summary> /// Constructs an empty solution plan. /// </summary> /// <param name="initialState">Initial state of the plan.</param> public SolutionPlan(ISearchNode initialState) { if (initialState != null) { InitialState = initialState; } }
public void EvaluateBranch(int index, ISearchNode searchNode, InnerResult parentResult) { LogFile.Debug("{0} start eval move {1}", searchNode, index); // Create a snapshot, of the game before traversing // a branch. var snaphost = _game.CreateSnapshot(); searchNode.SetResult(index); ParentResult = parentResult; ResultIndex = index; // Traverse this branch, and build result subtree. _game.Simulate(_search.SearchUntilDepth); if (parentResult.HasChildrenWithIndex(index) == false) { // No children were added on this branch and the game has // finished or we have reached our intended depth. // Add a leaf node with game score. var leafResult = new LeafResult(_game.Score, SearchDepth); parentResult.AddChild(index, leafResult); } // Restore the game from the snapshot. _game.RollbackToSnapshot(snaphost); LogFile.Debug("{0} stop eval move {1}", searchNode, index); }
public SearchStatistics Start(ISearchNode searchNode) { _stopwatch.Start(); // Lock original changer tracker. // So we are sure that original game state stays intact. // This is usefull for debuging state copy issues. _game.ChangeTracker.Lock(); // Both original and copied tracker will be enabled, // but only the copy is unlocked and can track state. _game.ChangeTracker.Enable(); // Copy game state, var searchNodeCopy = new CopyService().CopyRoot(searchNode); // create the first worker var worker = CreateWorker(_root, searchNodeCopy.Game); // and start the search. worker.StartSearch(searchNodeCopy); RemoveWorker(worker); _game.ChangeTracker.Disable(); _game.ChangeTracker.Unlock(); _root.EvaluateSubtree(); _stopwatch.Stop(); return(GetSearchStatistics()); }
/// <summary> /// Create a new search node for BreadFirstSearch. /// </summary> /// <param name="x">X coordinate of the search node.</param> /// <param name="y">Y coordinate of the search node.</param> /// <param name="previousNode">Search node preceeding this one.</param> public BreadthFirstSearchNode(int x, int y, BreadthFirstSearchNode previousNode = null) { this.x = x; this.y = y; this.searchStatus = SearchState.Unchecked; this.previousNode = previousNode; }
public SearchPartitioningStrategyParameters(ISearchNode node, int moveIndex, Search search, Game gameStateAtBegginingOfSearch) { Node = node; MoveIndex = moveIndex; Search = search; GameStateAtBegginingOfSearch = gameStateAtBegginingOfSearch; SearchDepth = Node.Game.Turn.StateCount - GameStateAtBegginingOfSearch.Turn.StateCount; }
/// <summary> /// Processes the transitions from the specified search node. /// </summary> /// <param name="node">Search node to be processed.</param> /// <param name="gValue">Distance of the node from the initial node.</param> protected override void ProcessTransitionsFromNode(ISearchNode node, int gValue) { Candidates.SelectBestTransitionCandidates(node); foreach (var candidate in Candidates) { AddToOpenNodes(candidate.Node, candidate.AppliedOperator.GetCost() + gValue, candidate.HValue, node, candidate.AppliedOperator); } }
/// <summary> /// Sets the initial search node of the search procedure. /// </summary> /// <param name="initialNode">Initial node of the search.</param> protected override void SetInitialNode(ISearchNode initialNode) { foreach (var item in OpenLists) { item.Add(0, initialNode); ++AllOpenNodesCount; } NodesInfo.Add(initialNode, new NodeInfo(0, null)); }
/// <summary> /// Computes the heuristic value for the specified node and inserts both into open nodes. Should not be called separately, but only /// within AddToOpenNodes() method containing necessary checks and additional operations. /// </summary> /// <param name="node">Node to be added.</param> /// <param name="gValue">Calculated distance from the start.</param> /// <param name="predecessor">Predecessor node.</param> /// <param name="appliedOperator">Predecessor operator.</param> protected virtual void ComputeHeuristicAndInsertNewOpenNode(ISearchNode node, int gValue, ISearchNode predecessor, IOperator appliedOperator) { double hValue = (IsComplexHeuristic) ? ((ComplexHeuristic)Heuristic).GetValue(node, predecessor, appliedOperator) : Heuristic.GetValue(node); if (!double.IsInfinity(hValue)) // Infinity heuristic indicates dead-end { OpenNodes.Add(ComputeNewOpenNodeValueWithTieBreakingRule(gValue, hValue), node); } }
/// <summary> /// Finalization of the search procedure. Should be done after every search! /// </summary> /// <param name="resultStatus">Result of the search.</param> /// <param name="goalNode">Goal node (if solution found).</param> /// <returns>Result of the search.</returns> public virtual ResultStatus FinishSearch(ResultStatus resultStatus, ISearchNode goalNode = null) { ResultStatus = resultStatus; GoalNode = goalNode; StopTimer(); LogSearchEnd(); return(resultStatus); }
// returns true if the search is to continue protected bool SearchInternal(ISearchNode node, int level) { if (level > _maxLevel) { return(true); } // Remember the chain of nodes during the search _searchStack.Push(node); if (_nodeLooking != null) { // Cancel if _nodeLooking returns flase if (!_nodeLooking(this, node)) { _searchStack.Pop(); return(false); } } // Intermediate nodes can't match if (((_useName && DoCompare(node.GetSearchNameString())) || (_useValue && DoCompare(node.GetSearchValueString()))) && !(node is IntermediateTreeNode)) { _nodeFound(this, node); } bool continueSearch = true; // Call HasChildren because some nodes might use that // to prepare themselves for the search if (node.HasSearchChildren(this)) { foreach (ISearchNode childNode in node.GetSearchChildren()) { continueSearch = SearchInternal(childNode, level + 1); if (!continueSearch) { break; } } } if (!continueSearch) { TraceUtil.WriteLineInfo(null, "Search cancelled"); _searchStack.Pop(); return(false); } _searchStack.Pop(); return(true); }
/// <summary> /// Gets a sequence of states corresponding to successive application of the operators in the solution plan. /// The first state should be always initial state of the problem, the last state should be a goal state. /// </summary> /// <returns></returns> public IEnumerable <ISearchNode> GetStatesSequence() { ISearchNode currentState = InitialState; yield return(currentState); foreach (var op in this) { currentState = op.Apply((IState)currentState); yield return(currentState); } }
public string WriteSolution() { var actions = new List <string>(); for (ISearchNode <A, S, T, C> node = this; node != null; node = node.Parent) { if (node.Action != null) { actions.Add(node.Action.ToString()); } } actions.Reverse(); return(String.Join(" ", actions)); }
/// <summary> /// Computes the heuristic value for the specified node and inserts both into open nodes. Should not be called separately, but only /// within AddToOpenNodes() method containing necessary checks and additional operations. /// </summary> /// <param name="node">Node to be added.</param> /// <param name="gValue">Calculated distance from the start.</param> /// <param name="predecessor">Predecessor node.</param> /// <param name="appliedOperator">Predecessor operator.</param> protected override void ComputeHeuristicAndInsertNewOpenNode(ISearchNode node, int gValue, ISearchNode predecessor, IOperator appliedOperator) { for (int i = 0; i < NumberOfOpenLists; ++i) { Heuristic = Heuristics[i]; OpenNodes = OpenLists[i]; double hValue = Heuristic.GetValue(node); if (!double.IsInfinity(hValue)) // Infinity heuristic indicates dead-end { OpenNodes.Add(ComputeNewOpenNodeValueWithTieBreakingRule(gValue, hValue), node); ++AllOpenNodesCount; } } }
/// <summary> /// Applies the specified operator to the specified search node. /// </summary> /// <param name="node">Search node.</param> /// <param name="oper">Operator to be applied.</param> /// <returns>New search node.</returns> protected ISearchNode Apply(ISearchNode node, IOperator oper) { switch (SearchType) { case SearchType.Forward: return(oper.Apply((IState)node)); case SearchType.BackwardWithConditions: return(oper.ApplyBackwards((IConditions)node)); case SearchType.BackwardWithStates: return(oper.ApplyBackwards((IRelativeState)node).First()); default: throw new NotSupportedException("Unknown search type!"); } }
/// <summary> /// Gets the full string description of the solution plan, i.e. the full path of operator applications /// including all the intermediate states. /// </summary> /// <returns>Full description of the solution plan.</returns> public string GetFullDescription() { List <string> description = new List <string>(); ISearchNode currentState = InitialState; description.Add(currentState.ToString()); foreach (var oper in this) { description.Add("+"); description.Add(oper.GetName()); description.Add("=>"); currentState = oper.Apply((IState)currentState); description.Add(currentState.ToString()); } return(string.Join(" ", description)); }
public Task EvaluateBranch(SearchWorker worker, ISearchNode rootNode, InnerResult rootResult, int moveIndex) { var shouldCreateNewWorker = IsItFeasibleToCreateNewWorker(rootNode, moveIndex); if (shouldCreateNewWorker) { rootNode = new CopyService().CopyRoot(rootNode); worker = CreateWorker(rootResult, rootNode.Game); var task = Task.Factory.StartNew(() => { worker.EvaluateBranch(moveIndex, rootNode, rootResult); RemoveWorker(worker); }, TaskCreationOptions.PreferFairness); return task; } worker.EvaluateBranch(moveIndex, rootNode, rootResult); return null; }
internal bool NodeFound(BrowserFinder finder, ISearchNode node) { if (TraceUtil.If(this, TraceLevel.Verbose)) { Trace.WriteLine("node found: " + node.GetType().Name + " " + finder.GetFullName()); } ListViewItem li = new ListViewItem(); li.Text = finder.GetFullName(); li.Tag = node.GetSearchMaterializer(finder); li.ImageIndex = node.GetImageIndex(); _foundList.Items.Add(li); // Show it as its found Application.DoEvents(); return(true); }
public Task EvaluateBranch(SearchWorker worker, ISearchNode rootNode, InnerResult rootResult, int moveIndex) { var shouldCreateNewWorker = IsItFeasibleToCreateNewWorker(rootNode, moveIndex); if (shouldCreateNewWorker) { rootNode = new CopyService().CopyRoot(rootNode); worker = CreateWorker(rootResult, rootNode.Game); var task = Task.Factory.StartNew(() => { worker.EvaluateBranch(moveIndex, rootNode, rootResult); RemoveWorker(worker); }, TaskCreationOptions.PreferFairness); return(task); } worker.EvaluateBranch(moveIndex, rootNode, rootResult); return(null); }
/// <summary> /// Adds the specified node to the open nodes collection. /// </summary> /// <param name="node">Node to be added.</param> /// <param name="gValue">Calculated distance from the start.</param> /// <param name="hValue">Heuristic distance to the goal.</param> /// <param name="predecessor">Predecessor node.</param> /// <param name="appliedOperator">Predecessor operator.</param> protected void AddToOpenNodes(ISearchNode node, int gValue, double hValue, ISearchNode predecessor, IOperator appliedOperator) { NodeInfo nodeInfo; if (NodesInfo.TryGetValue(node, out nodeInfo)) { if (nodeInfo.GValue > gValue) { nodeInfo.GValue = gValue; nodeInfo.Predecessor = Tuple.Create(predecessor, appliedOperator); NodesInfo[node] = nodeInfo; OpenNodes.Add(gValue + hValue, node); } } else { NodesInfo.Add(node, new NodeInfo(gValue, Tuple.Create(predecessor, appliedOperator))); OpenNodes.Add(gValue + hValue, node); } }
/// <summary> /// Selects the best transition candidates of the specified node and adds them to the collection. /// </summary> /// <param name="node">Search node to be evaluated.</param> public void SelectBestTransitionCandidates(ISearchNode node) { Clear(); foreach (var transition in Problem.GetTransitions(node)) { ISearchNode newNode = transition.GetTransitionResult(); double appliedOperatorCost = transition.GetAppliedOperator().GetCost(); double worstSuccessorCandidateCost = WorstTransitionCandidateCost(); if (Count >= MaxSize && worstSuccessorCandidateCost < appliedOperatorCost) { continue; } double hValueNewState = Heuristic.GetValue(newNode); if (Count < MaxSize || worstSuccessorCandidateCost > appliedOperatorCost + hValueNewState) { Add(new BeamSearchTransitionCandidate(newNode, hValueNewState, transition.GetAppliedOperator())); } } }
/// <summary> /// Starts the search procedure. /// </summary> /// <param name="type">Type of search.</param> /// <returns>Result of the search.</returns> public override ResultStatus Start(SearchType type = SearchType.Forward) { InitSearch(type); SetInitialNode(GetInitialNode()); while (HasAnyOpenNode()) { if (IsTimeLimitExceeded()) { return(FinishSearch(ResultStatus.TimeLimitExceeded)); } if (IsMemoryLimitExceeded()) { return(FinishSearch(ResultStatus.MemoryLimitExceeded)); } LogSearchStatistics(); ISearchNode node = GetMinOpenNode(); var nodeInfo = NodesInfo[node]; if (!nodeInfo.IsClosed) { if (Problem.IsGoalNode(node)) { return(FinishSearch(ResultStatus.SolutionFound, node)); } ProcessTransitionsFromNode(node, nodeInfo.GValue); nodeInfo.IsClosed = true; ++ClosedNodesCount; } } return(FinishSearch(ResultStatus.NoSolutionFound)); }
/// <summary> /// Processes the transitions from the specified search node. /// </summary> /// <param name="node">Search node to be processed.</param> /// <param name="gValue">Distance of the node from the initial node.</param> protected virtual void ProcessTransitionsFromNode(ISearchNode node, int gValue) { MaxGValue = Math.Max(MaxGValue, gValue); foreach (var transition in Problem.GetTransitions(node)) { IOperator appliedOperator = transition.GetAppliedOperator(); int gValueNew = gValue + (appliedOperator?.GetCost() ?? 0); if (!transition.IsComplexTransition()) { ISearchNode newNode = transition.GetTransitionResult(); AddToOpenNodes(newNode, gValueNew, node, appliedOperator); } else { foreach (var newNode in transition.GetComplexTransitionResults()) { AddToOpenNodes(newNode, gValueNew, node, appliedOperator); } } } }
private void EvaluateBranches(ISearchNode searchNode, InnerResult rootResult) { LogFile.Debug("Evaluating moves of node {0}", searchNode); var tasks = new List <Task>(); for (var i = 0; i < searchNode.ResultCount; i++) { var task = _search.EvaluateBranch( worker: this, rootNode: searchNode, rootResult: rootResult, moveIndex: i); if (task != null) { tasks.Add(task); } } Task.WaitAll(tasks.ToArray()); return; }
/// <summary> /// Adds the specified node to the open nodes collection. /// </summary> /// <param name="node">Node to be added.</param> /// <param name="gValue">Calculated distance from the start.</param> /// <param name="predecessor">Predecessor node.</param> /// <param name="appliedOperator">Predecessor operator.</param> protected virtual void AddToOpenNodes(ISearchNode node, int gValue, ISearchNode predecessor, IOperator appliedOperator) { NodeInfo nodeInfo; if (NodesInfo.TryGetValue(node, out nodeInfo)) { if (nodeInfo.GValue > gValue) { nodeInfo.GValue = gValue; nodeInfo.Predecessor = Tuple.Create(predecessor, appliedOperator); NodesInfo[node] = nodeInfo; if (!nodeInfo.IsClosed) { ComputeHeuristicAndInsertNewOpenNode(node, gValue, predecessor, appliedOperator); } } } else { NodesInfo.Add(node, new NodeInfo(gValue, Tuple.Create(predecessor, appliedOperator))); ComputeHeuristicAndInsertNewOpenNode(node, gValue, predecessor, appliedOperator); } }
private bool IsItFeasibleToCreateNewWorker(ISearchNode node, int moveIndex) { return _p.SearchPartitioningStrategy( new SearchPartitioningStrategyParameters(node, moveIndex, this, _game)); }
public void EvaluateNode(ISearchNode searchNode) { var worker = GetWorker(searchNode.Game); worker.Evaluate(searchNode); }
public SearchStatistics Start(ISearchNode searchNode) { _stopwatch.Start(); // Lock original changer tracker. // So we are sure that original game state stays intact. // This is usefull for debuging state copy issues. _game.ChangeTracker.Lock(); // Both original and copied tracker will be enabled, // but only the copy is unlocked and can track state. _game.ChangeTracker.Enable(); // Copy game state, var searchNodeCopy = new CopyService().CopyRoot(searchNode); // create the first worker var worker = CreateWorker(_root, searchNodeCopy.Game); // and start the search. worker.StartSearch(searchNodeCopy); RemoveWorker(worker); _game.ChangeTracker.Disable(); _game.ChangeTracker.Unlock(); _root.EvaluateSubtree(); _stopwatch.Stop(); return GetSearchStatistics(); }
// Returns true if the search is to continue internal bool NodeLooking(BrowserFinder finder, ISearchNode node) { if (TraceUtil.If(this, TraceLevel.Verbose)) { Trace.WriteLine("node looking: " + node.GetType().Name + " " + finder.GetFullName()); } if (_cancelled) return false; _lookingNodeCount++; // Show it as its found if ((_lookingNodeCount % 10) == 0) { _lookingLabel.Text = StringParser.Parse("${res:ComponentInspector.FindDialog.LookingAtLabel}"); _lookingNode.Text = finder.GetFullName(); Application.DoEvents(); } return true; }
internal bool NodeFound(BrowserFinder finder, ISearchNode node) { if (TraceUtil.If(this, TraceLevel.Verbose)) { Trace.WriteLine("node found: " + node.GetType().Name + " " + finder.GetFullName()); } ListViewItem li = new ListViewItem(); li.Text = finder.GetFullName(); li.Tag = node.GetSearchMaterializer(finder); li.ImageIndex = node.GetImageIndex(); _foundList.Items.Add(li); // Show it as its found Application.DoEvents(); return true; }
private void EvaluateBranches(ISearchNode searchNode, InnerResult rootResult) { LogFile.Debug("Evaluating moves of node {0}", searchNode); var tasks = new List<Task>(); for (var i = 0; i < searchNode.ResultCount; i++) { var task = _search.EvaluateBranch( worker: this, rootNode: searchNode, rootResult: rootResult, moveIndex: i); if (task != null) tasks.Add(task); } Task.WaitAll(tasks.ToArray()); return; }
public void StartSearch(ISearchNode root) { LogFile.Debug("Search started, evaluating node: {0}", root); EvaluateBranches(root, ParentResult); }
private int StartNewSearch(ISearchNode searchNode, SearchResults cachedResults) { AdjustPerformance(); ClearResultCache(); var parameters = new SearchParameters(CurrentDepth, CurrentTargetCount, _searchParameters.SearchPartitioningStrategy); CurrentSearch = new Search(parameters, searchNode.Controller, cachedResults, _game); SearchStarted(this, EventArgs.Empty); _game.Publish(new SearchStartedEvent(_searchParameters)); _nodeCount = 0; using (new SearchMonitor(this)) { LastSearchStatistics = CurrentSearch.Start(searchNode); } var result = CurrentSearch.Result; LastSearchStatistics.NodeCount = _nodeCount; UpdateSearchDurations(); _game.Publish(new SearchFinishedEvent()); SearchFinished(this, EventArgs.Empty); CurrentSearch = null; return result; }
public void SetBestResult(ISearchNode searchNode) { Interlocked.Increment(ref _nodeCount); // set searching player the first time if (!IsSearchInProgress) { searchNode.Game.Players.Searching = searchNode.Controller; } // ask search node to generate all choices searchNode.GenerateChoices(); // Zero choices can happen if there are no legal targets // of a triggered ability. if (searchNode.ResultCount == 0) { return; } // Only one choice, nothing to consider here. if (searchNode.ResultCount == 1) { searchNode.SetResult(0); return; } if (IsSearchInProgress) { // More than one choice, and the search is already in progress. // Expand the tree by evaluating each branch. CurrentSearch.EvaluateNode(searchNode); return; } // More than one choice, find the best one. int bestChoice; // First try cached result from previous search. // If no results are found start a new search. var cachedResults = GetCachedResults(searchNode.Controller); var cached = cachedResults.GetResult(searchNode.Game.CalculateHash()); if (cached == null) { bestChoice = StartNewSearch(searchNode, cachedResults); } else { bestChoice = cached.BestMove.GetValueOrDefault(); if (cached.ChildrenCount != searchNode.ResultCount) { // cache is not ok, try to recover by new search // write debug report, so this error can be reproduced. LogFile.Debug("Invalid cached result, cached result count is {0} node's is {1}.", cached.ChildrenCount, searchNode.ResultCount); GenerateDebugReport(); bestChoice = StartNewSearch(searchNode, cachedResults); } } searchNode.SetResult(bestChoice); }
// returns true if the search is to continue protected bool SearchInternal(ISearchNode node, int level) { if (level > _maxLevel) return true; // Remember the chain of nodes during the search _searchStack.Push(node); if (_nodeLooking != null) { // Cancel if _nodeLooking returns flase if (!_nodeLooking(this, node)) { _searchStack.Pop(); return false; } } // Intermediate nodes can't match if (((_useName && DoCompare(node.GetSearchNameString())) || (_useValue && DoCompare(node.GetSearchValueString()))) && !(node is IntermediateTreeNode)) _nodeFound(this, node); bool continueSearch = true; // Call HasChildren because some nodes might use that // to prepare themselves for the search if (node.HasSearchChildren(this)) { foreach (ISearchNode childNode in node.GetSearchChildren()) { continueSearch = SearchInternal(childNode, level + 1); if (!continueSearch) break; } } if (!continueSearch) { TraceUtil.WriteLineInfo(null, "Search cancelled"); _searchStack.Pop(); return false; } _searchStack.Pop(); return true; }