Example #1
0
        public static String AsciiBoard(Board board, List <Move> moves = null, bool displayCount = false)
        {
            if (moves == null)
            {
                moves = new List <Move>();
            }
            moves = moves.Where(move => board.IsLegalMove(move)).ToList();

            StringBuilder ascii = new StringBuilder();

            ascii.Append("+---------------+\n");
            for (int row = 7; row >= 0; row--)
            {
                ascii.Append("|");
                for (int column = 0; column < 8; column++)
                {
                    var position        = row * BoardStateOffset.ROW_OFFSET + column;
                    var piece           = board.GetPiece(position);
                    var movesOnPosition = moves.Count(move => move.targetPosition == position);
                    if (movesOnPosition > 0)
                    {
                        if (movesOnPosition < 10 && displayCount)
                        {
                            ascii.Append(movesOnPosition);
                        }
                        else
                        {
                            ascii.Append("x");
                        }
                    }
                    else
                    {
                        ascii.Append(PieceParser.ToChar(piece));
                    }
                    if (column != 7)
                    {
                        ascii.Append(" ");
                    }
                }

                ascii.Append($"| {(row + 1)}\n");
            }
            ascii.Append("+---------------+\n");

            ascii.Append(" A B C D E F G H");
            return(ascii.ToString());
        }
Example #2
0
        public static String BoardToFen(Board board, int move = 0)
        {
            StringBuilder fen = new StringBuilder();

            for (int row = 7; row >= 0; row--)
            {
                int count = 0;
                for (int column = 0; column < 8; column++)
                {
                    var position = row * BoardStateOffset.ROW_OFFSET + column;
                    var piece    = board.GetPiece(position);
                    //var piece = Board.GetPiece(board, position);
                    char c = PieceParser.ToChar(piece);
                    if (c == '_')
                    {
                        count++;
                    }
                    else
                    {
                        if (count != 0)
                        {
                            fen.Append(count);
                            count = 0;
                        }
                        fen.Append(c);
                    }
                }
                if (count != 0)
                {
                    fen.Append(count);
                }

                if (row != 0)
                {
                    fen.Append("/");
                }
            }
            fen.Append(" ");
            fen.Append(board.IsWhiteTurnBool ? "w" : "b");
            fen.Append(" ");
            CastlingBits castlingBits = board.CastlingBits;

            if (castlingBits == CastlingBits.EMPTY)
            {
                fen.Append("-");
            }
            else
            {
                if ((castlingBits & CastlingBits.WHITE_KING_SIDE_CASTLE) != CastlingBits.EMPTY)
                {
                    fen.Append("K");
                }
                if ((castlingBits & CastlingBits.WHITE_QUEEN_SIDE_CASTLE) != CastlingBits.EMPTY)
                {
                    fen.Append("Q");
                }
                if ((castlingBits & CastlingBits.BLACK_KING_SIDE_CASTLE) != CastlingBits.EMPTY)
                {
                    fen.Append("k");
                }
                if ((castlingBits & CastlingBits.BLACK_QUEEN_SIDE_CASTLE) != CastlingBits.EMPTY)
                {
                    fen.Append("q");
                }
            }
            fen.Append(" ");
            fen.Append(board.EnPassantTarget != EnPassant.NO_ENPASSANT ? BoardPosition.ReadablePosition(board.EnPassantTarget) : "-");
            fen.Append(" ");
            fen.Append(board.HalfTurnCounter);
            fen.Append(" ");
            fen.Append(move);

            return(fen.ToString());
        }
Example #3
0
        public static ChessState GameToState(ChessGame game)
        {
            var chessState = new ChessState();
            //var moves = board.GetMoves().Where(move => board.IsLegalMove(move));
            var moves = game.Moves();

            for (int column = 0; column < 8; column++)
            {
                for (int row = 0; row < 8 * BoardStateOffset.ROW_OFFSET; row += BoardStateOffset.ROW_OFFSET)
                {
                    var   position = row + column;
                    Piece piece    = game.board.GetPiece(position);
                    if (piece != Piece.EMPTY)
                    {
                        var from       = BoardPosition.x88PositionToCoordinate(position);
                        var chessPiece = new ChessPiece()
                        {
                            piece   = PieceParser.ToChar(piece).ToString(),
                            row     = from.row,
                            column  = from.column,
                            isWhite = (piece & Piece.IS_WHITE) == Piece.IS_WHITE
                        };

                        chessState.pieces.Add(chessPiece);

                        foreach (var move in moves)
                        {
                            if (move.move.fromPosition == position)
                            {
                                var to = BoardPosition.x88PositionToCoordinate(move.move.targetPosition);
                                chessPiece.options.Add(new PieceOption()
                                {
                                    row         = to.row,
                                    column      = to.column,
                                    isPromotion = (Piece)move.move.promotion != Piece.EMPTY,
                                    isCastle    = ((MoveFlags)move.move.moveFlags & MoveFlags.CASTLING) == MoveFlags.CASTLING,
                                    isEnpassant = (((MoveFlags)move.move.moveFlags & MoveFlags.ENPASSANT) == MoveFlags.ENPASSANT),
                                    san         = move.san
                                });
                            }
                        }
                    }
                }
            }
            var winner = game.Winner();

            if (winner == Winner.DRAW)
            {
                chessState.isDraw = true;
            }
            else if (winner == Winner.WINNER_BLACK)
            {
                chessState.blackWins = true;
            }
            else if (winner == Winner.WINNER_WHITE)
            {
                chessState.whiteWins = true;
            }

            chessState.fen = game.FEN;

            return(chessState);
        }
Example #4
0
        // based on rules from https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
        // Notice the parameter legalMoves only contains legal moves
        public string StandardAlgebraicNotation(Move move, List <Move> legalMoves)
        {
            StringBuilder san   = new StringBuilder();
            var           piece = GetPiece(move.fromPosition);

            if (((MoveFlags)move.moveFlags & MoveFlags.CASTLING) == MoveFlags.CASTLING)
            {
                if (move.targetPosition < move.fromPosition)
                {
                    // castle queen side
                    san.Append("O-O-O");
                }
                else
                {
                    // castle king side
                    san.Append("O-O");
                }
            }
            else
            {
                var isPawn = (piece & Piece.PIECE_MASK) == Piece.PAWN;

                if (!isPawn)
                {
                    // all pieces other pawns display their piece name
                    var pChar = PieceParser.ToChar(piece);
                    san.Append(pChar.ToString().ToUpper());
                }


                int fromRow    = move.fromPosition / BoardStateOffset.ROW_OFFSET;
                int fromColumn = move.fromPosition - (fromRow * BoardStateOffset.ROW_OFFSET);

                bool sameColumns = false;
                bool sameRows    = false;
                bool isAmbigious = false;
                foreach (var possibleMove in legalMoves)
                {
                    // check all other moves of the same piece type if they can move to the same position
                    if (possibleMove.targetPosition == move.targetPosition && // check if it can reach the same square
                        possibleMove.fromPosition != move.fromPosition && // check if not the same piece
                        piece == GetPiece(possibleMove.fromPosition))      // check it is the same type of piece

                    {
                        isAmbigious = true;

                        int possibleFromRow    = possibleMove.fromPosition / BoardStateOffset.ROW_OFFSET;
                        int possibleFromColumn = possibleMove.fromPosition - (possibleFromRow * BoardStateOffset.ROW_OFFSET);
                        if (possibleFromColumn == fromColumn)
                        {
                            sameColumns = true;
                        }
                        if (possibleFromRow == fromRow)
                        {
                            sameRows = true;
                        }
                    }
                }
                if (isPawn)
                {
                    if ((Piece)move.capturedPiece != Piece.EMPTY)
                    {
                        // when pawn captures always specify the starting column
                        san.Append(Convert.ToChar('a' + (fromColumn)));
                    }
                }
                else
                {
                    if (isAmbigious)
                    {
                        // disambiguating moves
                        if (sameColumns && sameRows)
                        {
                            san.Append(Convert.ToChar('a' + (fromColumn)));
                            san.Append((fromRow + 1).ToString());
                        }
                        else if (sameColumns)
                        {
                            san.Append((fromRow + 1).ToString());
                        }
                        else
                        {
                            san.Append(Convert.ToChar('a' + (fromColumn)));
                        }
                    }
                }
                if ((Piece)move.capturedPiece != Piece.EMPTY)
                {
                    san.Append("x");
                }

                int targetRow    = move.targetPosition / BoardStateOffset.ROW_OFFSET;
                int targetColumn = move.targetPosition - (targetRow * BoardStateOffset.ROW_OFFSET);
                san.Append(Convert.ToChar('a' + (targetColumn))).Append((targetRow + 1).ToString());

                Piece promotion = (Piece)move.promotion;
                if (promotion != Piece.EMPTY)
                {
                    san.Append("=").Append(PieceParser.ToChar(promotion).ToString().ToUpper());
                }
            }



            Move(move);

            // check for checkmate
            // after the move is played check if the current players king is attacked
            if (Attacked(GetKingPosition(IsWhiteTurn), IsWhiteTurn))
            {
                var winner = detectWinner(GetMoves());

                if (winner == Winner.WINNER_BLACK || winner == Winner.WINNER_WHITE)
                {
                    //san += "#";
                    san.Append("#");
                }
                else
                {
                    //san += "+";
                    san.Append("+");
                }
            }

            UndoMove(move);

            return(san.ToString());
        }
Example #5
0
        // Loads a board from the FEN notation(Forsyth–Edwards Notation)
        // Useful for getting to certain chess positions quickly.
        // Use the website below to generate positions
        // https://lichess.org/editor/8/1QQ2QQ1/QqqQQqqQ/QqqqqqqQ/QqqqqqqQ/1QqqqqQ1/2QqqQ2/3QQ3_b_-_-_0_1
        // FEN consists of 6 parts which are sepperated by space
        // 1. Position
        //  - Describes what pieces are at which positions
        //  - The pieces are described from left to right with a "/" to indicate row changes
        //  - a single letter is used to represent a piece
        //    - P = Pawn
        //    - N = Knight
        //    - B = Bishop
        //    - R = Rook
        //    - Q = Queen
        //    - K = King
        //  - Capital letters indicate White pieces, while lowercase letter indicate Black pieces
        // 2. active color
        //  - Either "w" or "b", which indicates whose turn it is.
        // 3. castling options
        //  - stores information if about who is allowed to castle.
        //  - Capital letters indicate White side lowercase letters are blacks options
        //  - the letters K and Q mean queen or kingside castle.
        //  - If no castling options it is marked with a "-"
        // 4. En passant target
        //  - marks which square is current possible to attack with en passant.
        // 5. Half move clock
        //  - Stores how many half moves have been made since the last capture or pawn move
        //  - This is used for declaring stalemate
        // 6. Fullmove number
        //  - Counts how many full moves have been made
        //  - full moves are not a part of Board since it is not required to play legal chess, it will be handled by the Chess class
        public static Board LoadBoardFromFen(out int move, String fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
        {
            Board board = new Board(new byte[BoardStateOffset.BOARD_STATE_SIZE]);

            var sections = fen.Split(" ");

            if (sections.Length != 6)
            {
                throw new ArgumentException("FEN has to contanin 6 sections");
            }

            string positions               = sections[0];
            string activeColor             = sections[1];
            string castlingOptions         = sections[2];
            string enPassantAttackedSquare = sections[3];
            string halfMoveClock           = sections[4];
            string fullMoveClock           = sections[5];

            int square = BoardStateOffset.A8;

            for (var i = 0; i < positions.Length; i++)
            {
                char piece = positions[i];
                if (piece == '/')
                {
                    square -= 24;
                }
                else if (Char.IsDigit(piece))
                {
                    square += int.Parse(piece.ToString());
                }
                else
                {
                    Piece parsedPiece = PieceParser.FromChar(piece);
                    //Board.PutPiece(board, square, parsedPiece);
                    board.SetPiece(square, parsedPiece);
                    if ((parsedPiece & Piece.PIECE_MASK) == Piece.KING)
                    {
                        //Board.SetKingPosition(board, (parsedPiece & Piece.IS_WHITE) == Piece.IS_WHITE, square);
                        board.SetKingPosition((int)(parsedPiece & Piece.IS_WHITE), (byte)square);
                    }
                    square++;
                }
            }

            //Board.SetIsWhitesTurn(board, activeColor == "w");
            board.IsWhiteTurnBool = activeColor == "w";

            if (castlingOptions.Contains("K") && board.WhiteKingPosition == BoardStateOffset.E1 && board.GetPiece(BoardStateOffset.H1) == (Piece.ROOK | Piece.IS_WHITE))
            {
                //Board.SetCastleBit(board, CastlingBits.WHITE_KING_SIDE_CASTLE, true);
                board.CastlingBits |= CastlingBits.WHITE_KING_SIDE_CASTLE;
            }
            if (castlingOptions.Contains("Q") && board.WhiteKingPosition == BoardStateOffset.E1 && board.GetPiece(BoardStateOffset.A1) == (Piece.ROOK | Piece.IS_WHITE))
            {
                //Board.SetCastleBit(board, CastlingBits.WHITE_QUEEN_SIDE_CASTLE, true);
                board.CastlingBits |= CastlingBits.WHITE_QUEEN_SIDE_CASTLE;
            }
            if (castlingOptions.Contains("k") && board.BlackKingPosition == BoardStateOffset.E8 && board.GetPiece(BoardStateOffset.H8) == Piece.ROOK)
            {
                //Board.SetCastleBit(board, CastlingBits.BLACK_KING_SIDE_CASTLE, true);
                board.CastlingBits |= CastlingBits.BLACK_KING_SIDE_CASTLE;
            }
            if (castlingOptions.Contains("q") && board.BlackKingPosition == BoardStateOffset.E8 && board.GetPiece(BoardStateOffset.A8) == Piece.ROOK)
            {
                //Board.SetCastleBit(board, CastlingBits.BLACK_QUEEN_SIDE_CASTLE, true);
                board.CastlingBits |= CastlingBits.BLACK_QUEEN_SIDE_CASTLE;
            }

            if (enPassantAttackedSquare == "-")
            {
                //Board.SetEnPassantAttackedSquare(board, EnPassant.NO_ENPASSANT);
                board.EnPassantTarget = EnPassant.NO_ENPASSANT;
            }
            else
            {
                //Board.SetEnPassantAttackedSquare(board, Board.AlgebraicPosition(enPassantAttackedSquare));
                board.EnPassantTarget = (byte)BoardPosition.ArrayPosition(enPassantAttackedSquare);
            }

            //Board.SetHalfTurnCounter(board, int.Parse(halfMoveClock));
            board.HalfTurnCounter = (byte)int.Parse(halfMoveClock);


            //Board.SetFullMoveClock(board, int.Parse(fullMoveClock));
            move = (short)int.Parse(fullMoveClock);
            return(board);
        }