Beispiel #1
0
 /// <summary>
 /// Initialize a chess game.
 /// </summary>
 public ChessGame()
 {
     // Create a new ChessBoardState.
     // This keeps track of the position of all pieces, whether or not each king can castle to each side,
     // en passant capture squares, whose turn it is, and number of moves made since the last pawn move / capture.
     boardState = new ChessBoardState();
     boardState.Initialize();
 }
Beispiel #2
0
 public ChessBoardState(ChessBoardState orig)
 {
     this.chessBoard              = orig.chessBoard;
     this.SideToMove              = orig.SideToMove;
     this.WhiteCanCastleKingside  = orig.WhiteCanCastleKingside;
     this.WhiteCanCastleQueenside = orig.WhiteCanCastleQueenside;
     this.BlackCanCastleKingside  = orig.BlackCanCastleKingside;
     this.BlackCanCastleQueenside = orig.BlackCanCastleQueenside;
     this.EnPassantTargetSquare   = orig.EnPassantTargetSquare;
     this.HalfMoveClock           = orig.HalfMoveClock;
     this.FullMoves = orig.FullMoves;
 }
Beispiel #3
0
        public object Clone()
        {
            var newState = new ChessBoardState
            {
                BlackCanCastleKingside  = this.BlackCanCastleKingside,
                BlackCanCastleQueenside = this.BlackCanCastleQueenside,
                WhiteCanCastleKingside  = this.WhiteCanCastleKingside,
                WhiteCanCastleQueenside = this.WhiteCanCastleQueenside,
                EnPassantTargetSquare   = this.EnPassantTargetSquare,
                chessBoard    = (ChessPiece[, ]) this.chessBoard.Clone(),
                FullMoves     = this.FullMoves,
                HalfMoveClock = this.HalfMoveClock,
                SideToMove    = this.SideToMove
            };

            return(newState);
        }
Beispiel #4
0
        /// <summary>
        /// Returns an ordered list of chess moves from the given position.
        /// For each square (starting with a1, going to a8, then b1 to b8, etc), if a piece on that square is movable by the player,
        /// find all moves that piece can make (destination square starting with a1 to a8, then b1 to b8, etc).
        /// </summary>
        /// <returns></returns>
        public List <ChessMove> PossibleMoves(bool onlyReturnCaptures = false)
        {
            var moves = new List <ChessMove>();

            for (var r = 1; r <= 8; r++)
            {
                for (var f = 1; f <= 8; f++)
                {
                    var pieceMoves = new List <ChessMove>();
                    var spot       = this.chessBoard[f, r];
                    if (spot == ChessPiece.Space)
                    {
                        continue;
                    }
                    if ((int)spot * (int)this.SideToMove < 0)
                    {
                        continue;
                    }
                    switch (Math.Abs((int)spot))
                    {
                    case 1:     // pawn
                        // deltaRank is the change in rank for each pawn move.
                        // White will increase their rank with each move, Black will decrease their rank.
                        var deltaRank = (int)SideToMove;
                        if ((SideToMove == ChessColor.White && r == 7) || (SideToMove == ChessColor.Black && r == 2))
                        {
                            // Push + Promotion
                            if (this.chessBoard[f, r + deltaRank] == ChessPiece.Space)
                            {
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece          = spot,
                                    StartSquare    = ChessBoardSquare.GetAN(f, r),
                                    EndSquare      = ChessBoardSquare.GetAN(f, r + deltaRank),
                                    PawnPromotedTo = PromotionChessPiece.Bishop
                                });
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece          = spot,
                                    StartSquare    = ChessBoardSquare.GetAN(f, r),
                                    EndSquare      = ChessBoardSquare.GetAN(f, r + deltaRank),
                                    PawnPromotedTo = PromotionChessPiece.Knight
                                });
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece          = spot,
                                    StartSquare    = ChessBoardSquare.GetAN(f, r),
                                    EndSquare      = ChessBoardSquare.GetAN(f, r + deltaRank),
                                    PawnPromotedTo = PromotionChessPiece.Queen
                                });
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece          = spot,
                                    StartSquare    = ChessBoardSquare.GetAN(f, r),
                                    EndSquare      = ChessBoardSquare.GetAN(f, r + deltaRank),
                                    PawnPromotedTo = PromotionChessPiece.Rook
                                });
                            }

                            // Capture + Promotion
                            // Look for capture forward-left and forward-right.
                            for (var deltaFile = -1; deltaFile <= 1; deltaFile += 2)
                            {
                                if (this.GetSpotPieceColor(f + deltaFile, r + deltaRank) == (ChessColor)(-1 * (int)SideToMove))
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true,
                                        PawnPromotedTo   = PromotionChessPiece.Bishop
                                    });
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true,
                                        PawnPromotedTo   = PromotionChessPiece.Knight
                                    });
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true,
                                        PawnPromotedTo   = PromotionChessPiece.Queen
                                    });
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true,
                                        PawnPromotedTo   = PromotionChessPiece.Rook
                                    });
                                }
                            }
                        }
                        else
                        {
                            if ((SideToMove == ChessColor.White && r == 2) || (SideToMove == ChessColor.Black && r == 7))
                            {
                                // Starting row; can double-push
                                if (this.chessBoard[f, r + deltaRank] == ChessPiece.Space &&
                                    this.chessBoard[f, r + deltaRank + deltaRank] == ChessPiece.Space)
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece       = spot,
                                        StartSquare = ChessBoardSquare.GetAN(f, r),
                                        EndSquare   = ChessBoardSquare.GetAN(f, r + deltaRank + deltaRank)
                                    });
                                }
                            }

                            // Try pushing pawn forward.
                            if (this.chessBoard[f, r + deltaRank] == ChessPiece.Space)
                            {
                                // Push pawn
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece       = spot,
                                    StartSquare = ChessBoardSquare.GetAN(f, r),
                                    EndSquare   = ChessBoardSquare.GetAN(f, r + deltaRank)
                                });
                            }

                            // Check for captures.
                            for (var deltaFile = -1; deltaFile <= 1; deltaFile += 2)
                            {
                                if (this.GetSpotPieceColor(f + deltaFile, r + deltaRank) == (ChessColor)(-1 * (int)SideToMove))
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true
                                    });
                                }

                                if (EnPassantTargetSquare == ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank))
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece            = spot,
                                        StartSquare      = ChessBoardSquare.GetAN(f, r),
                                        EndSquare        = ChessBoardSquare.GetAN(f + deltaFile, r + deltaRank),
                                        WasPieceCaptured = true
                                    });
                                }
                            }
                        }
                        break;

                    case 2:     // Knight
                        var targets = new List <string> {
                            "1,2", "2,1", "1,-2", "2,-1", "-1,-2", "-2,-1", "-1,2", "-2,1"
                        };
                        foreach (var target in targets)
                        {
                            var newFile = f + int.Parse(target.Split(',')[0]);
                            var newRank = r + int.Parse(target.Split(',')[1]);
                            if (newFile < 1 || newFile > 8 || newRank < 1 || newRank > 8)
                            {
                                continue;
                            }
                            var canCapture = this.SpotHasCapturableEnemyPiece(this.SideToMove, ChessBoardSquare.GetAN(newFile, newRank));
                            if (this.chessBoard[newFile, newRank] == ChessPiece.Space || canCapture)
                            {
                                pieceMoves.Add(new ChessMove
                                {
                                    Piece            = spot,
                                    WasPieceCaptured = canCapture,
                                    StartSquare      = ChessBoardSquare.GetAN(f, r),
                                    EndSquare        = ChessBoardSquare.GetAN(newFile, newRank)
                                });
                            }
                        }
                        break;

                    case 3:     // Bishop
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, 1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, 1, spot));
                        break;

                    case 4:     // Rook
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, 0, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, 0, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 0, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 0, 1, spot));
                        break;

                    case 5:     // Queen
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, 1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, 1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 1, 0, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, -1, 0, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 0, -1, spot));
                        pieceMoves.AddRange(GetSlideMoves(f, r, 0, 1, spot));
                        break;

                    case 6:     // King
                        pieceMoves.AddRange(GetAdjacentMoves(f, r, spot));
                        if (this.SideToMove == ChessColor.White)
                        {
                            if (this.chessBoard[5, 1] == ChessPiece.WhiteKing)
                            {
                                if (this.chessBoard[1, 1] == ChessPiece.WhiteRook &&
                                    this.chessBoard[2, 1] == ChessPiece.Space && this.chessBoard[3, 1] == ChessPiece.Space && this.chessBoard[4, 1] == ChessPiece.Space &&
                                    this.WhiteCanCastleQueenside)
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece           = ChessPiece.WhiteKing,
                                        StartSquare     = "e1",
                                        EndSquare       = "c1",
                                        QueensideCastle = true
                                    });
                                }

                                if (this.chessBoard[8, 1] == ChessPiece.WhiteRook &&
                                    this.chessBoard[7, 1] == ChessPiece.Space && this.chessBoard[6, 1] == ChessPiece.Space &&
                                    this.WhiteCanCastleKingside)
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece          = ChessPiece.WhiteKing,
                                        StartSquare    = "e1",
                                        EndSquare      = "g1",
                                        KingsideCastle = true
                                    });
                                }
                            }
                        }
                        else if (this.SideToMove == ChessColor.Black)
                        {
                            if (this.chessBoard[5, 8] == ChessPiece.BlackKing)
                            {
                                if (this.chessBoard[1, 8] == ChessPiece.BlackRook &&
                                    this.chessBoard[2, 8] == ChessPiece.Space && this.chessBoard[3, 8] == ChessPiece.Space && this.chessBoard[4, 8] == ChessPiece.Space &&
                                    this.WhiteCanCastleQueenside)
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece           = ChessPiece.BlackKing,
                                        StartSquare     = "e8",
                                        EndSquare       = "c8",
                                        QueensideCastle = true
                                    });
                                }

                                if (this.chessBoard[8, 8] == ChessPiece.BlackRook &&
                                    this.chessBoard[7, 8] == ChessPiece.Space && this.chessBoard[6, 8] == ChessPiece.Space &&
                                    this.WhiteCanCastleKingside)
                                {
                                    pieceMoves.Add(new ChessMove
                                    {
                                        Piece          = ChessPiece.BlackKing,
                                        StartSquare    = "e8",
                                        EndSquare      = "g8",
                                        KingsideCastle = true
                                    });
                                }
                            }
                        }
                        break;
                    }

                    moves.AddRange(pieceMoves.OrderBy(x => x.EndSquare).ThenBy(x => x.PawnPromotedTo.ToString()));
                }
            }

            // Jump out if we only want to return captures.
            // This is used when determining if the king is in check.
            if (onlyReturnCaptures)
            {
                return(moves.Where(x => x.WasPieceCaptured).ToList());
            }

            // Reject moves that cause the current player's turn's king to be in check.
            var rejectedMoves = new List <ChessMove>();

            foreach (var move in moves)
            {
                ChessBoardState checkBoard = (ChessBoardState)this.Clone();
                if (!checkBoard.TryMakeMove(move))
                {
                    rejectedMoves.Add(move);
                }

                if (checkBoard.IsOpponentInCheck())
                {
                    // Reject the move; the player is in check after making this move.
                    rejectedMoves.Add(move);
                }

                // When the player castles, make sure the King isn't in check, AND not jumping over a check square.
                if (move.KingsideCastle)
                {
                    if (this.IsPlayerInCheck())
                    {
                        rejectedMoves.Add(move);
                    }

                    if (checkBoard.SideToMove == ChessColor.Black)
                    {
                        // White made a move, so now it's Black's turn.  Make sure White's move was legal.
                        this.chessBoard[5, 1] = ChessPiece.Space;
                        this.chessBoard[6, 1] = ChessPiece.WhiteKing;
                        if (this.IsPlayerInCheck())
                        {
                            rejectedMoves.Add(move);
                        }

                        this.chessBoard[5, 1] = ChessPiece.WhiteKing;
                        this.chessBoard[6, 1] = ChessPiece.Space;
                    }
                    else if (checkBoard.SideToMove == ChessColor.White)
                    {
                        // Black made a move, so now it's White's turn.  Make sure Black's move was legal.
                        this.chessBoard[5, 8] = ChessPiece.Space;
                        this.chessBoard[6, 8] = ChessPiece.BlackKing;
                        if (this.IsPlayerInCheck())
                        {
                            rejectedMoves.Add(move);
                        }

                        this.chessBoard[5, 8] = ChessPiece.BlackKing;
                        this.chessBoard[6, 8] = ChessPiece.Space;
                    }
                }
                else if (move.QueensideCastle)
                {
                    if (this.IsPlayerInCheck())
                    {
                        rejectedMoves.Add(move);
                    }

                    if (checkBoard.SideToMove == ChessColor.Black)
                    {
                        // White made a move, so now it's Black's turn.  Make sure White's move was legal.
                        this.chessBoard[5, 1] = ChessPiece.Space;
                        this.chessBoard[4, 1] = ChessPiece.WhiteKing;
                        if (this.IsPlayerInCheck())
                        {
                            rejectedMoves.Add(move);
                        }

                        this.chessBoard[5, 1] = ChessPiece.WhiteKing;
                        this.chessBoard[4, 1] = ChessPiece.Space;
                    }
                    else if (checkBoard.SideToMove == ChessColor.White)
                    {
                        // Black made a move, so now it's White's turn.  Make sure Black's move was legal.
                        this.chessBoard[5, 8] = ChessPiece.Space;
                        this.chessBoard[4, 8] = ChessPiece.BlackKing;
                        if (this.IsPlayerInCheck())
                        {
                            rejectedMoves.Add(move);
                        }

                        this.chessBoard[5, 8] = ChessPiece.BlackKing;
                        this.chessBoard[4, 8] = ChessPiece.Space;
                    }
                }
            }

            moves = moves.Where(x => !rejectedMoves.Contains(x)).ToList();

            return(moves
                   .OrderBy(x => x.StartSquare[1])
                   .ThenBy(x => x.StartSquare[0])
                   .ThenBy(x => x.EndSquare[1])
                   .ThenBy(x => x.EndSquare[0])
                   .ThenBy(x => x.PawnPromotedTo.ToString())
                   .ToList());
        }