Beispiel #1
0
        /// <summary>
        /// Limitation: castling moves decoded from a string can't be undone
        /// </summary>
        public void UndoMove(Move move)
        {
#if DEBUG
            _moveHistory.Pop();
#endif
            _colorToMove = 1 - _colorToMove;

            var state = _gameStateHistory.Pop();
            if (state.CapturedPiece != Piece.None)
            {
                if (move.IsEnPassant)
                {
                    var enPassantOffset = WhiteToMove ? 8 : -8;
                    EnemyPieces.Add(state.CapturedPiece, move.EndSquare + enPassantOffset);
                }
                else
                {
                    EnemyPieces.Add(state.CapturedPiece, move.EndSquare);
                }

                // Restore original piece position, replacing with pawn in case of promotion move
                PiecesToMove.Move(move.EndSquare, move.StartSquare, move.PromotionPiece != Piece.None ? Piece.Pawn : Piece.None);
            }
            else if (move.IsCastling)
            {
                // Return rook and King to it's original square
                (int rookOriginalSquare, int rookEndSquare) = GetCastlingRookMove(move);
                PiecesToMove.RemoveAt(rookEndSquare);
                PiecesToMove.RemoveAt(GetCastlingKingSqare(move));
                PiecesToMove.Add(Piece.King, move.StartSquare);
                PiecesToMove.Add(Piece.Rook, rookOriginalSquare);
            }
            else
            {
                // Restore original piece position, replacing with pawn in case of promotion move
                PiecesToMove.Move(move.EndSquare, move.StartSquare, move.PromotionPiece != Piece.None ? Piece.Pawn : Piece.None);
            }

            TotalMoves -= _colorToMove;

#if MOVE_CONSISTENCY_CHECK
            var previousPosition = _fenHistory.Pop();
            var restoredPosition = _fenWriter.Write(this, true);
            if (previousPosition != restoredPosition)
            {
                System.Diagnostics.Debugger.Break();
            }
#endif
        }
Beispiel #2
0
        public Position MakeMove(Move move)
        {
#if DEBUG
            _moveHistory.Push(move);
#endif
#if MOVE_CONSISTENCY_CHECK
            _fenHistory.Push(_fenWriter.Write(this, true));
#endif
            // Get the curent state to apply changes on top of it
            var state = CurrentState;
            state.HalfMoveClock++;
            state.CapturedPiece = Piece.None;

            int newEnPassantSquare = -1;

            // Adjust castling flags before actually moving pieces
            Castling enemyCastlingOptions = state[1 - _colorToMove];
            Castling castlingOptions      = state[_colorToMove];
            if (enemyCastlingOptions != 0 && EnemyPieces[move.EndSquare] == Piece.Rook)
            {
                // One of the rooks was captured
                enemyCastlingOptions &= move.EndSquare % Constants.BoardFiles == QueenSideRookFile ? ~Castling.QueenSide : ~Castling.KingSide;
            }

            if (castlingOptions != 0)
            {
                if (PiecesToMove[move.StartSquare] == Piece.Rook)
                {
                    // One of the rooks was moved
                    castlingOptions &= move.StartSquare % Constants.BoardFiles == QueenSideRookFile ? ~Castling.QueenSide : ~Castling.KingSide;
                }
                else if (PiecesToMove[move.StartSquare] == Piece.King)
                {
                    // King was moved
                    castlingOptions = 0;
                }
            }

            if (EnemyPieces[move.EndSquare] != Piece.None)
            {
                // Capture, remove enemy piece from the board and reset the clock
                state.CapturedPiece = EnemyPieces[move.EndSquare];
                state.HalfMoveClock = 0;
                EnemyPieces.RemoveAt(move.EndSquare);
                PiecesToMove.Move(move.StartSquare, move.EndSquare, move.PromotionPiece);
            }
            else if (PiecesToMove[move.StartSquare] == Piece.Pawn)
            {
                // Reset the clock on pawn moves
                state.HalfMoveClock = 0;
                var enPassantOffset = WhiteToMove ? 8 : -8;
                if (move.EndSquare == state.EnPassantSquare)
                {
                    // EnPassant, remove enemy pawn from the board
                    state.CapturedPiece = Piece.Pawn;
                    EnemyPieces.RemoveAt(move.EndSquare + enPassantOffset);
                }
                else if (move.StartSquare - move.EndSquare == enPassantOffset * 2)
                {
                    // EnPassant is possible next move
                    newEnPassantSquare = move.EndSquare + enPassantOffset;
                }

                PiecesToMove.Move(move.StartSquare, move.EndSquare, move.PromotionPiece);
            }
            else if (PiecesToMove[move.StartSquare] == Piece.King &&
                     (Math.Abs(move.StartSquare - move.EndSquare) == 2 || PiecesToMove[move.EndSquare] == Piece.Rook))
            {
                // Castling
                // To support general chess 960 case remove king and rook from the board and put them to the final sqares
                (int rookStartSquare, int rookEndSquare) = GetCastlingRookMove(move);
                PiecesToMove.RemoveAt(rookStartSquare);
                PiecesToMove.RemoveAt(move.StartSquare);
                PiecesToMove.Add(Piece.King, GetCastlingKingSqare(move));
                PiecesToMove.Add(Piece.Rook, rookEndSquare);
            }
            else
            {
                // General piece move
                PiecesToMove.Move(move.StartSquare, move.EndSquare, move.PromotionPiece);
            }

            state[1 - _colorToMove] = enemyCastlingOptions;
            state[_colorToMove]     = castlingOptions;
            state.EnPassantSquare   = newEnPassantSquare;
            _gameStateHistory.Push(state);

            // Increment total moves after the black's move only
            TotalMoves  += _colorToMove;
            _colorToMove = 1 - _colorToMove;

            return(this);
        }