diff --git a/chessengine/bitboard.py b/chessengine/bitboard.py index 014b303..0b35632 100644 --- a/chessengine/bitboard.py +++ b/chessengine/bitboard.py @@ -42,6 +42,7 @@ coords_to_pos, pos_to_coords, san_piece_map, + piece_square_table, ) from chessengine.utils import ( get_bit_positions, @@ -230,19 +231,24 @@ def score(self): The "score" of the board. A higher/more positive score favors white, a lower/more negative score favors black. """ - K = self.piece_count[("white", "kings")] - Q = self.piece_count[("white", "queens")] - R = self.piece_count[("white", "rooks")] - B = self.piece_count[("white", "bishops")] - N = self.piece_count[("white", "knights")] - P = self.piece_count[("white", "pawns")] - k = self.piece_count[("black", "kings")] - q = self.piece_count[("black", "queens")] - r = self.piece_count[("black", "rooks")] - b = self.piece_count[("black", "bishops")] - n = self.piece_count[("black", "knights")] - p = self.piece_count[("black", "pawns")] - s = 200 * (K - k) + 9 * (Q - q) + 5 * (R - r) + 3 * (B - b + N - n) + (P - p) + s = 0 + piece_values = { + "pawns": 100, + "rooks": 500, + "knights": 320, + "bishops": 330, + "queens": 900, + "kings": 20000, + } + for i in range(64): + pos = 2**i + side, piece, _ = self.identify_piece_at(pos) + if side is None: + continue + elif side == "white": + s += piece_values[piece] + piece_square_table[(side, piece)][i] + else: + s -= piece_values[piece] + piece_square_table[(side, piece)][i] if self.side == "white": return s return -s @@ -398,11 +404,12 @@ def identify_piece_at(self, position: int) -> tuple: the piece identified at position (e.g, "black"), piece is the type of piece identified at position (e.g, "bishops"), and bitboard is the bitboard of the piece (e.g, Board.black_bishops). """ + if not position & self.all_pieces: + return None, None, None for side, piece in self.board: board = self.board[(side, piece)] if board & position > 0: return side, piece, board - return None, None, None def move(self, start: int, end: int, track: bool = True) -> None: """ @@ -487,11 +494,11 @@ def move(self, start: int, end: int, track: bool = True) -> None: if start_piece == "pawns": if start_side == "white": # Check en passant status - if get_rank(end) - get_rank(start) == 2: + if get_rank(start) == 2 and get_rank(end) == 4: self.en_passant_position = start << 8 # Check if a pawn captured by an en passant move - elif get_file(start) != get_file(end): + elif end == self.en_passant_position: # White pawn made an en passant move black_pawn_bb = self.get_bitboard("black", "pawns") black_pawn_bb &= clear_position[end >> 8] @@ -505,11 +512,11 @@ def move(self, start: int, end: int, track: bool = True) -> None: else: # Check en passant status - if get_rank(start) - get_rank(end) == 2: + if get_rank(start) == 7 and get_rank(end) == 5: self.en_passant_position = start >> 8 # Check if a pawn captured by an en passant move - elif get_file(start) != get_file(end): + elif end == self.en_passant_position: # Black pawn made an en passant move white_pawn_bb = self.get_bitboard("white", "pawns") white_pawn_bb &= clear_position[end << 8] @@ -768,7 +775,6 @@ def get_moves( ("black", "knights"): get_black_knight_moves, ("black", "pawns"): get_black_pawn_moves, } - # TODO - Add support for en passant move detection return move_gens[(side, piece)](self, position) else: moves = [] diff --git a/chessengine/lookup_tables.py b/chessengine/lookup_tables.py index 79f99c7..8a74191 100644 --- a/chessengine/lookup_tables.py +++ b/chessengine/lookup_tables.py @@ -326,3 +326,141 @@ "N": "knights", "R": "rooks", } + +# fmt: off + +piece_square_table = { + ('white', 'kings'): [ + 20, 30, 10, 0, 0, 10, 30, 20, + 20, 20, 0, 0, 0, 0, 20, 20, + -10, -20, -20, -20, -20, -20, -20, -10, + 20, -30, -30, -40, -40, -30, -30, -20, + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30 + ], + + ('white', 'queens'): [ + -20, -10, -10, -5, -5, -10, -10, -20, + -10, 0, 0, 0, 0, 0, 0, -10, + -10, 0, 5, 5, 5, 5, 0, -10, + -5, 0, 5, 5, 5, 5, 0, -5, + 0, 0, 5, 5, 5, 5, 0, -5, + -10, 5, 5, 5, 5, 5, 0, -10, + -10, 0, 5, 0, 0, 0, 0, -10, + -20, -10, -10, -5, -5, -10, -10, -20 + ], + + ('white', 'rooks'): [ + 0, 0, 0, 5, 5, 0, 0, 0, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + 5, 10, 10, 10, 10, 10, 10, 5, + 0, 0, 0, 0, 0, 0, 0, 0 + ], + + ('white', 'bishops'): [ + -20, -10, -10, -10, -10, -10, -10, -20, + -10, 5, 0, 0, 0, 0, 5, -10, + -10, 10, 10, 10, 10, 10, 10, -10, + -10, 0, 10, 10, 10, 10, 0, -10, + -10, 5, 5, 10, 10, 5, 5, -10, + -10, 0, 5, 10, 10, 5, 0, -10, + -10, 0, 0, 0, 0, 0, 0, -10, + -20, -10, -10, -10, -10, -10, -10, -20 + ], + + ('white', 'knights'): [ + -50, -40, -30, -30, -30, -30, -40, -50, + -40, -20, 0, 0, 0, 0, -20, -40, + -30, 0, 10, 15, 15, 10, 0, -30, + -30, 5, 15, 20, 20, 15, 5, -30, + -30, 0, 15, 20, 20, 15, 0, -30, + -30, 5, 10, 15, 15, 10, 5, -30, + -40, -20, 0, 5, 5, 0, -20, -40, + -50, -40, -30, -30, -30, -30, -40, -50 + ], + + ('white', 'pawns'): [ + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 10, 10, -20, -20, 10, 10, 5, + 5, -5, -10, 0, 0, -10, -5, 5, + 0, 0, 0, 20, 20, 0, 0, 0, + 5, 5, 10, 25, 25, 10, 5, 5, + 10, 10, 20, 30, 30, 20, 10, 10, + 50, 50, 50, 50, 50, 50, 50, 50, + 0, 0, 0, 0, 0, 0, 0, 0 + ], + + ('black', 'kings'): [ + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30, + -30, -40, -40, -50, -50, -40, -40, -30, + 20, -30, -30, -40, -40, -30, -30, -20, + -10, -20, -20, -20, -20, -20, -20, -10, + 20, 20, 0, 0, 0, 0, 20, 20, + 20, 30, 10, 0, 0, 10, 30, 20, + ], + + ('black', 'queens'): [ + -20, -10, -10, -5, -5, -10, -10, -20, + -10, 0, 0, 0, 0, 0, 0, -10, + -10, 0, 5, 5, 5, 5, 0, -10, + -5, 0, 5, 5, 5, 5, 0, -5, + 0, 0, 5, 5, 5, 5, 0, -5, + -10, 5, 5, 5, 5, 5, 0, -10, + -10, 0, 5, 0, 0, 0, 0, -10, + -20, -10, -10, -5, -5, -10, -10, -20 + ], + + ('black', 'rooks'): [ + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 10, 10, 10, 10, 10, 10, 5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + 0, 0, 0, 5, 5, 0, 0, 0, + ], + + ('black', 'bishops'): [ + -20, -10, -10, -10, -10, -10, -10, -20, + -10, 0, 0, 0, 0, 0, 0, -10, + -10, 0, 5, 10, 10, 5, 0, -10, + -10, 5, 5, 10, 10, 5, 5, -10, + -10, 0, 10, 10, 10, 10, 0, -10, + -10, 10, 10, 10, 10, 10, 10, -10, + -10, 5, 0, 0, 0, 0, 5, -10, + -20, -10, -10, -10, -10, -10, -10, -20, + ], + + ('black', 'knights'): [ + -50, -40, -30, -30, -30, -30, -40, -50, + -40, -20, 0, 0, 0, 0, -20, -40, + -30, 0, 10, 15, 15, 10, 0, -30, + -30, 5, 15, 20, 20, 15, 5, -30, + -30, 0, 15, 20, 20, 15, 0, -30, + -30, 5, 10, 15, 15, 10, 5, -30, + -40, -20, 0, 5, 5, 0, -20, -40, + -50, -40, -30, -30, -30, -30, -40, -50 + ], + + ('black', 'pawns'): [ + 0, 0, 0, 0, 0, 0, 0, 0, + 50, 50, 50, 50, 50, 50, 50, 50, + 10, 10, 20, 30, 30, 20, 10, 10, + 5, 5, 10, 25, 25, 10, 5, 5, + 0, 0, 0, 20, 20, 0, 0, 0, + 5, -5, -10, 0, 0, -10, -5, 5, + 5, 10, 10, -20, -20, 10, 10, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + ], +} + +# fmt: on diff --git a/chessengine/utils.py b/chessengine/utils.py index 8aea5ae..a96c3d4 100644 --- a/chessengine/utils.py +++ b/chessengine/utils.py @@ -26,7 +26,7 @@ def get_bit_positions(bitboard: int) -> List[int]: """ Returns a list of positions in the bitboard which have a 1. - For e.g. - 1001100 returns [100, 1000, 1000000] + For e.g. - 1001100 returns [100, 1000, 1000000] (all numbers in binary) :param bitboard: A bitboard. """