Example #1
0
        // Takes ownership of all arrays passed to it; they should not be changed after the position is created.
        public Position(Piece[] pieceSquares, Color sideToMove, ulong castlingRights, ulong enPassant, int fiftyMoveCounter, int fullMove)
        {
            _pieceBitboards = new BitboardArray();
            _squares        = new PieceSquareArray();
            // safer to go by the length the PieceSquareArray, because the Piece[] will always error on index out of bounds
            for (int i = 0; i < _squares.Length; i++)
            {
                _squares[i] = pieceSquares[i];
            }

            PopulatePieceBitboardsFromSquares(ref _pieceBitboards, pieceSquares);

            _occupiedWhite = CalculateOccupied(Color.White);
            _occupiedBlack = CalculateOccupied(Color.Black);

            _occupied = _occupiedWhite | _occupiedBlack;

            Parent = null;

            SideToMove     = sideToMove;
            CastlingRights = castlingRights;
            EnPassant      = enPassant;

            FiftyMoveCounter = fiftyMoveCounter;
            GamePly          = GamePlyFromFullMove(fullMove, sideToMove);
            _historyPly      = 0;

            RepetitionNumber = 1;

            ZobristHash = ZobristHashing.CalculateFullHash(this);
        }
Example #2
0
        public static Position MakeMove(Position shell, Move move, Position parent)
        {
            // copy data which doesn't depend on performing the move
            parent.CopyPieceBitboards(ref shell._pieceBitboards);
            parent.CopySquares(ref shell._squares);
            shell.ZobristHash      = parent.ZobristHash;
            shell.Parent           = parent;
            shell._inCheckWhite    = null;
            shell._inCheckBlack    = null;
            shell.SideToMove       = parent.SideToMove.Other();
            shell.EnPassant        = 0; // this gets set for double moves
            shell.FiftyMoveCounter = CalculateFiftyMoveCounter(parent, move);
            shell.GamePly          = parent.GamePly + 1;
            shell._historyPly      = parent._historyPly + 1;

            switch (move.MoveType)
            {
            case MoveType.Normal | MoveType.Quiet:
                shell.MakeNormalQuietMove(move);
                break;

            case MoveType.Normal | MoveType.Capture:
                shell.MakeNormalCaptureMove(move);
                break;

            case MoveType.DoubleMove | MoveType.Quiet:
                shell.MakeDoublePawnMove(move);
                break;

            case MoveType.EnPassant | MoveType.Capture:
                shell.MakeEnPassantMove(move);
                break;

            case MoveType.Promotion | MoveType.Quiet:
                shell.MakePromotionQuietMove(move);
                break;

            case MoveType.Promotion | MoveType.Capture:
                shell.MakePromotionCaptureMove(move);
                break;

            case MoveType.Castling | MoveType.Quiet:
                shell.MakeCastlingMove(move);
                break;

            default:
                throw new Exception($"Invalid move type: {move.MoveType}");
            }

            shell.CastlingRights   = parent.CastlingRights & CastlingTables.GetCastlingUpdateMask(move);
            shell._occupiedWhite   = shell.CalculateOccupied(Color.White);
            shell._occupiedBlack   = shell.CalculateOccupied(Color.Black);
            shell._occupied        = shell._occupiedWhite | shell._occupiedBlack;
            shell.ZobristHash     ^= ZobristHashing.OtherHashDiff(parent, shell);
            shell.RepetitionNumber = CalculateRepetitionNumber(shell);

            return(shell);
        }
Example #3
0
        private void RemovePiece(int ix, Color color, PieceType pieceType)
        {
            Debug.Assert(_squares[ix] == new Piece(color, pieceType));
            _pieceBitboards[PieceBitboardIndex(color, pieceType)] &= ~ValueFromIx(ix);
            _squares[ix] = Piece.None;

            ZobristHash ^= ZobristHashing.CalculatePieceBitboardHashDiff(ValueFromIx(ix), color, pieceType);
            // TODO: material hash update
            // TODO: pawn hash update
        }
Example #4
0
        private void MovePiece(int srcIx, int dstIx, Color color, PieceType pieceType)
        {
            Debug.Assert(_squares[srcIx] == new Piece(color, pieceType));
            Debug.Assert(_squares[dstIx].PieceType == PieceType.None);
            _pieceBitboards[PieceBitboardIndex(color, pieceType)] &= ~ValueFromIx(srcIx);
            _pieceBitboards[PieceBitboardIndex(color, pieceType)] |= ValueFromIx(dstIx);
            _squares[srcIx] = Piece.None;
            _squares[dstIx] = new Piece(color, pieceType);

            ZobristHash ^= ZobristHashing.CalculatePieceBitboardHashDiff(
                ValueFromIx(srcIx) | ValueFromIx(dstIx),
                color,
                pieceType);
            // No material hash update needed
            // TODO: pawn hash update
        }
Example #5
0
        public static BoardState Parse(string fen, bool allocateStacks)
        {
            var split          = fen.Split(' ');
            var boardState     = split[0];
            var colorState     = split[1];
            var castlingState  = split[2];
            var enPassantState = split[3];

            var halfmoveClock = 0;
            var movesCount    = 0;

            if (split.Length > 4)
            {
                int.TryParse(split[4], out halfmoveClock);
            }

            if (split.Length > 5)
            {
                int.TryParse(split[5], out movesCount);
            }

            var result       = new BoardState(allocateStacks);
            var currentColor = ParseCurrentColor(colorState);

            ParseBoardState(boardState, result);
            ParseCastlingState(castlingState, result);
            ParseEnPassantState(enPassantState, result);

            result.RecalculateEvaluationDependentValues();
            result.CalculatePieceTable(result.PieceTable);

            result.MovesCount             = movesCount;
            result.IrreversibleMovesCount = halfmoveClock;
            result.ColorToMove            = currentColor;
            result.Hash     = ZobristHashing.CalculateHash(result);
            result.PawnHash = ZobristHashing.CalculatePawnHash(result);

            result.CastlingDone[Color.White] = (result.Castling & Castling.WhiteCastling) == 0;
            result.CastlingDone[Color.Black] = (result.Castling & Castling.BlackCastling) == 0;

            return(result);
        }
Example #6
0
            public void NoTwoKeysShouldBeTheSame()
            {
                var hash = new ZobristHashing();

                for (int i = 0; i < hash.PieceKeys.Length; i++)
                {
                    for (int j = i + 1; j < hash.PieceKeys.Length; j++)
                    {
                        (hash.PieceKeys[i] == hash.PieceKeys[j]).Should().BeFalse();
                    }
                    for (int j = 0; j < hash.CastleKeys.Length; j++)
                    {
                        (hash.PieceKeys[i] == hash.CastleKeys[j]).Should().BeFalse();
                    }
                    for (int j = 0; j < hash.EnPassantKeys.Length; j++)
                    {
                        (hash.PieceKeys[i] == hash.EnPassantKeys[j]).Should().BeFalse();
                    }
                    (hash.PieceKeys[i] == hash.SideKey).Should().BeFalse();
                }

                for (int i = 0; i < hash.CastleKeys.Length; i++)
                {
                    for (int j = i + 1; j < hash.CastleKeys.Length; j++)
                    {
                        (hash.CastleKeys[i] == hash.CastleKeys[j]).Should().BeFalse();
                    }
                    for (int j = 0; j < hash.EnPassantKeys.Length; j++)
                    {
                        (hash.CastleKeys[i] == hash.EnPassantKeys[j]).Should().BeFalse();
                    }
                    (hash.CastleKeys[i] == hash.SideKey).Should().BeFalse();
                }
                for (int i = 0; i < hash.EnPassantKeys.Length; i++)
                {
                    for (int j = i + 1; j < hash.EnPassantKeys.Length; j++)
                    {
                        (hash.EnPassantKeys[i] == hash.EnPassantKeys[j]).Should().BeFalse();
                    }
                    (hash.EnPassantKeys[i] == hash.SideKey).Should().BeFalse();
                }
            }
Example #7
0
        private static bool VerifyBoard(BoardState board)
        {
            if (board.Material[Color.White] != board.CalculateMaterial(Color.White) ||
                board.Material[Color.Black] != board.CalculateMaterial(Color.Black))
            {
                return(false);
            }

            if (board.Hash != ZobristHashing.CalculateHash(board))
            {
                return(false);
            }

            if (board.PawnHash != ZobristHashing.CalculatePawnHash(board))
            {
                return(false);
            }

            if (board.Position[Color.White][GamePhase.Opening] != board.CalculatePosition(Color.White, GamePhase.Opening) ||
                board.Position[Color.White][GamePhase.Ending] != board.CalculatePosition(Color.White, GamePhase.Ending) ||
                board.Position[Color.Black][GamePhase.Opening] != board.CalculatePosition(Color.Black, GamePhase.Opening) ||
                board.Position[Color.Black][GamePhase.Ending] != board.CalculatePosition(Color.Black, GamePhase.Ending))
            {
                return(false);
            }

            var pieceTable = new int[64];

            board.CalculatePieceTable(pieceTable);

            for (var fieldIndex = 0; fieldIndex < 64; fieldIndex++)
            {
                if (board.PieceTable[fieldIndex] != pieceTable[fieldIndex])
                {
                    return(false);
                }
            }

            return(true);
        }
Example #8
0
        private void ZobristTestHelper(Position position, int depth)
        {
            Assert.AreEqual(position.ZobristHash, ZobristHashing.CalculateFullHash(position));
            if (depth <= 0)
            {
                return;
            }

            var moves = new List <Move>();

            _moveGenerator.Generate(moves, position);

            foreach (var move in moves)
            {
                var updatedBoard = Position.MakeMove(new Position(), move, position);

                if (!_moveGenerator.OnlyLegalMoves && updatedBoard.MovedIntoCheck())
                {
                    continue;
                }

                ZobristTestHelper(updatedBoard, depth - 1);
            }
        }
Example #9
0
        public static BoardState Parse(string fen)
        {
            var split          = fen.Split(' ');
            var boardState     = split[0];
            var colorState     = split[1];
            var castlingState  = split[2];
            var enPassantState = split[3];
            var halfmoveClock  = split.Length > 4 ? int.Parse(split[4]) : 0;
            var movesCount     = split.Length > 5 ? int.Parse(split[5]) : 0;

            var result       = new BoardState();
            var currentColor = ParseCurrentColor(colorState);

            ParseBoardState(boardState, result);
            ParseCastlingState(castlingState, result);
            ParseEnPassantState(enPassantState, result);

            result.Material[Color.White] = result.CalculateMaterial(Color.White);
            result.Material[Color.Black] = result.CalculateMaterial(Color.Black);

            result.Position[Color.White][GamePhase.Opening] = result.CalculatePosition(Color.White, GamePhase.Opening);
            result.Position[Color.White][GamePhase.Ending]  = result.CalculatePosition(Color.White, GamePhase.Ending);
            result.Position[Color.Black][GamePhase.Opening] = result.CalculatePosition(Color.Black, GamePhase.Opening);
            result.Position[Color.Black][GamePhase.Ending]  = result.CalculatePosition(Color.Black, GamePhase.Ending);

            result.CalculatePieceTable(result.PieceTable);
            result.MaterialAtOpening = result.CalculateMaterialAtOpening();

            result.MovesCount             = movesCount;
            result.IrreversibleMovesCount = halfmoveClock;
            result.ColorToMove            = currentColor;
            result.Hash     = ZobristHashing.CalculateHash(result);
            result.PawnHash = ZobristHashing.CalculatePawnHash(result);

            return(result);
        }