private void IterativeDeepening_OnSearchUpdate(object sender, SearchStatistics statistics) { // Main search result _interactiveConsole.WriteLine($" === Depth: {statistics.Depth}, Score: {statistics.Score}, Best: {statistics.PrincipalVariation[0]}, " + $"Time: {((float) statistics.SearchTime / 1000):F} s"); // Normal search _interactiveConsole.WriteLine($" Normal search: Nodes: {statistics.Nodes}, Leafs: {statistics.Leafs}, " + $"Branching factor: {statistics.BranchingFactor:F}, Beta cutoffs: {statistics.BetaCutoffs}"); // Quiescence search _interactiveConsole.WriteLine($" Q search: Nodes: {statistics.QNodes}, Leafs: {statistics.QLeafs}, " + $"Branching factor: {statistics.QBranchingFactor:F}, Beta cutoffs: {statistics.QBetaCutoffs}"); // Total _interactiveConsole.WriteLine($" Total: Nodes: {statistics.TotalNodes} ({((float)statistics.TotalNodesPerSecond / 1000000):F} MN/s), " + $"Leafs: {statistics.TotalLeafs}, Branching factor: {statistics.TotalBranchingFactor:F}, " + $"Beta cutoffs: {statistics.TotalBetaCutoffs}"); #if DEBUG // Beta cutoffs at first move _interactiveConsole.WriteLine($" Beta cutoffs at first move: {statistics.BetaCutoffsAtFirstMove} ({statistics.BetaCutoffsAtFirstMovePercent:F} %), " + $"Q Beta cutoffs at first move: {statistics.QBetaCutoffsAtFirstMove} ({statistics.QBetaCutoffsAtFirstMovePercent:F} %)"); // Transposition statistics _interactiveConsole.WriteLine($" TT: " + $"Added: {statistics.TTAddedEntries}, " + $"Replacements: {statistics.TTReplacements} ({statistics.TTReplacesPercent:F} %), " + $"Hits: {statistics.TTHits} ({statistics.TTHitsPercent:F} %), " + $"Missed: {statistics.TTNonHits}, " + $"Filled: {TranspositionTable.GetFillLevel():F} %"); // Pawn hash table statistics _interactiveConsole.WriteLine($" PHT: " + $"Added: {statistics.EvaluationStatistics.PHTAddedEntries}, " + $"Replacements: {statistics.EvaluationStatistics.PHTReplacements} ({statistics.EvaluationStatistics.PHTReplacesPercent:F} %), " + $"Hits: {statistics.EvaluationStatistics.PHTHits} ({statistics.EvaluationStatistics.PHTHitsPercent:F} %), " + $"Missed: {statistics.EvaluationStatistics.PHTNonHits}, " + $"Filled: {PawnHashTable.GetFillLevel():F} %"); // Evaluation hash table statistics _interactiveConsole.WriteLine($" EHT: " + $"Added: {statistics.EvaluationStatistics.EHTAddedEntries}, " + $"Replacements: {statistics.EvaluationStatistics.EHTReplacements} ({statistics.EvaluationStatistics.EHTReplacesPercent:F} %), " + $"Hits: {statistics.EvaluationStatistics.EHTHits} ({statistics.EvaluationStatistics.EHTHitsPercent:F} %), " + $"Missed: {statistics.EvaluationStatistics.EHTNonHits}, " + $"Filled: {EvaluationHashTable.GetFillLevel():F} %"); _interactiveConsole.WriteLine($" Valid TT moves: {statistics.TTValidMoves}, Invalid TT moves: {statistics.TTInvalidMoves}, " + $"IID hits: {statistics.IIDHits}, Loud generations: {statistics.LoudMovesGenerated}, " + $"Quiet generations: {statistics.QuietMovesGenerated}"); #endif _interactiveConsole.WriteLine(); }
public void Run(params string[] parameters) { TranspositionTable.Clear(); PawnHashTable.Clear(); EvaluationHashTable.Clear(); KillerHeuristic.Clear(); HistoryHeuristic.Clear(); _uciClient.BoardState.SetDefaultState(); }
private void Test(BoardState boardState, string name, int depth) { _interactiveConsole.WriteLine($" == {name}:"); TranspositionTable.Clear(); PawnHashTable.Clear(); EvaluationHashTable.Clear(); KillerHeuristic.Clear(); HistoryHeuristic.Clear(); var context = new SearchContext(boardState) { MaxDepth = depth }; IterativeDeepening.OnSearchUpdate += IterativeDeepening_OnSearchUpdate; IterativeDeepening.FindBestMove(context); IterativeDeepening.OnSearchUpdate -= IterativeDeepening_OnSearchUpdate; _interactiveConsole.WriteLine(); }
public static int FindBestMove(SearchContext context, int depth, int ply, int alpha, int beta) { context.Statistics.QNodes++; if (ply > context.Statistics.SelectiveDepth) { context.Statistics.SelectiveDepth = ply; } if (context.BoardState.Pieces[context.BoardState.ColorToMove][Piece.King] == 0) { context.Statistics.QLeafs++; return(SearchConstants.NoKingValue); } if (context.BoardState.IsKingChecked(ColorOperations.Invert(context.BoardState.ColorToMove))) { context.Statistics.QLeafs++; return(-SearchConstants.NoKingValue); } var standPat = 0; var evaluationEntry = EvaluationHashTable.Get(context.BoardState.Hash); if (evaluationEntry.IsKeyValid(context.BoardState.Hash)) { standPat = evaluationEntry.Score; #if DEBUG context.Statistics.EvaluationStatistics.EHTHits++; #endif } else { standPat = Evaluation.Evaluate(context.BoardState, true, context.Statistics.EvaluationStatistics); EvaluationHashTable.Add(context.BoardState.Hash, (short)standPat); #if DEBUG context.Statistics.EvaluationStatistics.EHTNonHits++; context.Statistics.EvaluationStatistics.EHTAddedEntries++; if (evaluationEntry.Key != 0 || evaluationEntry.Score != 0) { context.Statistics.EvaluationStatistics.EHTReplacements++; } #endif } if (standPat >= beta) { context.Statistics.QLeafs++; return(standPat); } if (standPat > alpha) { alpha = standPat; } Span <Move> moves = stackalloc Move[SearchConstants.MaxMovesCount]; Span <short> moveValues = stackalloc short[SearchConstants.MaxMovesCount]; var movesCount = context.BoardState.GetAvailableCaptureMoves(moves); MoveOrdering.AssignQValues(context.BoardState, moves, moveValues, movesCount); for (var moveIndex = 0; moveIndex < movesCount; moveIndex++) { MoveOrdering.SortNextBestMove(moves, moveValues, movesCount, moveIndex); if (moveValues[moveIndex] < 0) { #if DEBUG context.Statistics.QSEEPrunes++; #endif break; } if (standPat + moveValues[moveIndex] + SearchConstants.QFutilityPruningMargin < alpha) { #if DEBUG context.Statistics.QFutilityPrunes++; #endif break; } context.BoardState.MakeMove(moves[moveIndex]); var score = -FindBestMove(context, depth - 1, ply + 1, -beta, -alpha); context.BoardState.UndoMove(moves[moveIndex]); if (score > alpha) { alpha = score; if (alpha >= beta) { #if DEBUG if (moveIndex == 0) { context.Statistics.QBetaCutoffsAtFirstMove++; } else { context.Statistics.QBetaCutoffsNotAtFirstMove++; } #endif context.Statistics.QBetaCutoffs++; break; } } } return(alpha); }