/// <summary> /// Generates the move. /// </summary> /// <param name="board">The board</param> /// <param name="from">The starting square</param> /// <param name="to">The ending square</param> /// <returns></returns> internal override Move GenerateMove(Board board, int from, int to) { Move move; // if it's an en passant capture if (IsEnPassantCaptureMove(board, from, to)) { move = new EnPassantCaptureMove(board.Status, from, to); move.ChangeSideToMove(); // change the side to move move.SetEnPassantTarget(null); // reset the en passant target move.ResetPly(); // reset the ply move.IncrementMoves(); // increment the number of moves // we need to verify for check move.Make(board); bool result = !board.BlackKingInCheck(); move.TakeBack(board); return(result ? move : null); } move = base.GenerateMove(board, from, to); if (move != null) { move.ResetPly();// reset the ply // if it's the two-squares move if (IsTwoSquaresMove(board, from, to)) { // set the en passant target move.SetEnPassantTarget(to - Board.SideSquareNo); } // if it's a promotion if (Board.Rank(to) == Board.SideSquareNo - 1) { // we don't need to verify for check again // so the promotion delegate will not be triggered // later we will change the promotion type as needed move = new PromotionMove(board.Status, from, to); move.ChangeSideToMove(); // change the side to move move.SetEnPassantTarget(null); // reset the en passant target move.ResetPly(); // reset the ply move.IncrementMoves(); // increment the number of moves (move as PromotionMove).SetCapture(board[to]); // the capture information is set } return(move); } else { return(null); } }
/// <summary> /// Generates the move. /// Adds check verification to move generation, /// returns null if its own king will be in check. /// </summary> /// <param name="board">The board</param> /// <param name="from">The starting square</param> /// <param name="to">The ending square</param> /// <returns></returns> internal override Move GenerateMove(Board board, int from, int to) { Move move = base.GenerateMove(board, from, to); if (move != null) { move.IncrementMoves();// the number of moves is incremented after Black moves // verify for king in check move.Make(board); bool result = !board.BlackKingInCheck(); move.TakeBack(board); return result ? move : null; } else { return null; } }
/// <summary> /// Generates the move. /// Adds check verification to move generation, /// returns null if its own king will be in check. /// </summary> /// <param name="board">The board</param> /// <param name="from">The starting square</param> /// <param name="to">The ending square</param> /// <returns></returns> internal override Move GenerateMove(Board board, int from, int to) { Move move = base.GenerateMove(board, from, to); if (move != null) { move.IncrementMoves();// the number of moves is incremented after Black moves // verify for king in check move.Make(board); bool result = !board.BlackKingInCheck(); move.TakeBack(board); return(result ? move : null); } else { return(null); } }
/// <summary> /// Verifies the current board for check. /// </summary> /// <returns></returns> private bool IsCheck() { return(currentBoard.Status.WhiteTurn ? currentBoard.WhiteKingInCheck() : currentBoard.BlackKingInCheck()); }
/// <summary> /// Verifies if the board is in a valid state, throws ArgumentException if it's not. /// </summary> /// <param name="board">The board</param> public static void VerifyState(Board board) { // the board must not be null if (board == null) { throw new ArgumentNullException("board", Resources.NullBoardMsg); } // hastable to remember the number of each piece type // a pair consists in a piece type and the number of pieces on this board Dictionary <Type, int> pieceNo = new Dictionary <Type, int>(Piece.TypesNo); // initialize the values with 0 foreach (Type type in pieceZobristIndexTable.Keys) { pieceNo[type] = 0; } // loop through the squares for (int sqIndex = 0; sqIndex < Board.SquareNo; sqIndex++) { if (board[sqIndex] != null) { // increment the number of this piece type Type type = board[sqIndex].GetType(); pieceNo[type] = pieceNo[type] + 1; // check if the White Pawn has rank 1 if (type == typeof(WhitePawn) && Utils.GetRankNotation(sqIndex) == '1') { throw new ArgumentException(Resources.WhitePawnRank1Msg, "board"); } // check if the Black Pawn has rank 8 if (type == typeof(BlackPawn) && Utils.GetRankNotation(sqIndex) == '8') { throw new ArgumentException(Resources.BlackPawnRank8Msg, "board"); } } } // if there are too many White pieces // check if the number of Pawns // plus the number of extra Queens, Rooks, Bishops, Knights // (which can result only by promotion) exceeds 8 if ((pieceNo[typeof(WhitePawn)] + Math.Max(pieceNo[typeof(WhiteQueen)] - 1, 0) + Math.Max(pieceNo[typeof(WhiteRook)] - 2, 0) + Math.Max(pieceNo[typeof(WhiteBishop)] - 2, 0) + Math.Max(pieceNo[typeof(WhiteKnight)] - 2, 0)) > 8) { throw new ArgumentException(Resources.TooManyWhitePiecesMsg, "board"); } // if there are too many Black pieces // check if the number of Pawns // plus the number of extra Queens, Rooks, Bishops, Knights // (which can result only by promotion) exceeds 8 if ((pieceNo[typeof(BlackPawn)] + Math.Max(pieceNo[typeof(BlackQueen)] - 1, 0) + Math.Max(pieceNo[typeof(BlackRook)] - 2, 0) + Math.Max(pieceNo[typeof(BlackBishop)] - 2, 0) + Math.Max(pieceNo[typeof(BlackKnight)] - 2, 0)) > 8) { throw new ArgumentException(Resources.TooManyBlackPiecesMsg, "board"); } // check for White King if (pieceNo[typeof(WhiteKing)] > 1) { throw new ArgumentException(Resources.MoreThanOneWhiteKingMsg, "board"); } if (pieceNo[typeof(WhiteKing)] < 1) { throw new ArgumentException(Resources.NoWhiteKingMsg, "board"); } // check for Black King if (pieceNo[typeof(BlackKing)] > 1) { throw new ArgumentException(Resources.MoreThanOneBlackKingMsg, "board"); } if (pieceNo[typeof(BlackKing)] < 1) { throw new ArgumentException(Resources.NoBlackKingMsg, "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.WhiteCouldCastleShort && !(board[Board.E1] is WhiteKing && board[Board.H1] is WhiteRook)) { throw new ArgumentException(Resources.IllegalWhiteKingShortCastlingMsg, "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.WhiteCouldCastleLong && !(board[Board.E1] is WhiteKing && board[Board.A1] is WhiteRook)) { throw new ArgumentException(Resources.IllegalWhiteKingLongCastlingMsg, "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.BlackCouldCastleShort && !(board[Board.E8] is BlackKing && board[Board.H8] is BlackRook)) { throw new ArgumentException(Resources.IllegalBlackKingShortCastlingMsg, "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.BlackCouldCastleLong && !(board[Board.E8] is BlackKing && board[Board.A8] is BlackRook)) { throw new ArgumentException(Resources.IllegalBlackKingLongCastlingMsg, "board"); } // check the en passant target if ( board.Status.EnPassantTarget != null && !( ( Board.Rank(board.Status.EnPassantTarget.Value) == 5 && board.Status.BlackTurn && // the rank of en passant target is correct board[board.Status.EnPassantTarget.Value - Board.SideSquareNo] is WhitePawn && // there is a pawn in front of the target board[board.Status.EnPassantTarget.Value] == null && board[board.Status.EnPassantTarget.Value + Board.SideSquareNo] == null // the en passant target square and the one behind are empty ) || ( Board.Rank(board.Status.EnPassantTarget.Value) == 2 && board.Status.WhiteTurn && // the rank of en passant target is correct board[board.Status.EnPassantTarget.Value + Board.SideSquareNo] is BlackPawn && // there is a pawn in front of the target board[board.Status.EnPassantTarget.Value] == null && board[board.Status.EnPassantTarget.Value - Board.SideSquareNo] == null // the en passant target square and the one behind are empty ) ) ) { throw new ArgumentException(Resources.IllegalEPTargetMsg, "board"); } // check if ply >= 0 if (board.Status.Ply < 0) { throw new ArgumentException(Resources.NonNegativePlyMsg, "board"); } // check if move number >= 1 if (board.Status.Moves < 1) { throw new ArgumentException(Resources.PositiveMoveNoMsg, "board"); } // check if the side which is not to move is in check if ((board.Status.WhiteTurn && board.BlackKingInCheck()) || (board.Status.BlackTurn && board.WhiteKingInCheck())) { throw new ArgumentException(Resources.NoSideNotToMoveCheckMsg, "board"); } }
/// <summary> /// Generates the move. /// </summary> /// <param name="board">The board</param> /// <param name="from">The starting square</param> /// <param name="to">The ending square</param> /// <returns></returns> internal override Move GenerateMove(Board board, int from, int to) { Move move; // if it's an en passant capture if (IsEnPassantCaptureMove(board, from, to)) { move = new EnPassantCaptureMove(board.Status, from, to); move.ChangeSideToMove();// change the side to move move.SetEnPassantTarget(null);// reset the en passant target move.ResetPly();// reset the ply move.IncrementMoves();// increment the number of moves // we need to verify for check move.Make(board); bool result = !board.BlackKingInCheck(); move.TakeBack(board); return result ? move : null; } move = base.GenerateMove(board, from, to); if (move != null) { move.ResetPly();// reset the ply // if it's the two-squares move if (IsTwoSquaresMove(board, from, to)) { // set the en passant target move.SetEnPassantTarget(to - Board.SideSquareNo); } // if it's a promotion if (Board.Rank(to) == Board.SideSquareNo - 1) { // we don't need to verify for check again // so the promotion delegate will not be triggered // later we will change the promotion type as needed move = new PromotionMove(board.Status, from, to); move.ChangeSideToMove();// change the side to move move.SetEnPassantTarget(null);// reset the en passant target move.ResetPly();// reset the ply move.IncrementMoves();// increment the number of moves (move as PromotionMove).SetCapture(board[to]);// the capture information is set } return move; } else { return null; } }
/// <summary> /// Verifies if the board is in a valid state, throws ArgumentException if it's not. /// </summary> /// <param name="board">The board</param> public static void VerifyState(Board board) { // the board must not be null if (board == null) { throw new ArgumentNullException("board", "Resources.NullBoardMsg"); } // hastable to remember the number of each piece type // a pair consists in a piece type and the number of pieces on this board Dictionary<Type, int> pieceNo = new Dictionary<Type, int>(Piece.TypesNo); // initialize the values with 0 foreach (Type type in pieceZobristIndexTable.Keys) { pieceNo[type] = 0; } // loop through the squares for (int sqIndex = 0; sqIndex < Board.SquareNo; sqIndex++) { if (board[sqIndex] != null) { // increment the number of this piece type Type type = board[sqIndex].GetType(); pieceNo[type] = pieceNo[type] + 1; // check if the White Pawn has rank 1 if (type == typeof(WhitePawn) && Utils.GetRankNotation(sqIndex) == '1') { throw new ArgumentException("Resources.WhitePawnRank1Msg", "board"); } // check if the Black Pawn has rank 8 if (type == typeof(BlackPawn) && Utils.GetRankNotation(sqIndex) == '8') { throw new ArgumentException("Resources.BlackPawnRank8Msg", "board"); } } } // if there are too many White pieces // check if the number of Pawns // plus the number of extra Queens, Rooks, Bishops, Knights // (which can result only by promotion) exceeds 8 if ((pieceNo[typeof(WhitePawn)] + Math.Max(pieceNo[typeof(WhiteQueen)] - 1, 0) + Math.Max(pieceNo[typeof(WhiteRook)] - 2, 0) + Math.Max(pieceNo[typeof(WhiteBishop)] - 2, 0) + Math.Max(pieceNo[typeof(WhiteKnight)] - 2, 0)) > 8) { throw new ArgumentException("Resources.TooManyWhitePiecesMsg", "board"); } // if there are too many Black pieces // check if the number of Pawns // plus the number of extra Queens, Rooks, Bishops, Knights // (which can result only by promotion) exceeds 8 if ((pieceNo[typeof(BlackPawn)] + Math.Max(pieceNo[typeof(BlackQueen)] - 1, 0) + Math.Max(pieceNo[typeof(BlackRook)] - 2, 0) + Math.Max(pieceNo[typeof(BlackBishop)] - 2, 0) + Math.Max(pieceNo[typeof(BlackKnight)] - 2, 0)) > 8) { throw new ArgumentException("Resources.TooManyBlackPiecesMsg", "board"); } // check for White King if (pieceNo[typeof(WhiteKing)] > 1) { throw new ArgumentException("Resources.MoreThanOneWhiteKingMsg", "board"); } if (pieceNo[typeof(WhiteKing)] < 1) { throw new ArgumentException("Resources.NoWhiteKingMsg", "board"); } // check for Black King if (pieceNo[typeof(BlackKing)] > 1) { throw new ArgumentException("Resources.MoreThanOneBlackKingMsg", "board"); } if (pieceNo[typeof(BlackKing)] < 1) { throw new ArgumentException("Resources.NoBlackKingMsg", "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.WhiteCouldCastleShort && !(board[Board.E1] is WhiteKing && board[Board.H1] is WhiteRook)) { throw new ArgumentException("Resources.IllegalWhiteKingShortCastlingMsg", "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.WhiteCouldCastleLong && !(board[Board.E1] is WhiteKing && board[Board.A1] is WhiteRook)) { throw new ArgumentException("Resources.IllegalWhiteKingLongCastlingMsg", "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.BlackCouldCastleShort && !(board[Board.E8] is BlackKing && board[Board.H8] is BlackRook)) { throw new ArgumentException("Resources.IllegalBlackKingShortCastlingMsg", "board"); } // check if the King and the Rook are in place for castling availability if (board.Status.BlackCouldCastleLong && !(board[Board.E8] is BlackKing && board[Board.A8] is BlackRook)) { throw new ArgumentException("Resources.IllegalBlackKingLongCastlingMsg", "board"); } // check the en passant target if ( board.Status.EnPassantTarget != null && !( ( Board.Rank(board.Status.EnPassantTarget.Value) == 5 && board.Status.BlackTurn &&// the rank of en passant target is correct board[board.Status.EnPassantTarget.Value - Board.SideSquareNo] is WhitePawn &&// there is a pawn in front of the target board[board.Status.EnPassantTarget.Value] == null && board[board.Status.EnPassantTarget.Value + Board.SideSquareNo] == null// the en passant target square and the one behind are empty ) || ( Board.Rank(board.Status.EnPassantTarget.Value) == 2 && board.Status.WhiteTurn &&// the rank of en passant target is correct board[board.Status.EnPassantTarget.Value + Board.SideSquareNo] is BlackPawn &&// there is a pawn in front of the target board[board.Status.EnPassantTarget.Value] == null && board[board.Status.EnPassantTarget.Value - Board.SideSquareNo] == null// the en passant target square and the one behind are empty ) ) ) { throw new ArgumentException("Resources.IllegalEPTargetMsg", "board"); } // check if ply >= 0 if (board.Status.Ply < 0) { throw new ArgumentException("Resources.NonNegativePlyMsg", "board"); } // check if move number >= 1 if (board.Status.Moves < 1) { throw new ArgumentException("Resources.PositiveMoveNoMsg", "board"); } // check if the side which is not to move is in check if ((board.Status.WhiteTurn && board.BlackKingInCheck()) || (board.Status.BlackTurn && board.WhiteKingInCheck())) { throw new ArgumentException("Resources.NoSideNotToMoveCheckMsg", "board"); } }