public BoardState(Piece[] currentBoardPosition, UInt64[] pieceToBitboard, CastlingAndEnPassantRights castlingAndEnPassant, int sideToMove, UInt64 zobristHash) { CurrentBoardPosition = currentBoardPosition; PieceToBitboard = pieceToBitboard; CastlingAndEnPassant = castlingAndEnPassant; SideToMove = sideToMove; ZobristHash = zobristHash; }
public Move(sbyte side, byte startPosition, byte endPosition, Piece promotedPiece) { Side = side; StartPosition = startPosition; EndPosition = endPosition; PromotedPiece = promotedPiece; HashKey = (UInt16)((StartPosition << 8) ^ EndPosition); }
/// <summary> /// Sets the move data by parsing in a long algebraic notation as described in /// this document: http://wbec-ridderkerk.nl/html/UCIProtocol.html (see Move format). /// </summary> /// <param name="longAlgebraicNotationMove">The move string, e.g. a8a5.</param> public void Set(sbyte side, string longAlgebraicNotationMove) { Side = side; string start = longAlgebraicNotationMove.Substring(0, 2); StartPosition = Constants.AlgebraicToIntegerIndex[start]; string end = longAlgebraicNotationMove.Substring(2, 2); EndPosition = Constants.AlgebraicToIntegerIndex[end]; // if length is greater than 5, e.g. b7b8q, then it means a pawn promotion. if (longAlgebraicNotationMove.Length == 5) { IsPawnPromotion = true; string promotedPiece = longAlgebraicNotationMove.Substring(4, 1); switch (promotedPiece) { case "q": PromotedPiece = (Side == Engine.Side.Black) ? Piece.BlackQueen : Piece.WhiteQueen; break; case "r": PromotedPiece = (Side == Engine.Side.Black) ? Piece.BlackRook : Piece.WhiteRook; break; case "b": PromotedPiece = (Side == Engine.Side.Black) ? Piece.BlackBishop : Piece.WhiteBishop; break; case "n": PromotedPiece = (Side == Engine.Side.Black) ? Piece.BlackKnight : Piece.WhiteKnight; break; case "p": PromotedPiece = (Side == Engine.Side.Black) ? Piece.BlackPawn : Piece.WhitePawn; break; default: throw new ArgumentException("Invalid promoted piece."); } } else { IsPawnPromotion = false; PromotedPiece = Piece.None; } HashKey = (UInt16)((StartPosition << 8) ^ EndPosition); }
private void GenerateMoves(Piece piece, UInt16[] moves, UInt16[] quietMoves, ref int movesCount, ref int quietMovesCount) { UInt64 pieceBitboard = PieceToBitboard[piece.Index]; byte[] startPositions = BitHelper.GetSetBitIndexes2(pieceBitboard); UInt64 ownBoard = GetBoardForSide(sideToMove); for (int i = 0; i < startPositions.Length; i++) { UInt64 validMoves = GetValidMovesForPiece(piece, startPositions[i], ownBoard); ExtractPseudoLegalMoves(validMoves, startPositions[i], moves, quietMoves, ref movesCount, ref quietMovesCount); } }
private void ReplacePawnWithPromotedPiece(Piece promotedPiece, Piece pawnToReplace, byte promotionSquare) { UInt64 pawnQueenMask = (UInt64)1 << promotionSquare; PieceToBitboard[pawnToReplace.Index] = PieceToBitboard[pawnToReplace.Index] ^ pawnQueenMask; PieceToBitboard[promotedPiece.Index] = PieceToBitboard[promotedPiece.Index] | pawnQueenMask; squareToPiece[promotionSquare] = promotedPiece; // update zobrist hash: XOR out the pawn and XOR in the promoted piece ZobristHash ^= _zobristKeys[pawnToReplace.ZobristStartingIndex + promotionSquare]; ZobristHash ^= _zobristKeys[promotedPiece.ZobristStartingIndex + promotionSquare]; }
// updates: 1. piece to BB for that piece, 2. zobrist, 3. square to piece array. private void JustMoveThePiece(Piece movingPiece, byte fromSquare, byte toSquare) { /* Update KDFs */ // KDF 1: piece to BB array UInt64 startEndBitboard = (((UInt64)1) << fromSquare) ^ (((UInt64)1) << toSquare); PieceToBitboard[movingPiece.Index] ^= startEndBitboard; // KDF 2: zobrist hash // update zobrist hash (http://stackoverflow.com/questions/10067514/correctly-implementing-zobrist-hashing) // remove starting position of moving piece from hash (i.e. XOR out) ZobristHash ^= _zobristKeys[movingPiece.ZobristStartingIndex + fromSquare]; // include ending position of moving piece into hash (i.e. XOR in) ZobristHash ^= _zobristKeys[movingPiece.ZobristStartingIndex + toSquare]; // KDF 3: square to piece array // square to piece array: squareToPiece[fromSquare] = Piece.None; squareToPiece[toSquare] = movingPiece; }
private bool IsSameSide(Piece piece, int side) { return ((piece.Number * side) > 0); }
private UInt64 GetValidMovesForPiece(Piece piece, int square, UInt64 ownBoard) { // gets all the spots that this piece can move to assuming that this is the only piece on the board. switch (piece.Number) { case Constants.BlackKingNumber: case Constants.WhiteKingNumber: return GetValidMovesForKing(square, ownBoard); case Constants.BlackKnightNumber: case Constants.WhiteKnightNumber: return GetValidMovesForKnight(square, ownBoard); case Constants.WhitePawnNumber: return GetValidMovesForWhitePawn(square); case Constants.BlackPawnNumber: return GetValidMovesForBlackPawn(square); case Constants.BlackRookNumber: case Constants.WhiteRookNumber: return GetValidMovesForRook(square, ownBoard); case Constants.BlackBishopNumber: case Constants.WhiteBishopNumber: return GetValidMovesForBishop(square, ownBoard); case Constants.BlackQueenNumber: case Constants.WhiteQueenNumber: return GetValidMovesForQueen(square, ownBoard); default: throw new ArgumentException("Invalid piece."); } }