private static ulong AKnightMoveMap(Board board, bool activePlayer, BoardAddress address) { if (activePlayer) { return(MoveMaps.Knight[address.Index] & ~board.ActivePlayer.All); } else { return(MoveMaps.Knight[address.Index] & ~board.InactivePlayer.All); } }
// 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); } }
private static ulong AQueenMoveMap(Board board, bool activePlayer, BoardAddress address) { return(ARookMoveMap(board, activePlayer, address) | ABishopMoveMap(board, activePlayer, address)); }
private static ulong ARookMoveMap(Board board, bool activePlayer, BoardAddress address) { // get the rook's move bitboard ulong Result = MoveMaps.Rook[address.Index]; // get the file and rank of the rook int RookFile = address.File; int RookRank = address.Rank; // get file and rank masks ulong FileMask = Masks.Files[RookFile]; ulong RankMask = Masks.Ranks[RookRank]; // get friends and foes in the same rank and file as the rook ulong FriendsInFile, FriendsInRank, FoesInFile, FoesInRank; if (activePlayer) { FriendsInFile = Result & board.ActivePlayer.All & FileMask; FriendsInRank = Result & board.ActivePlayer.All & RankMask; FoesInFile = Result & board.InactivePlayer.All & FileMask; FoesInRank = Result & board.InactivePlayer.All & RankMask; } else { FriendsInFile = Result & board.InactivePlayer.All & FileMask; FriendsInRank = Result & board.InactivePlayer.All & RankMask; FoesInFile = Result & board.ActivePlayer.All & FileMask; FoesInRank = Result & board.ActivePlayer.All & RankMask; } int TempFile, TempRank; // step through friends in the same file foreach (BoardAddress friend in BoardAddresses(FriendsInFile)) { TempRank = friend.Rank; if (TempRank > RookRank) // clear moves at and above this piece { Result &= ~Masks.North[TempRank]; } else // clear moves at and below this piece { Result &= ~Masks.South[TempRank]; } } // step through foes in the same file foreach (BoardAddress foe in BoardAddresses(FoesInFile)) { TempRank = foe.Rank; if (TempRank > RookRank) // clear moves above this piece { if (TempRank != 7) { Result &= ~Masks.North[TempRank + 1]; } } else // clear moves below this piece { if (TempRank != 0) { Result &= ~Masks.South[TempRank - 1]; } } } // step through friends in the same rank foreach (BoardAddress friend in BoardAddresses(FriendsInRank)) { TempFile = friend.File; if (TempFile > RookFile) // clear moves at and to the right of this piece { Result &= ~Masks.East[TempFile]; } else // clear moves at and to the left of this piece { Result &= ~Masks.West[TempFile]; } } // step through foes in the same rank foreach (BoardAddress foe in BoardAddresses(FoesInRank)) { TempFile = foe.File; if (TempFile > RookFile) // clear moves to the right of this piece { if (TempFile != 7) { Result &= ~Masks.East[TempFile + 1]; } } else // clear moves to the left of this piece { if (TempFile != 0) { Result &= ~Masks.West[TempFile - 1]; } } } return(Result); }
private static ulong ABishopMoveMap(Board board, bool activePlayer, BoardAddress address) { // get the bishop's move bitboard ulong Result = MoveMaps.Bishop[address.Index]; // get the file and rank of the bishop int BishopFile = address.File; int BishopRank = address.Rank; // get slash and backslash masks ulong SlashMask = Masks.Slash[address.SlashIndex]; ulong BackslashMask = Masks.BackSlash[address.BackSlashIndex]; // get friends and foes in same slash and backslash as bishop ulong FriendsInSlash, FriendsInBackslash, FoesInSlash, FoesInBackslash; if (activePlayer) { FriendsInSlash = Result & board.ActivePlayer.All & SlashMask; FriendsInBackslash = Result & board.ActivePlayer.All & BackslashMask; FoesInSlash = Result & board.InactivePlayer.All & SlashMask; FoesInBackslash = Result & board.InactivePlayer.All & BackslashMask; } else { FriendsInSlash = Result & board.InactivePlayer.All & SlashMask; FriendsInBackslash = Result & board.InactivePlayer.All & BackslashMask; FoesInSlash = Result & board.ActivePlayer.All & SlashMask; FoesInBackslash = Result & board.ActivePlayer.All & BackslashMask; } int TempFile, TempRank; // step through friends in the same slash foreach (BoardAddress friend in BoardAddresses(FriendsInSlash)) { TempFile = friend.File; if (TempFile > BishopFile) // clear moves at and to the northeast of this piece { Result &= ~Masks.NorthEast[friend.BackSlashIndex]; } else // clear moves at and to the southwest of this piece { Result &= ~Masks.SouthWest[friend.BackSlashIndex]; } } // step through foes in the same slash foreach (BoardAddress foe in BoardAddresses(FoesInSlash)) { TempFile = foe.File; if (TempFile > BishopFile) // clear moves to the northeast of this piece { if (foe.BackSlashIndex != 9) { Result &= ~Masks.NorthEast[(foe.BackSlashIndex - 1) & 0xF]; } } else // clear moves to the southwest of this piece { if (foe.BackSlashIndex != 7) { Result &= ~Masks.SouthWest[(foe.BackSlashIndex + 1) & 0xF]; } } } // step through friends in the same backslash foreach (BoardAddress friend in BoardAddresses(FriendsInBackslash)) { TempRank = friend.Rank; if (TempRank > BishopRank) // clear moves at and to the northwest of this piece { Result &= ~Masks.NorthWest[friend.SlashIndex]; } else // clear moves at and to the southeast of this piece { Result &= ~Masks.SouthEast[friend.SlashIndex]; } } // step through foes in the same backslash foreach (BoardAddress foeInBackslash in BoardAddresses(FoesInBackslash)) { TempRank = foeInBackslash.Rank; if (TempRank > BishopRank) // clear moves to the northwest of this piece { if (foeInBackslash.SlashIndex != 7) { Result &= ~Masks.NorthWest[(foeInBackslash.SlashIndex + 1) & 0xF]; } } else // clear moves to the southeast of this piece { if (foeInBackslash.SlashIndex != 9) { Result &= ~Masks.SouthEast[(foeInBackslash.SlashIndex - 1) & 0xF]; } } } return(Result); }
// get a map of all of a player's moves for a particular piece private static ulong APawnMoveMap(Board board, bool activePlayer, BoardAddress address) { // get moves and captures ulong Moves, Caps; if (board.ActiveColorWhite) { if (activePlayer) { Moves = MoveMaps.WhitePawn[address.Index]; Caps = MoveMaps.WhitePawnCapture[address.Index]; } else { Moves = MoveMaps.BlackPawn[address.Index]; Caps = MoveMaps.BlackPawnCapture[address.Index]; } } else // black { if (activePlayer) { Moves = MoveMaps.BlackPawn[address.Index]; Caps = MoveMaps.BlackPawnCapture[address.Index]; } else { Moves = MoveMaps.WhitePawn[address.Index]; Caps = MoveMaps.WhitePawnCapture[address.Index]; } } // is a double move allowed? if (Utilities.NumActiveBits(Moves) == 2) // yes // is at least one move unallowed? { if ((Moves & board.Pieces.All) != 0) //yes // get the single move { ulong SingleMove = Moves & ((address.Position << 8) | (address.Position >> 8)); // if single move allowed, then it is the only move if ((SingleMove & board.Pieces.All) == 0) { Moves = SingleMove; } else // otherwise no moves are allowed { Moves = 0; } } // else no, leave both moves } else // no // can't move into a another piece { Moves &= ~board.Pieces.All; } // can only move to en passant position or into an enemy position if (activePlayer) { Caps &= board.InactivePlayer.All | board.EnPassantTarget; // only active player can cap en passant } else { Caps &= board.ActivePlayer.All; } return(Moves | Caps); }
// create a board with a FEN string public Board(string fen) { Match Match = FenParser.Match(fen); if (!Match.Success) { throw new ArgumentException(string.Format("invalid FEN string \"{0}\"", fen)); } // piece placement string Field = Match.Groups[1].Value; string[] RankPlacement = Field.Split('/'); BoardAddress Location; int File; Pieces = new PiecePositions(); for (int rank = 0; rank < 8; rank++) { File = 0; foreach (char c in RankPlacement[7 - rank]) { Location = new BoardAddress((char)('a' + File), rank); switch (c) { case 'p': Pieces.Black.Pawns |= Location.Position; break; case 'P': Pieces.White.Pawns |= Location.Position; break; case 'n': Pieces.Black.Knights |= Location.Position; break; case 'N': Pieces.White.Knights |= Location.Position; break; case 'b': Pieces.Black.Bishops |= Location.Position; break; case 'B': Pieces.White.Bishops |= Location.Position; break; case 'r': Pieces.Black.Rooks |= Location.Position; break; case 'R': Pieces.White.Rooks |= Location.Position; break; case 'q': Pieces.Black.Queens |= Location.Position; break; case 'Q': Pieces.White.Queens |= Location.Position; break; case 'k': Pieces.Black.King |= Location.Position; break; case 'K': Pieces.White.King |= Location.Position; break; default: // num empty spaces if (!char.IsDigit(c)) { throw new ArgumentException(string.Format("invalid character \"{0}\" in piece placement field", c)); } File += c - '1'; // convert char to int break; } File++; } } // active color Field = Match.Groups[2].Value.ToLower(); if (Field == "w") { ActiveColorWhite = true; } else { ActiveColorWhite = false; } // castling availablity CastlingAvailability = new Castling(); Field = Match.Groups[3].Value; if (Field == "-") // not available { CastlingAvailability.White = Castling.Move.Disallowed; CastlingAvailability.Black = Castling.Move.Disallowed; } else // available to at least one player // check white { if (Field.Contains("K") && Field.Contains("Q")) { CastlingAvailability.White = Castling.Move.BothSides; } else if (Field.Contains("K")) { CastlingAvailability.White = Castling.Move.KingSide; } else if (Field.Contains("Q")) { CastlingAvailability.White = Castling.Move.QueenSide; } else { CastlingAvailability.White = Castling.Move.Disallowed; } // check black if (Field.Contains("k") && Field.Contains("q")) { CastlingAvailability.Black = Castling.Move.BothSides; } else if (Field.Contains("k")) { CastlingAvailability.Black = Castling.Move.KingSide; } else if (Field.Contains("q")) { CastlingAvailability.Black = Castling.Move.QueenSide; } else { CastlingAvailability.Black = Castling.Move.Disallowed; } } // enpassant location Field = Match.Groups[4].Value; if (Field == "-") { EnPassantTarget = 0; } else { EnPassantTarget = new BoardAddress(Field).Position; } // halfmove clock Field = Match.Groups[5].Value; if (!byte.TryParse(Field, out HalfMoveClock)) { throw new ArgumentException(string.Format("could not parse halfmove clock \"{0}\"", Field)); } // halfmove clock Field = Match.Groups[6].Value; if (!int.TryParse(Field, out FullMoveNumber)) { throw new ArgumentException(string.Format("could not parse full move number \"{0}\"", Field)); } }
// create a move from ACN string and the piece positions public Move(string acn, PiecePositions pieces) { int Len = acn.Length; if (Len < 4 || Len > 5) { throw new ArgumentException(string.Format("ACN strings must be 4 or 5 characters long: \"{0}\"", acn)); } string f = acn.Substring(0, 2); string t = acn.Substring(2, 2); From = new BoardAddress(f); To = new BoardAddress(t); // determine the type of piece that is moving if ((pieces.Pawns & From.Position) != 0) { MoveType = PieceMoveType.Pawn; } else if ((pieces.Knights & From.Position) != 0) { MoveType = PieceMoveType.Knight; } else if ((pieces.Bishops & From.Position) != 0) { MoveType = PieceMoveType.Bishop; } else if ((pieces.Rooks & From.Position) != 0) { MoveType = PieceMoveType.Rook; } else if ((pieces.Queens & From.Position) != 0) { MoveType = PieceMoveType.Queen; } else if ((pieces.Kings & From.Position) != 0) { MoveType = PieceMoveType.King; } else { throw new ArgumentException(string.Format("move \"{0}\" invalid given current piece positions", acn)); } // promotion on this move? if (Len == 5) // yes { if (MoveType != PieceMoveType.Pawn) { throw new ArgumentException("tried to promote from a piece type other than pawn"); } char promo = char.ToLower(acn[4]); switch (promo) { case 'n': MoveType = PieceMoveType.PawnKnight; break; case 'b': MoveType = PieceMoveType.PawnBishop; break; case 'r': MoveType = PieceMoveType.PawnRook; break; case 'q': MoveType = PieceMoveType.PawnQueen; break; default: throw new ArgumentException(string.Format("ACN string contains invalid promotion character \"{0}\"", promo)); } } }
public Move(ulong f, ulong t, PieceMoveType m) { From = new BoardAddress(f); To = new BoardAddress(t); MoveType = m; }
public Move(BoardAddress f, BoardAddress t, PieceMoveType m) { From = f; To = t; MoveType = m; }