/// <summary> /// Search the game tree multiple times with increasing depth until the wall clock time limit /// specified by the configuration is exhausted. Take best result found at that point and /// cancel search. /// </summary> private static Result BestFixedTime(Configuration c, FastWorld w, int ownIndex) { Debug.Assert(c.SearchLimit.LimitType == DeepeningSearch.LimitType.Milliseconds); // Keep in mind on thread safety: // The thread that calls Abort might block if the thread that is being aborted is in a protected // region of code, such as a catch block, finally block, or constrained execution region. If the // thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur. // https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.abort?view=netframework-4.7.2 var myLock = new object(); Result best = null; var stop = new DeepeningSearch.Stop(); Thread t = new Thread(() => { try { for (int i = 1; ; ++i) { var result = SearchSelectingStrategy(c, w, ownIndex, i, stop); lock (myLock) { best = result; } } } catch (DeepeningSearch.StopSearchException) { // Perfectly normal to throw this exception upon stopping deepening return; } }); t.Start(); Thread.Sleep(c.SearchLimit.Limit); stop.RequestStop(); // Should be no more contention since t is aborted and joined // But I guess it doesn't hurt lock (myLock) { return(best); } }
private static Result SearchSelectingStrategy(Configuration c, FastWorld w, int ownIndex, int depth, DeepeningSearch.Stop stop) { var reflexMask = c.ReflexMask ?? FindMaskForDepth(w, ownIndex, depth); var simulatedCount = reflexMask.Count(el => el == false); var ordering = MaxN.CalculateSteppingOrdering(w, ownIndex, reflexMask); if (simulatedCount == 2 && c.AlphaBetaFallbackHeuristic != null) { // If alpha beta fallback heuristic is provided and we have two simulated snakes, use alpha beta search var abConf = new DeepeningSearch.Configuration(c.AlphaBetaFallbackHeuristic(ordering[0], ordering[1]), ordering[0], ordering[1]); abConf.Stop = stop; var(direction, score) = new AlphaBeta().Search(abConf, w, depth); return(new Result(new DeepeningSearch.Result(score, direction, depth))); } else { var internalConfiguration = new InternalConfiguration { ReflexMask = reflexMask, Depth = depth, OwnIndex = ownIndex, StopHandler = stop }; var(scoresAbs, scoresRel, directions) = PseudoPlyStep(w, internalConfiguration, c.MaxNHeuristicProducer(ownIndex), 0, 0, ordering, null); return(new Result( internalConfiguration.steps, internalConfiguration.ReflexMask.Count(el => el == false), internalConfiguration.Depth, directions[ownIndex], scoresRel[ownIndex], scoresAbs, scoresRel, directions )); } }