// get the type of piece at a given board address private static PieceMoveType PieceTypeAtAddress(PiecePositions.Player player, BoardAddress address) { if ((address.Position & player.Pawns) != 0) { return(PieceMoveType.Pawn); } else if ((address.Position & player.Knights) != 0) { return(PieceMoveType.Knight); } else if ((address.Position & player.Bishops) != 0) { return(PieceMoveType.Bishop); } else if ((address.Position & player.Rooks) != 0) { return(PieceMoveType.Rook); } else if ((address.Position & player.Queens) != 0) { return(PieceMoveType.Queen); } else if ((address.Position & player.King) != 0) { return(PieceMoveType.King); } else { Debug.WriteLine("no piece found at specified position"); return(PieceMoveType.Undefined); } }
// the material value for a given player private int MaterialValue(PiecePositions.Player player) { int Result = 0; foreach (ulong pawn in Utilities.BitSplit(player.Pawns)) { Result += PawnValue; } foreach (ulong knight in Utilities.BitSplit(player.Knights)) { Result += KnightValue; } foreach (ulong bishop in Utilities.BitSplit(player.Knights)) { Result += BishopValue; } foreach (ulong rook in Utilities.BitSplit(player.Knights)) { Result += RookValue; } foreach (ulong queen in Utilities.BitSplit(player.Knights)) { Result += QueenValue; } return(Result); }
// apply a move to a given board internal static Board ApplyMove(Board board, Move move) { var Result = new Board(); Result.ActiveColorWhite = board.ActiveColorWhite; /// update piece positions /// Result.Pieces = new PiecePositions(board.Pieces); Result.Pieces.All &= ~(move.From.Position | move.To.Position); PiecePositions.Player ActiveP = Result.ActivePlayer; switch (move.MoveType) { case PieceMoveType.Pawn: ActiveP.Pawns |= move.To.Position; break; case PieceMoveType.Knight: case PieceMoveType.PawnKnight: ActiveP.Knights |= move.To.Position; break; case PieceMoveType.Bishop: case PieceMoveType.PawnBishop: ActiveP.Bishops |= move.To.Position; break; case PieceMoveType.Rook: case PieceMoveType.PawnRook: ActiveP.Rooks |= move.To.Position; break; case PieceMoveType.Queen: case PieceMoveType.PawnQueen: ActiveP.Queens |= move.To.Position; break; case PieceMoveType.King: ActiveP.King |= move.To.Position; break; case PieceMoveType.KingQueenside: ActiveP.King |= move.To.Position; if (board.ActiveColorWhite) { ActiveP.Rooks &= ~Masks.WhiteQueenSideRookInitPos; ActiveP.Rooks |= Masks.WhiteQueenSideRookPostCastlePos; } else { ActiveP.Rooks &= ~Masks.BlackQueenSideRookInitPos; ActiveP.Rooks |= Masks.BlackQueenSideRookPostCastlePos; } break; case PieceMoveType.KingKingside: ActiveP.King |= move.To.Position; if (board.ActiveColorWhite) { ActiveP.Rooks &= ~Masks.WhiteKingSideRookInitPos; ActiveP.Rooks |= Masks.WhiteQueenSideRookPostCastlePos; } else { ActiveP.Rooks &= ~Masks.BlackKingSideRookInitPos; ActiveP.Rooks |= Masks.BlackKingSideRookPostCastlePos; } break; default: throw new ArgumentException("invalid move type"); } /// update the draw counter /// bool PawnMoved = move.MoveType < PieceMoveType.Knight; bool CaptureOccured = (move.To.Position & (board.InactivePlayer.All | board.EnPassantTarget)) != 0; if (PawnMoved || CaptureOccured) { Result.HalfMoveClock = 0; // reset } else { Result.HalfMoveClock = (byte)(board.HalfMoveClock + 1); // increment } /// check for en passant target /// if (PawnMoved && (move.From.Position & Masks.Ranks27) != 0) { if (board.ActiveColorWhite && ((move.From.Position << 16) & move.To.Position) != 0) { Result.EnPassantTarget = move.From.Position << 8; } else if (!board.ActiveColorWhite && ((move.From.Position >> 16) & move.To.Position) != 0) { Result.EnPassantTarget = move.From.Position >> 8; } } /// update castling availability /// // copy the availablity of the inactive player and store the past availablity for the active player Result.CastlingAvailability = new Board.Castling(); Board.Castling.Move PastActiveCastlingStatus, NewActiveCastlingStatus; if (board.ActiveColorWhite) { Result.CastlingAvailability.Black = board.CastlingAvailability.Black; PastActiveCastlingStatus = board.CastlingAvailability.White; } else { Result.CastlingAvailability.White = board.CastlingAvailability.White; PastActiveCastlingStatus = board.CastlingAvailability.Black; } // was castling already disallowed or did the king just move? if (PastActiveCastlingStatus == Board.Castling.Move.Disallowed || (move.MoveType >= PieceMoveType.King)) // yes { NewActiveCastlingStatus = Board.Castling.Move.Disallowed; } else // no { switch (PastActiveCastlingStatus) { case Board.Castling.Move.KingSide: if (KingSideRookMoved(board)) { NewActiveCastlingStatus = Board.Castling.Move.Disallowed; } else { NewActiveCastlingStatus = Board.Castling.Move.KingSide; } break; case Board.Castling.Move.QueenSide: if (QueenSideRookMoved(board)) { NewActiveCastlingStatus = Board.Castling.Move.Disallowed; } else { NewActiveCastlingStatus = Board.Castling.Move.QueenSide; } break; case Board.Castling.Move.BothSides: if (QueenSideRookMoved(board)) { NewActiveCastlingStatus = Board.Castling.Move.KingSide; } else if (KingSideRookMoved(board)) { NewActiveCastlingStatus = Board.Castling.Move.KingSide; } else { NewActiveCastlingStatus = Board.Castling.Move.BothSides; } break; default: throw new Exception(string.Format("invalid castling status \"{0}\"", PastActiveCastlingStatus)); } if (board.ActiveColorWhite) { Result.CastlingAvailability.White = NewActiveCastlingStatus; } else { Result.CastlingAvailability.Black = NewActiveCastlingStatus; } } /// update full move counter /// if (!board.ActiveColorWhite) { Result.FullMoveNumber++; // on black player's move } /// switch the active player /// Result.ActiveColorWhite = !board.ActiveColorWhite; /// update past move tracker /// Result.PastMoves = new Queue <Move>(board.PastMoves); // copy references to the past moves if (Result.PastMoves.Count == 8) { Result.PastMoves.Dequeue(); // limit at 8 moves } Result.PastMoves.Enqueue(move); // add the current move return(Result); }
// create a move from a diff of two boards private static Move BoardDiff(Board before, Board after) { // cache player handles PiecePositions.Player ActivePlayerBefore = before.ActivePlayer; PiecePositions.Player InactivePlayerAfter = after.InactivePlayer; var Result = new Move(); /// get the starting positions of the moving pieces /// ulong MultiPositions = ActivePlayerBefore.All & ~InactivePlayerAfter.All; if (MultiPositions == 0) { Debug.WriteLine("none of the active player's pieces moved"); return(null); } bool TwoPieceFlag = false; ulong RookStartPosition = 0; ulong RookEndPosition = 0; ulong[] Positions = new List <ulong>(Utilities.BitSplit(MultiPositions)).ToArray(); PieceMoveType FromPiece, ToPiece; if (Positions.Length > 2) // more than two moved pieces { Debug.WriteLine("more than two pieces moved"); return(null); } else if (Positions.Length == 2) // double piece move (castle) { TwoPieceFlag = true; FromPiece = PieceTypeAtAddress(ActivePlayerBefore, new BoardAddress(Positions[0])); if (FromPiece != PieceMoveType.King) { if (FromPiece != PieceMoveType.Rook) { Debug.WriteLine("two pieces moved, but a rook was not one of them"); return(null); } FromPiece = PieceTypeAtAddress(ActivePlayerBefore, new BoardAddress(Positions[1])); if (FromPiece != PieceMoveType.King) { Debug.WriteLine("two pieces moved, but the king was not one of them"); return(null); } Result.From = new BoardAddress(Positions[1]); RookStartPosition = Positions[0]; } else { if (PieceTypeAtAddress(ActivePlayerBefore, new BoardAddress(Positions[1])) != PieceMoveType.Rook) { Debug.WriteLine("two pieces moved, but a rook was not one of them"); return(null); } Result.From = new BoardAddress(Positions[0]); RookStartPosition = Positions[1]; } } else // single piece moved { Result.From = new BoardAddress(Positions[0]); FromPiece = PieceTypeAtAddress(ActivePlayerBefore, new BoardAddress(Positions[0])); } /// get the ending position of the moving piece /// MultiPositions = InactivePlayerAfter.All & ~ActivePlayerBefore.All; Positions = new List <ulong>(Utilities.BitSplit(MultiPositions)).ToArray(); if (MultiPositions == 0) { Debug.WriteLine("the active player lost a piece on thier turn"); return(null); } if (Positions.Length > 2) // more than two pieces moved { Debug.WriteLine("a piece was added to the board"); return(null); } else if (Positions.Length == 2) // double piece move (castle) { if (!TwoPieceFlag) { Debug.WriteLine("a piece was added to the board"); return(null); } ToPiece = PieceTypeAtAddress(InactivePlayerAfter, new BoardAddress(Positions[0])); if (ToPiece != PieceMoveType.King) { if (ToPiece != PieceMoveType.Rook) { Debug.WriteLine("two pieces moved, but a rook was not one of them"); return(null); } ToPiece = PieceTypeAtAddress(InactivePlayerAfter, new BoardAddress(Positions[1])); if (ToPiece != PieceMoveType.King) { Debug.WriteLine("two pieces moved, but the king was not one of them"); return(null); } Result.To = new BoardAddress(Positions[1]); RookEndPosition = Positions[0]; } else { if (PieceTypeAtAddress(InactivePlayerAfter, new BoardAddress(Positions[1])) != PieceMoveType.Rook) { Debug.WriteLine("two pieces moved, but a rook was not one of them"); return(null); } Result.To = new BoardAddress(Positions[0]); RookEndPosition = Positions[1]; } } else // single piece moved { if (TwoPieceFlag) { Debug.WriteLine("the active player lost a piece on thier turn"); return(null); } Result.To = new BoardAddress(Positions[0]); ToPiece = PieceTypeAtAddress(InactivePlayerAfter, new BoardAddress(Positions[0])); } Result.MoveType = MoveTypeFromPieceTypes(FromPiece, ToPiece); if (TwoPieceFlag) // update king move to a castling move { if (Result.MoveType != PieceMoveType.King) // sanity check { Debug.WriteLine("the move indicates a castle, but the king didn't move"); return(null); } if (before.ActiveColorWhite) // white player's move { if ((RookStartPosition ^ Masks.WhiteKingSideRookInitPos) == 0) // king side castle { if ((RookEndPosition ^ Masks.WhiteKingSideRookPostCastlePos) != 0) // does the rook's end position agree? { Debug.WriteLine("the move indicates a kingside castle, but the rook didn't move to its proper position"); return(null); } Result.MoveType = PieceMoveType.KingKingside; } else if ((RookStartPosition ^ Masks.WhiteQueenSideRookInitPos) == 0) // queenside castle { if ((RookEndPosition ^ Masks.WhiteQueenSideRookPostCastlePos) != 0) // does the rook's end position agree? { Debug.WriteLine("the move indicates a queenside castle, but the rook didn't move to its proper position"); return(null); } Result.MoveType = PieceMoveType.KingQueenside; } else // invalid { Debug.WriteLine("the move indicates a castle, but the rook was not in its proper position"); return(null); } } else // black player's move { if ((RookStartPosition ^ Masks.BlackKingSideRookInitPos) == 0) // king side castle { if ((RookEndPosition ^ Masks.BlackKingSideRookPostCastlePos) != 0) // does the rook's end position agree? { Debug.WriteLine("the move indicates a kingside castle, but the rook didn't move to its proper position"); return(null); } Result.MoveType = PieceMoveType.KingKingside; } else if ((RookStartPosition ^ Masks.BlackQueenSideRookInitPos) == 0) // queenside castle { if ((RookEndPosition ^ Masks.BlackQueenSideRookPostCastlePos) != 0) // does the rook's end position agree? { Debug.WriteLine("the move indicates a queenside castle, but the rook didn't move to its proper position"); return(null); } Result.MoveType = PieceMoveType.KingQueenside; } else // invalid { Debug.WriteLine("the move indicates a castle, but the rook was not in its proper position"); return(null); } } } return(Result); }