// Returns true if a check mate or stalemate is found // Values of type of mate and side mated are stored in the three reference variables internal static bool SearchForMate(ChessPieceColor movingSide, Board examineBoard, ref bool blackMate, ref bool whiteMate, ref bool staleMate) { var foundNonCheckBlack = false; var foundNonCheckWhite = false; for (byte x = 0; x < 64; x++) { var sqr = examineBoard.Squares[x]; //Make sure there is a piece on the square if (sqr.Piece == null) { continue; } //Make sure the color is the same color as the one we are moving. if (sqr.Piece.PieceColor != movingSide) { continue; } //For each valid move for this piece foreach (var dst in sqr.Piece.ValidMoves) { //We make copies of the board and move so that we can move it without effecting the parent board var board = examineBoard.FastCopy(); //Make move so we can examine it Board.MovePiece(board, x, dst, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.BlackCheck == false) { foundNonCheckBlack = true; } else if (movingSide == ChessPieceColor.Black) { continue; } if (board.WhiteCheck == false) { foundNonCheckWhite = true; } else if (movingSide == ChessPieceColor.White) { } } } if (foundNonCheckBlack == false) { if (examineBoard.BlackCheck) { blackMate = true; return(true); } if (!examineBoard.WhiteMate && movingSide != ChessPieceColor.White) { staleMate = true; return(true); } } // ReSharper disable once InvertIf if (foundNonCheckWhite == false) { if (examineBoard.WhiteCheck) { whiteMate = true; return(true); } // ReSharper disable once InvertIf if (!examineBoard.BlackMate && movingSide != ChessPieceColor.Black) { staleMate = true; return(true); } } return(false); }
public void AiPonderMove() { Thinking = true; ChessBoard.BlackMate = false; ChessBoard.WhiteMate = false; PieceValidMoves.GenerateValidMoves(ChessBoard); NodesSearched = 0; var resultBoards = new ResultBoards { Positions = new List <Board>() }; // First search if human move might have caused a mate if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; return; } var bestMove = new MoveContent(); //If there is no playbook move search for the best move if (FindPlayBookMove(ref bestMove, ChessBoard, OpeningBook) == false || ChessBoard.HalfMoveClock > 90 || ChessBoard.RepeatedMove >= 2) { if (FindPlayBookMove(ref bestMove, ChessBoard, CurrentGameBook) == false || ChessBoard.HalfMoveClock > 90 || ChessBoard.RepeatedMove >= 2) { bestMove = Search.IterativeSearch( ChessBoard, PlyDepthSearched, ref NodesSearched, ref NodesQuiessence, ref pvLine, ref PlyDepthReached, ref RootMovesSearched, CurrentGameBook); } } //Make the move PreviousChessBoard = new Board(ChessBoard); RootMovesSearched = (byte)resultBoards.Positions.Count; Board.MovePiece(ChessBoard, bestMove.MovingPiecePrimary.SrcPosition, bestMove.MovingPiecePrimary.DstPosition, ChessPieceType.Queen); ChessBoard.LastMove.GeneratePGNString(ChessBoard); FileIO.SaveCurrentGameMove(ChessBoard, PreviousChessBoard, CurrentGameBook, bestMove); for (byte x = 0; x < 64; x++) { var sqr = ChessBoard.Squares[x]; if (sqr.Piece == null) { continue; } sqr.Piece.DefendedValue = 0; sqr.Piece.AttackedValue = 0; } PieceValidMoves.GenerateValidMoves(ChessBoard); Evaluation.EvaluateBoardScore(ChessBoard); PieceTakenAdd(ChessBoard.LastMove); MoveHistory.Push(ChessBoard.LastMove); //Second Call if computer move might have caused a mate if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; if (ChessBoard.WhiteMate || ChessBoard.BlackMate) { LastMove.PgnMove += "#"; } return; } if (ChessBoard.WhiteCheck || ChessBoard.BlackCheck) { LastMove.PgnMove += "+"; } Thinking = false; }
//Quiescence Search private static int Quiescence(Board examineBoard, int alpha, int beta, ref int nodesSearched) { nodesSearched++; //Evaluate Score Evaluation.EvaluateBoardScore(examineBoard); //Invert Score to support Negamax examineBoard.Score = SideToMoveScore(examineBoard.Score, examineBoard.WhoseMove); if (examineBoard.Score >= beta) { return(beta); } if (examineBoard.Score > alpha) { alpha = examineBoard.Score; } List <Position> positions; if (examineBoard.WhiteCheck || examineBoard.BlackCheck) { positions = EvaluateMoves(examineBoard, 0); } else { positions = EvaluateMovesQ(examineBoard); } if (positions.Count == 0) { return(examineBoard.Score); } positions.Sort(Sort); foreach (var move in positions) { if (StaticExchangeEvaluation(examineBoard.Squares[move.DstPosition]) >= 0) { continue; } //Make a copy var board = examineBoard.FastCopy(); //Move Piece Board.MovePiece(board, move.SrcPosition, move.DstPosition, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.BlackCheck) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } } if (board.WhiteCheck) { if (examineBoard.WhoseMove == ChessPieceColor.White) { continue; } } var value = -Quiescence(board, -beta, -alpha, ref nodesSearched); if (value >= beta) { KillerMove[2, 0].SrcPosition = move.SrcPosition; KillerMove[2, 0].DstPosition = move.DstPosition; return(beta); } if (value > alpha) { alpha = value; } } return(alpha); }
// Final version // ReSharper disable once IdentifierTypo private static int AlphaBeta(Board examineBoard, byte depth, int alpha, int beta, ref int nodesSearched, ref int nodesQuiessence, ref List <Position> pvLine, bool extended) { nodesSearched++; if (examineBoard.HalfMoveClock >= 100 || examineBoard.RepeatedMove >= 3) { return(0); } //End Main Search with Quiescence if (depth == 0) { if (!extended && examineBoard.BlackCheck || examineBoard.WhiteCheck) { depth++; extended = true; } else { //Perform a Quiessence Search return(Quiescence(examineBoard, alpha, beta, ref nodesQuiessence)); } } var positions = EvaluateMoves(examineBoard, depth); if (examineBoard.WhiteCheck || examineBoard.BlackCheck || positions.Count == 0) { if (SearchForMate(examineBoard.WhoseMove, examineBoard, ref examineBoard.BlackMate, ref examineBoard.WhiteMate, ref examineBoard.StaleMate)) { if (examineBoard.BlackMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(-32767 - depth); } return(32767 + depth); } // ReSharper disable once InvertIf if (examineBoard.WhiteMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(32767 + depth); } return(-32767 - depth); } //If Not Mate then StaleMate return(0); } } positions.Sort(Sort); foreach (var move in positions) { var pvChild = new List <Position>(); //Make a copy var board = examineBoard.FastCopy(); //Move Piece Board.MovePiece(board, move.SrcPosition, move.DstPosition, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.BlackCheck) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } } if (board.WhiteCheck) { if (examineBoard.WhoseMove == ChessPieceColor.White) { continue; } } var value = -AlphaBeta(board, (byte)(depth - 1), -beta, -alpha, ref nodesSearched, ref nodesQuiessence, ref pvChild, extended); if (value >= beta) { KillerMove[kIndex, depth].SrcPosition = move.SrcPosition; KillerMove[kIndex, depth].DstPosition = move.DstPosition; kIndex = (kIndex + 1) % 2; return(beta); } // ReSharper disable once InvertIf if (value > alpha) { //This nodes is PV-node //That nodes have a score that ends up being inside the window //Between the lower bound Alpha and the upper bound Beta. var pvPos = new Position { SrcPosition = board.LastMove.MovingPiecePrimary.SrcPosition, DstPosition = board.LastMove.MovingPiecePrimary.DstPosition, Move = board.LastMove.ToString() }; //All Siblings of a PV-node are expected Cut-nodes pvChild.Insert(0, pvPos); pvLine = pvChild; alpha = value; } } return(alpha); }
// Not used anymore // ReSharper disable once UnusedMember.Local private static int AlphaBeta(Board examineBoard, byte depth, int alpha, int beta, ref int nodesSearched) { nodesSearched++; if (examineBoard.HalfMoveClock >= 100 || examineBoard.RepeatedMove >= 3) { return(0); } if (depth == 0) { //Evaluate Score Evaluation.EvaluateBoardScore(examineBoard); //Invert Score to support Negamax return(SideToMoveScore(examineBoard.Score, examineBoard.WhoseMove)); } var positions = EvaluateMoves(examineBoard, depth); if (examineBoard.WhiteCheck || examineBoard.BlackCheck || positions.Count == 0) { if (SearchForMate(examineBoard.WhoseMove, examineBoard, ref examineBoard.BlackMate, ref examineBoard.WhiteMate, ref examineBoard.StaleMate)) { if (examineBoard.BlackMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(-32767 - depth); } return(32767 + depth); } // ReSharper disable once InvertIf if (examineBoard.WhiteMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(32767 + depth); } return(-32767 - depth); } //If Not Mate then StaleMate return(0); } } positions.Sort(Sort); foreach (var move in positions) { //Make a copy var board = examineBoard.FastCopy(); //Move Piece Board.MovePiece(board, move.SrcPosition, move.DstPosition, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.BlackCheck) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } } if (board.WhiteCheck) { if (examineBoard.WhoseMove == ChessPieceColor.White) { continue; } } var value = -AlphaBeta(board, (byte)(depth - 1), -beta, -alpha, ref nodesSearched); if (value >= beta) { return(beta); } if (value > alpha) { alpha = value; } } return(alpha); }
// Not used anymore // ReSharper disable once UnusedMember.Local private static int MinMax(Board examineBoard, byte depth) { if (depth == 0) { //Evaluate Score Evaluation.EvaluateBoardScore(examineBoard); //Invert Score to support Negamax return(SideToMoveScore(examineBoard.Score, examineBoard.WhoseMove)); } var positions = EvaluateMoves(examineBoard, depth); if (examineBoard.WhiteCheck || examineBoard.BlackCheck || positions.Count == 0) { if (SearchForMate(examineBoard.WhoseMove, examineBoard, ref examineBoard.BlackMate, ref examineBoard.WhiteMate, ref examineBoard.StaleMate)) { if (examineBoard.BlackMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(-32767 - depth); } return(32767 + depth); } // ReSharper disable once InvertIf if (examineBoard.WhiteMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { return(32767 + depth); } return(-32767 - depth); } //If Not Mate then StaleMate return(0); } } var bestScore = -32767; foreach (var move in positions) { //Make a copy var board = examineBoard.FastCopy(); //Move Piece Board.MovePiece(board, move.SrcPosition, move.DstPosition, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.BlackCheck) { if (examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } } if (board.WhiteCheck) { if (examineBoard.WhoseMove == ChessPieceColor.White) { continue; } } var value = -MinMax(board, (byte)(depth - 1)); if (value > bestScore) { bestScore = value; } } return(bestScore); }
private static ResultBoards GetSortValidMoves(Board examineBoard) { var sortValidMoves = new ResultBoards { Positions = new List <Board>(30) }; piecesRemaining = 0; for (byte x = 0; x < 64; x++) { var sqr = examineBoard.Squares[x]; //Make sure there is a piece on the square if (sqr.Piece == null) { continue; } piecesRemaining++; //Make sure the color is the same color as the one we are moving. if (sqr.Piece.PieceColor != examineBoard.WhoseMove) { continue; } //For each valid move for this piece foreach (var dst in sqr.Piece.ValidMoves) { //We make copies of the board and move so that we can move it without effecting the parent board var board = examineBoard.FastCopy(); //Make move so we can examine it Board.MovePiece(board, x, dst, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); //Invalid Move if (board.WhiteCheck && examineBoard.WhoseMove == ChessPieceColor.White) { continue; } //Invalid Move if (board.BlackCheck && examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } //We calculate the board score Evaluation.EvaluateBoardScore(board); //Invert Score to support Negamax board.Score = SideToMoveScore(board.Score, board.WhoseMove); sortValidMoves.Positions.Add(board); } } sortValidMoves.Positions.Sort(Sort); return(sortValidMoves); }