/// <summary> /// Runs a search. /// </summary> /// <param name="startState">The state that the search will start from</param> /// <param name="maxDepth">The search will be terminated after maxDepth</param> /// <param name="cancellationToken">Used to cancel the search</param> public SearchResult Search(IDeterministicState startState, int maxDepth, CancellationToken cancellationToken) { if (StateDefinesDepth && CacheMode != CacheMode.NoCache && CacheKeyType != CacheKeyType.StateOnly) { throw new MinMaxSearchException($"If {nameof(StateDefinesDepth)} the cache key should be of type {CacheKeyType.StateOnly}"); } if (!startState.GetNeighbors().Any()) { throw new NoNeighborsException("start state has no neighbors " + startState); } if (maxDepth < 1) { throw new ArgumentException($"{nameof(maxDepth)} must be at least 1. Was {maxDepth}"); } if (SkipEvaluationForFirstNodeSingleNeighbor && startState.GetNeighbors().Count() == 1) { return(new SearchResult(0, startState, true, true, false)); } var searchContext = new SearchContext(maxDepth, 0, cancellationToken); var searchWorker = new SearchWorker(CreateSearchOptions(), GetThreadManager(maxDepth), cacheManagerFactory()); var stopwatch = new Stopwatch(); stopwatch.Start(); var result = searchWorker.Evaluate(startState, searchContext); stopwatch.Stop(); result.StateSequence.Reverse(); result.StateSequence.RemoveAt(0); // Removing the top node will make the result "nicer" return(new SearchResult(result, stopwatch.Elapsed, maxDepth, !cancellationToken.IsCancellationRequested)); }
public DeterministicSearchUtils(SearchWorker searchWorker, SearchOptions searchOptions, IThreadManager threadManager) { this.searchWorker = searchWorker; this.searchOptions = searchOptions; this.threadManager = threadManager; }