From 54e29b999a8c59f806077e07a8e878b3f663b5f5 Mon Sep 17 00:00:00 2001 From: Hrushikesh Vaidya Date: Sat, 14 Jan 2023 12:04:24 +0530 Subject: [PATCH 1/3] Added piece square table --- chessengine/bitboard.py | 3 +- chessengine/lookup_tables.py | 138 +++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/chessengine/bitboard.py b/chessengine/bitboard.py index 014b303..0a75bd0 100644 --- a/chessengine/bitboard.py +++ b/chessengine/bitboard.py @@ -398,11 +398,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: """ 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 From 80bde5fd8811d1787d46572f40cd6431dea9e22c Mon Sep 17 00:00:00 2001 From: Hrushikesh Vaidya Date: Sun, 15 Jan 2023 14:11:47 +0530 Subject: [PATCH 2/3] Implemented score function --- chessengine/bitboard.py | 34 ++++++++++++++++++++-------------- chessengine/utils.py | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/chessengine/bitboard.py b/chessengine/bitboard.py index 0a75bd0..66d5afb 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,20 +231,25 @@ 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) - if self.side == "white": + 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 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. """ From 9cadf7d9b73d896d7e2d05b2db3e900cc2d85427 Mon Sep 17 00:00:00 2001 From: Hrushikesh Vaidya Date: Mon, 16 Jan 2023 09:35:30 +0530 Subject: [PATCH 3/3] Fixed en passant detection bug --- chessengine/bitboard.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/chessengine/bitboard.py b/chessengine/bitboard.py index 66d5afb..0b35632 100644 --- a/chessengine/bitboard.py +++ b/chessengine/bitboard.py @@ -42,7 +42,7 @@ coords_to_pos, pos_to_coords, san_piece_map, - piece_square_table + piece_square_table, ) from chessengine.utils import ( get_bit_positions, @@ -233,23 +233,23 @@ def score(self): """ s = 0 piece_values = { - 'pawns': 100, - 'rooks': 500, - 'knights': 320, - 'bishops': 330, - 'queens': 900, - 'kings': 20000 + "pawns": 100, + "rooks": 500, + "knights": 320, + "bishops": 330, + "queens": 900, + "kings": 20000, } for i in range(64): - pos = 2 ** i + pos = 2**i side, piece, _ = self.identify_piece_at(pos) if side is None: continue - elif side == 'white': + 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': + if self.side == "white": return s return -s @@ -494,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] @@ -512,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] @@ -775,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 = []