public int EvaluateTerminalBoard(FastBoardNode node, int plyFromRoot) { diagnostics.terminalBoardEvaluations++; bool whiteIsChecking = node.currentMove != Team.White && node.IsChecking(Team.White); if (whiteIsChecking) { return(CheckmateValue - plyFromRoot); } bool blackIsChecking = node.currentMove != Team.Black && node.IsChecking(Team.Black); if (blackIsChecking) { return(-CheckmateValue + plyFromRoot); } // Either stalemate, or 50 move rule draw return(DrawValue); }
int Search(FastBoardNode node, int searchDepth, int plyFromRoot, int alpha, int beta, int color) { if (searchDepth == 0) { using (diagnostics.quiescence.Measure()) return(QuiescenceSearch(node, plyFromRoot, alpha, beta, color)); } List <FastMove> moves; using (diagnostics.moveGen.Measure()) { moves = moveCache[searchDepth]; moves.Clear(); node.AddAllPossibleMoves(moves, node.currentMove); } evaluationData.Prepare(node); using (diagnostics.moveSort.Measure()) { OrderMoves(node, moves, plyFromRoot); } bool isTerminal = true; int value = int.MinValue; foreach (var move in moves) { if (cancellationRequested) { return(0); } using (diagnostics.apply.Measure()) node.DoMove(move); bool isKingVulnerable; using (diagnostics.moveValidate.Measure()) isKingVulnerable = node.IsChecking(node.currentMove); if (isKingVulnerable) { diagnostics.invalidMoves++; using (diagnostics.apply.Measure()) node.UndoMove(move); continue; } isTerminal = false; int currentValue = -Search(node, searchDepth - 1, plyFromRoot + 1, -beta, -alpha, -color); if (previousOrderingEnabled && plyFromRoot == 0) { previousScores[move] = currentValue; } using (diagnostics.apply.Measure()) node.UndoMove(move); if (currentValue > value) { if (plyFromRoot == 0) { bestMoveThisIteration = move; } value = currentValue; } alpha = Math.Max(alpha, value); if (alpha >= beta) { diagnostics.searchCutoff++; break; } } if (isTerminal) { value = color * EvaluateTerminalBoard(node, plyFromRoot); } return(value); }
public int EvaluateBoard(FastBoardNode node, int plyFromRoot) { if (node.plySincePawnMovedOrPieceTaken >= 100) { return(0); // automatic draw due to 50 move rule. } int boardValue = 0; bool whiteIsChecking = node.currentMove != Team.White && node.IsChecking(Team.White); if (whiteIsChecking) { boardValue += CheckBonusValue; } bool blackIsChecking = node.currentMove != Team.Black && node.IsChecking(Team.Black); if (blackIsChecking) { boardValue -= CheckBonusValue; } if (!node.HasAnyValidMoves(node.currentMove)) { if (whiteIsChecking) { return(CheckmateValue - plyFromRoot); } else if (blackIsChecking) { return(-CheckmateValue + plyFromRoot); } else { return(DrawValue); } } /* * for (byte i = 0; i < node.positions.Length; i++) * { * var piece = node.positions[i]; * if (piece.team == Team.None) * continue; * * var valuedPosition = FastIndex.FromByte(i); * if (piece.team == Team.Black) * valuedPosition = valuedPosition.Mirror(); * * int pieceValue = GetPieceValue(piece.piece); * * if (pawnValueMapEnabled && piece.piece == FastPiece.Pawn) * { * pieceValue += pawnValueMap[valuedPosition.HexId]; * } * * boardValue += TeamMults[(byte)piece.team] * pieceValue; * } */ using (diagnostics.evalThreats.Measure()) { boardValue += evaluationData.White.Threats.Count - evaluationData.Black.Threats.Count; boardValue += (evaluationData.White.PawnThreats.Count * 2) - (evaluationData.Black.PawnThreats.Count * 2); boardValue += evaluationData.White.MaterialValue - evaluationData.Black.MaterialValue; var whiteAttacks = evaluationData.Black.Pieces & evaluationData.White.Threats; var blackAttacks = evaluationData.White.Pieces & evaluationData.Black.Threats; boardValue += whiteAttacks.Count - blackAttacks.Count; var whiteDefended = evaluationData.White.Pieces & evaluationData.White.Threats; var blackDefended = evaluationData.Black.Pieces & evaluationData.Black.Threats; boardValue += whiteDefended.Count - blackDefended.Count; var whiteHangingPieces = blackAttacks & ~evaluationData.White.Threats; var blackHangingPieces = whiteAttacks & ~evaluationData.Black.Threats; boardValue += (blackHangingPieces.Count - whiteHangingPieces.Count) * 100; } return(boardValue); }
int QuiescenceSearch(FastBoardNode node, int plyFromRoot, int alpha, int beta, int color) { int eval; evaluationData.Prepare(node); using (diagnostics.quiescenceEval.Measure()) eval = color * EvaluateBoard(node, plyFromRoot); if (!quiescenceSearchEnabled) { return(eval); } if (eval >= beta) { diagnostics.quiescenceCutoff++; return(beta); } if (eval > alpha) { alpha = eval; } List <FastMove> moves; using (diagnostics.quiescenceMoveGen.Measure()) { moves = new List <FastMove>(10); node.AddAllPossibleMoves(moves, node.currentMove, generateQuiet: false); } using (diagnostics.quiescenceMoveSort.Measure()) OrderMoves(node, moves, -1); bool maybeTerminal = true; int value = int.MinValue; foreach (var move in moves) { if (cancellationRequested) { return(0); } using (diagnostics.quiescenceApply.Measure()) node.DoMove(move); bool isKingVulnerable; using (diagnostics.quiescenceMoveValidate.Measure()) isKingVulnerable = node.IsChecking(node.currentMove); if (isKingVulnerable) { diagnostics.invalidMoves++; using (diagnostics.quiescenceApply.Measure()) node.UndoMove(move); continue; } maybeTerminal = false; int currentValue = -QuiescenceSearch(node, plyFromRoot + 1, -beta, -alpha, -color); using (diagnostics.quiescenceApply.Measure()) node.UndoMove(move); if (currentValue > value) { value = currentValue; } alpha = Math.Max(alpha, value); if (alpha >= beta) { diagnostics.quiescenceCutoff++; break; } } // No non-quiet moves were found from this position if (maybeTerminal) { return(eval); } return(value); }