private static ResultBoards GetSortValidMoves(Board examineBoard) { ResultBoards resultBoards = new ResultBoards() { Positions = new List <Board>(30) }; Search.piecesRemaining = 0; for (byte srcPosition = 0; (int)srcPosition < 64; ++srcPosition) { Square square = examineBoard.Squares[(int)srcPosition]; if (square.Piece != null) { ++Search.piecesRemaining; if (square.Piece.PieceColor == examineBoard.WhoseMove) { foreach (byte validMove in square.Piece.ValidMoves) { Board board = examineBoard.FastCopy(); Board.MovePiece(board, srcPosition, validMove, ChessPieceType.Queen); PieceValidMoves.GenerateValidMoves(board); if ((!board.WhiteCheck || examineBoard.WhoseMove != ChessPieceColor.White) && (!board.BlackCheck || examineBoard.WhoseMove != ChessPieceColor.Black)) { Evaluation.EvaluateBoardScore(board); board.Score = Search.SideToMoveScore(board.Score, board.WhoseMove); resultBoards.Positions.Add(board); } } } } } resultBoards.Positions.Sort(new Comparison <Board>(Search.Sort)); return(resultBoards); }
private static ResultBoards GetPossibleBoards(ChessPieceColor movingSide, Board examineBoard) { //We are going to store our result boards here resultBoards = new ResultBoards { Positions = new List <Board>() }; for (byte x = 0; x < 64; x++) { Square 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 (byte dst in sqr.Piece.ValidMoves) { //We make copies of the board and move so that we can move it without effecting the parent board Board 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 && movingSide == ChessPieceColor.Black) { continue; } if (board.WhiteCheck && movingSide == ChessPieceColor.White) { continue; } //We calculate the board score Evaluation.EvaluateBoardScore(board); //Invert Score to support Negamax board.Score = SideToMoveScore(board.Score, GetOppositeColor(movingSide)); resultBoards.Positions.Add(board); } } return(resultBoards); }
public void InitiateBoard(string fen) { ChessBoard = new Board(fen); if (!String.IsNullOrEmpty(fen)) { PieceValidMoves.GenerateValidMoves(ChessBoard); Evaluation.EvaluateBoardScore(ChessBoard); } }
public void InitiateBoard(string fen) { this.ChessBoard = new Board(fen); if (string.IsNullOrEmpty(fen)) { return; } PieceValidMoves.GenerateValidMoves(this.ChessBoard); Evaluation.EvaluateBoardScore(this.ChessBoard); }
public bool MovePiece(byte srcPosition, byte dstPosition) { Piece piece = ChessBoard.Squares[srcPosition].Piece; PreviousChessBoard = new Board(ChessBoard); UndoChessBoard = new Board(ChessBoard); UndoGameBook = new List <OpeningMove>(CurrentGameBook); Board.MovePiece(ChessBoard, srcPosition, dstPosition, PromoteToPieceType); ChessBoard.LastMove.GeneratePGNString(ChessBoard); PieceValidMoves.GenerateValidMoves(ChessBoard); Evaluation.EvaluateBoardScore(ChessBoard); //If there is a check in place, check if this is still true; if (piece.PieceColor == ChessPieceColor.White) { if (ChessBoard.WhiteCheck) { //Invalid Move ChessBoard = new Board(PreviousChessBoard); PieceValidMoves.GenerateValidMoves(ChessBoard); return(false); } } else if (piece.PieceColor == ChessPieceColor.Black) { if (ChessBoard.BlackCheck) { //Invalid Move ChessBoard = new Board(PreviousChessBoard); PieceValidMoves.GenerateValidMoves(ChessBoard); return(false); } } MoveHistory.Push(ChessBoard.LastMove); FileIO.SaveCurrentGameMove(ChessBoard, PreviousChessBoard, CurrentGameBook, ChessBoard.LastMove); CheckForMate(WhoseMove, ref ChessBoard); PieceTakenAdd(ChessBoard.LastMove); if (ChessBoard.WhiteMate || ChessBoard.BlackMate) { LastMove.PgnMove += "#"; } else if (ChessBoard.WhiteCheck || ChessBoard.BlackCheck) { LastMove.PgnMove += "+"; } return(true); }
public void AiPonderMove(BackgroundWorker worker) { this.Thinking = true; this.NodesSearched = 0; ResultBoards resultBoards = new ResultBoards(); resultBoards.Positions = new List <Board>(); if (ChessEngine.Engine.Engine.CheckForMate(this.WhoseMove, ref this.ChessBoard)) { this.Thinking = false; } else { MoveContent bestMove = new MoveContent(); if ((!ChessEngine.Engine.Engine.FindPlayBookMove(ref bestMove, this.ChessBoard, (IEnumerable <OpeningMove>) this.OpeningBook) || (int)this.ChessBoard.FiftyMove > 45 || (int)this.ChessBoard.RepeatedMove >= 2) && (!ChessEngine.Engine.Engine.FindPlayBookMove(ref bestMove, this.ChessBoard, (IEnumerable <OpeningMove>) this.CurrentGameBook) || (int)this.ChessBoard.FiftyMove > 45 || (int)this.ChessBoard.RepeatedMove >= 2)) { bestMove = Search.IterativeSearch(this.ChessBoard, this.PlyDepthSearched, ref this.NodesSearched, ref this.NodesQuiessence, ref this.pvLine, worker, ref this.PlyDepthReached, ref this.RootMovesSearched, this.CurrentGameBook); } this.PreviousChessBoard = new Board(this.ChessBoard); this.RootMovesSearched = (byte)resultBoards.Positions.Count; Board.MovePiece(this.ChessBoard, bestMove.MovingPiecePrimary.SrcPosition, bestMove.MovingPiecePrimary.DstPosition, ChessPieceType.Queen); this.ChessBoard.LastMove.GeneratePGNString(this.ChessBoard); for (byte index = 0; (int)index < 64; ++index) { Square square = this.ChessBoard.Squares[(int)index]; if (square.Piece != null) { square.Piece.DefendedValue = (short)0; square.Piece.AttackedValue = (short)0; } } PieceValidMoves.GenerateValidMoves(this.ChessBoard); Evaluation.EvaluateBoardScore(this.ChessBoard); this.PieceTakenAdd(this.ChessBoard.LastMove); this.MoveHistory.Push(this.ChessBoard.LastMove); if (ChessEngine.Engine.Engine.CheckForMate(this.WhoseMove, ref this.ChessBoard)) { this.Thinking = false; if (!this.ChessBoard.WhiteMate && !this.ChessBoard.BlackMate) { return; } this.LastMove.PgnMove += "#"; } else { if (this.ChessBoard.WhiteCheck || this.ChessBoard.BlackCheck) { this.LastMove.PgnMove += "+"; } this.Thinking = false; } } }
public void Undo() { if (this.UndoChessBoard == null) { return; } this.PieceTakenRemove(this.ChessBoard.LastMove); this.PieceTakenRemove(this.PreviousChessBoard.LastMove); this.ChessBoard = new Board(this.UndoChessBoard); this.CurrentGameBook = new List <OpeningMove>((IEnumerable <OpeningMove>) this.UndoGameBook); PieceValidMoves.GenerateValidMoves(this.ChessBoard); Evaluation.EvaluateBoardScore(this.ChessBoard); }
public void Undo() { if (UndoChessBoard != null) { PieceTakenRemove(ChessBoard.LastMove); PieceTakenRemove(PreviousChessBoard.LastMove); ChessBoard = new Board(UndoChessBoard); CurrentGameBook = new List <OpeningMove>(UndoGameBook); PieceValidMoves.GenerateValidMoves(ChessBoard); Evaluation.EvaluateBoardScore(ChessBoard); } }
private static int Quiescence(Board examineBoard, int alpha, int beta, ref int nodesSearched) { nodesSearched = nodesSearched + 1; Evaluation.EvaluateBoardScore(examineBoard); examineBoard.Score = Search.SideToMoveScore(examineBoard.Score, examineBoard.WhoseMove); if (examineBoard.Score >= beta) { return(beta); } if (examineBoard.Score > alpha) { alpha = examineBoard.Score; } List <Search.Position> positionList = examineBoard.WhiteCheck || examineBoard.BlackCheck ? Search.EvaluateMoves(examineBoard, (byte)0) : Search.EvaluateMovesQ(examineBoard); if (positionList.Count == 0) { return(examineBoard.Score); } positionList.Sort(new Comparison <Search.Position>(Search.Sort)); foreach (Search.Position position in positionList) { if (Search.StaticExchangeEvaluation(examineBoard.Squares[(int)position.DstPosition]) < 0) { Board board = examineBoard.FastCopy(); Board.MovePiece(board, position.SrcPosition, position.DstPosition, ChessPieceType.Queen); PieceValidMoves.GenerateValidMoves(board); if ((!board.BlackCheck || examineBoard.WhoseMove != ChessPieceColor.Black) && (!board.WhiteCheck || examineBoard.WhoseMove != ChessPieceColor.White)) { int num = -Search.Quiescence(board, -beta, -alpha, ref nodesSearched); if (num >= beta) { Search.KillerMove[2, 0].SrcPosition = position.SrcPosition; Search.KillerMove[2, 0].DstPosition = position.DstPosition; return(beta); } if (num > alpha) { alpha = num; } } } } return(alpha); }
public bool MovePiece(byte srcPosition, byte dstPosition) { Piece piece = this.ChessBoard.Squares[(int)srcPosition].Piece; this.PreviousChessBoard = new Board(this.ChessBoard); this.UndoChessBoard = new Board(this.ChessBoard); this.UndoGameBook = new List <OpeningMove>((IEnumerable <OpeningMove>) this.CurrentGameBook); Board.MovePiece(this.ChessBoard, srcPosition, dstPosition, this.PromoteToPieceType); this.ChessBoard.LastMove.GeneratePGNString(this.ChessBoard); PieceValidMoves.GenerateValidMoves(this.ChessBoard); Evaluation.EvaluateBoardScore(this.ChessBoard); if (piece.PieceColor == ChessPieceColor.White) { if (this.ChessBoard.WhiteCheck) { this.ChessBoard = new Board(this.PreviousChessBoard); PieceValidMoves.GenerateValidMoves(this.ChessBoard); return(false); } } else if (piece.PieceColor == ChessPieceColor.Black && this.ChessBoard.BlackCheck) { this.ChessBoard = new Board(this.PreviousChessBoard); PieceValidMoves.GenerateValidMoves(this.ChessBoard); return(false); } this.MoveHistory.Push(this.ChessBoard.LastMove); ChessEngine.Engine.Engine.CheckForMate(this.WhoseMove, ref this.ChessBoard); this.PieceTakenAdd(this.ChessBoard.LastMove); if (this.ChessBoard.WhiteMate || this.ChessBoard.BlackMate) { this.LastMove.PgnMove += "#"; } else if (this.ChessBoard.WhiteCheck || this.ChessBoard.BlackCheck) { this.LastMove.PgnMove += "+"; } return(true); }
public void AiPonderMove() { Thinking = true; /* Fix added to prevent premature declaration of checkmate against computer's king. * * The original version only looked at squares that were available for the black king to move to PRIOR to white's latest move. * So... suppose you had a situation like this: * r4r2/pppb1p1k/8/3p2Q1/q4P2/2np4/6PP/5RK1/ w - 0 27 * ... and moved the white queen from G5 to H5. * At the start of white's move, the black king has 5 possible moves... 4 of which are attackable by white, and noted by * GenerateValidMoves in WhiteAttackBoard[]. When AiPonderMove executes, it immediately eliminates those 4 squares as options * for the black king, even though 2 of them are now safe because no white piece can attack them. However, square 7 is now * directly in the queen's attack path, so it's eliminated as an option as well. Boom, premature checkmate... game over. */ ChessBoard.BlackMate = false; ChessBoard.WhiteMate = false; PieceValidMoves.GenerateValidMoves(ChessBoard); NodesSearched = 0; var resultBoards = new ResultBoards(); resultBoards.Positions = new List <Board>(); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; return; } MoveContent 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++) { Square 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); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; if (ChessBoard.WhiteMate || ChessBoard.BlackMate) { LastMove.PgnMove += "#"; } return; } if (ChessBoard.WhiteCheck || ChessBoard.BlackCheck) { LastMove.PgnMove += "+"; } Thinking = false; }
public int EvaluateBoardScore() { Evaluation.EvaluateBoardScore(ChessBoard); return(ChessBoard.Score); }
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 (Position move in positions) { if (StaticExchangeEvaluation(examineBoard.Squares[move.DstPosition]) >= 0) { continue; } //Make a copy Board 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) { //Invalid Move continue; } } if (board.WhiteCheck) { if (examineBoard.WhoseMove == ChessPieceColor.White) { //Invalid Move continue; } } int 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); }
private static ResultBoards GetSortValidMoves(Board examineBoard) { ResultBoards succ = new ResultBoards { Positions = new List <Board>(30) }; piecesRemaining = 0; for (byte x = 0; x < 64; x++) { Square 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 (byte dst in sqr.Piece.ValidMoves) { //We make copies of the board and move so that we can move it without effecting the parent board Board 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); succ.Positions.Add(board); } } succ.Positions.Sort(Sort); return(succ); }
public void AiPonderMove() { Thinking = true; NodesSearched = 0; var resultBoards = new ResultBoards(); resultBoards.Positions = new List <Board>(); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; return; } MoveContent bestMove = new MoveContent(); //If there is no playbook move search for the best move if (FindPlayBookMove(ref bestMove, ChessBoard, OpeningBook) == false || ChessBoard.FiftyMove > 45 || ChessBoard.RepeatedMove >= 2) { if (FindPlayBookMove(ref bestMove, ChessBoard, CurrentGameBook) == false || ChessBoard.FiftyMove > 45 || 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++) { Square 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); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; if (ChessBoard.WhiteMate || ChessBoard.BlackMate) { LastMove.PgnMove += "#"; } return; } if (ChessBoard.WhiteCheck || ChessBoard.BlackCheck) { LastMove.PgnMove += "+"; } Thinking = false; }
public void AiPonderMove() { Thinking = true; /* Fix added to prevent premature declaration of checkmate against computer's king. * * The original version only looked at squares that were available for the black king to move to PRIOR to white's latest move. * So... suppose you had a situation like this: * r4r2/pppb1p1k/8/3p2Q1/q4P2/2np4/6PP/5RK1/ w - 0 27 * ... and moved the white queen from G5 to H5. * At the start of white's move, the black king has 5 possible moves... 4 of which are attackable by white, and noted by * GenerateValidMoves in WhiteAttackBoard[]. When AiPonderMove executes, it immediately eliminates those 4 squares as options * for the black king, even though 2 of them are now safe because no white piece can attack them. However, square 7 is now * directly in the queen's attack path, so it's eliminated as an option as well. Boom, premature checkmate... game over. * * The time it takes to regenerate the valid moves is nontrivial under Android. To improve performance, * my fix regenerates the valid moves ONLY when it might prevent a game-ending premature declaration * of checkmate, unless the difficulty is set to Hard or VeryHard (in which case it runs every time). * Even a novice player is likely to get confused if the engine declares checkmate for no apparent reason, * but the bug's more insidious manifestations at the two easiest difficulty levels help to make the computer a tiny bit easier * to beat by giving it a blind spot that a player can exploit, the same way HUMAN opponents have blind spots and weaknesses of their own. */ if (ChessBoard.BlackMate || ChessBoard.WhiteMate || (GameDifficulty == Difficulty.VeryHard) || (GameDifficulty == Difficulty.Hard)) { ChessBoard.BlackMate = false; ChessBoard.WhiteMate = false; PieceValidMoves.GenerateValidMoves(ChessBoard); } NodesSearched = 0; var resultBoards = new ResultBoards(); resultBoards.Positions = new List <Board>(); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; return; } MoveContent bestMove = new MoveContent(); //If there is no playbook move search for the best move if (FindPlayBookMove(ref bestMove, ChessBoard, OpeningBook) == false || ChessBoard.FiftyMove > 45 || ChessBoard.RepeatedMove >= 2) { if (FindPlayBookMove(ref bestMove, ChessBoard, CurrentGameBook) == false || ChessBoard.FiftyMove > 45 || 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++) { Square 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); if (CheckForMate(WhoseMove, ref ChessBoard)) { Thinking = false; if (ChessBoard.WhiteMate || ChessBoard.BlackMate) { LastMove.PgnMove += "#"; } return; } if (ChessBoard.WhiteCheck || ChessBoard.BlackCheck) { LastMove.PgnMove += "+"; } Thinking = false; }