From 9774588e8659c0128f7fe3fac058ebdc131d71f2 Mon Sep 17 00:00:00 2001 From: Hrushikesh Vaidya Date: Mon, 30 Jan 2023 08:10:50 +0530 Subject: [PATCH] Made search 4x faster --- chessengine/__init__.py | 2 +- chessengine/bitboard.py | 20 ++++++--- chessengine/moves.py | 98 ++++++++++++++++++++++++++--------------- docs/conf.py | 2 +- pyproject.toml | 2 +- 5 files changed, 80 insertions(+), 44 deletions(-) diff --git a/chessengine/__init__.py b/chessengine/__init__.py index 31d6331..86be979 100644 --- a/chessengine/__init__.py +++ b/chessengine/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.3.1" +__version__ = "0.3.2" from chessengine.bitboard import Board from chessengine import moves diff --git a/chessengine/bitboard.py b/chessengine/bitboard.py index 7948c7f..67f4724 100644 --- a/chessengine/bitboard.py +++ b/chessengine/bitboard.py @@ -277,13 +277,13 @@ def copy(self): Create and return a copy of the board. """ return copy(self) - + def evaluate_score(self) -> int: """ Evaluate the current score/evaluation of the board state. Use this method to reset the board score to the correct value if the game starts from an intermediate stage. - + :return: The score/evaluation of the current board state. """ s = 0 @@ -296,7 +296,7 @@ def evaluate_score(self) -> int: "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 @@ -490,7 +490,15 @@ def move(self, start: int, end: int, score: int = None, track: bool = True) -> N # Track moves made so we can undo if track: - start_state = (start, end, end_side, end_piece, end_board, castle_type, self.score) + start_state = ( + start, + end, + end_side, + end_piece, + end_board, + castle_type, + self.score, + ) self.moves.append(start_state) # Check en passant moves @@ -567,7 +575,7 @@ def move(self, start: int, end: int, score: int = None, track: bool = True) -> N self.move(2**56, 2**59, False) # Don't track this move self.black_king_side_castle = False self.black_queen_side_castle = False - + # Update the board evaluation if track: if score is None: @@ -718,7 +726,7 @@ def undo_move(self) -> None: raise RuntimeError("No moves have been made yet to undo.") end, start, side, piece, board, castle_type, prev_score = self.moves.pop() self.score = prev_score - + if castle_type is not None: # TODO - if user castles when both self.white_kingside and self.white_queenside are # True, undoing this move only lets the user castle to the same side they castled diff --git a/chessengine/moves.py b/chessengine/moves.py index 2fda00f..f9d925e 100644 --- a/chessengine/moves.py +++ b/chessengine/moves.py @@ -68,7 +68,9 @@ def get_rook_moves(board, side: str, position: int) -> list[tuple[int, int, int] while True: # Move rank up _ = _ << 8 - valid, should_break = check_valid_position(board, side, 'rooks', position, _, moves) + valid, should_break = check_valid_position( + board, side, "rooks", position, _, moves + ) if should_break: break @@ -76,7 +78,9 @@ def get_rook_moves(board, side: str, position: int) -> list[tuple[int, int, int] while True: # Move rank down _ = _ >> 8 - valid, should_break = check_valid_position(board, side, 'rooks', position, _, moves) + valid, should_break = check_valid_position( + board, side, "rooks", position, _, moves + ) if should_break: break @@ -86,7 +90,9 @@ def get_rook_moves(board, side: str, position: int) -> list[tuple[int, int, int] for i in range(max_right): # Move right _ = _ << 1 - valid, should_break = check_valid_position(board, side, 'rooks', position, _, moves) + valid, should_break = check_valid_position( + board, side, "rooks", position, _, moves + ) if should_break: break @@ -95,7 +101,9 @@ def get_rook_moves(board, side: str, position: int) -> list[tuple[int, int, int] for i in range(max_left): # Move left _ = _ >> 1 - valid, should_break = check_valid_position(board, side, 'rooks', position, _, moves) + valid, should_break = check_valid_position( + board, side, "rooks", position, _, moves + ) if should_break: break @@ -136,14 +144,18 @@ def get_bishop_moves(board, side: str, position: int) -> list[tuple[int, int, in _ = position for i in range(max_right): _ = _ << 9 - valid, should_break = check_valid_position(board, side, 'bishops', position, _, moves) + valid, should_break = check_valid_position( + board, side, "bishops", position, _, moves + ) if should_break: break _ = position for i in range(max_right): _ = _ >> 7 - valid, should_break = check_valid_position(board, side, 'bishops', position, _, moves) + valid, should_break = check_valid_position( + board, side, "bishops", position, _, moves + ) if should_break: break @@ -151,14 +163,18 @@ def get_bishop_moves(board, side: str, position: int) -> list[tuple[int, int, in _ = position for i in range(max_left): _ = _ << 7 - valid, should_break = check_valid_position(board, side, 'bishops', position, _, moves) + valid, should_break = check_valid_position( + board, side, "bishops", position, _, moves + ) if should_break: break _ = position for i in range(max_left): _ = _ >> 9 - valid, should_break = check_valid_position(board, side, 'bishops', position, _, moves) + valid, should_break = check_valid_position( + board, side, "bishops", position, _, moves + ) if should_break: break @@ -200,34 +216,34 @@ def get_knight_moves(board, side: str, position: int) -> list[tuple[int, int, in if rank >= 3: if file >= 2: _ = position >> 17 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if file <= 7: _ = position >> 15 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if rank >= 2: if file >= 3: _ = position >> 10 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if file <= 6: _ = position >> 6 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if rank <= 6: if file >= 2: _ = position << 15 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if file <= 7: _ = position << 17 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if rank <= 7: if file >= 3: _ = position << 6 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) if file <= 6: _ = position << 10 - check_valid_position(board, side, 'knights', position, _, moves) + check_valid_position(board, side, "knights", position, _, moves) return moves @@ -267,35 +283,35 @@ def get_king_moves(board, side: str, position: int) -> list[tuple[int, int, int] if rank >= 2: _ = position >> 8 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file >= 2: _ = position >> 9 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file <= 7: _ = position >> 7 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if rank <= 7: _ = position << 8 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file >= 2: _ = position << 7 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file <= 7: _ = position << 9 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file >= 2: _ = position >> 1 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if file <= 7: _ = position << 1 - check_valid_position(board, side, 'kings', position, _, moves) + check_valid_position(board, side, "kings", position, _, moves) if side == "white": if board.white_queen_side_castle: @@ -373,35 +389,41 @@ def get_white_pawn_moves(board, position: int) -> list[tuple[int, int, int]]: _ = position << 8 if board.all_pieces & _ == 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('white', 'pawns', position, _, end_piece, board.score) + score = score_from_move("white", "pawns", position, _, end_piece, board.score) moves.append((position, _, score)) if rank == 2: _ = position << 16 if board.all_pieces & _ == 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('white', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "white", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) file = get_file(position) if file >= 2: _ = position << 7 if board.all_black & _ > 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('white', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "white", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) if file <= 7: _ = position << 9 if board.all_black & _ > 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('white', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "white", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) en_passant_position = board.en_passant_position if en_passant_position == position << 7 and file >= 2: _ = position << 7 - check_valid_position(board, "white", 'pawns', position, _, moves) + check_valid_position(board, "white", "pawns", position, _, moves) if en_passant_position == position << 9 and file <= 7: _ = position << 9 - check_valid_position(board, "white", 'pawns', position, _, moves) + check_valid_position(board, "white", "pawns", position, _, moves) return moves @@ -421,32 +443,38 @@ def get_black_pawn_moves(board, position: int) -> list[tuple[int, int, int]]: _ = position >> 8 if board.all_pieces & _ == 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('black', 'pawns', position, _, end_piece, board.score) + score = score_from_move("black", "pawns", position, _, end_piece, board.score) moves.append((position, _, score)) if rank == 7: _ = position >> 16 if board.all_pieces & _ == 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('black', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "black", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) file = get_file(position) if file >= 2: _ = position >> 9 if board.all_white & _ > 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('black', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "black", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) if file <= 7: _ = position >> 7 if board.all_white & _ > 0: end_side, end_piece, end_board = board.identify_piece_at(_) - score = score_from_move('black', 'pawns', position, _, end_piece, board.score) + score = score_from_move( + "black", "pawns", position, _, end_piece, board.score + ) moves.append((position, _, score)) en_passant_position = board.en_passant_position if en_passant_position == position >> 9 and file >= 2: _ = position >> 9 - check_valid_position(board, "black", 'pawns', position, _, moves) + check_valid_position(board, "black", "pawns", position, _, moves) if en_passant_position == position >> 7 and file <= 7: _ = position >> 7 check_valid_position(board, "black", "pawns", position, _, moves) diff --git a/docs/conf.py b/docs/conf.py index df2ce55..21af007 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ project = "chessengine" copyright = "2022, Hrushikesh Vaidya" author = "Hrushikesh Vaidya" -release = "0.3.1" +release = "0.3.2" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml index 33a42e6..94cbf8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ openings = ["*.pgn"] [project] name = "chessengine" -version = "0.3.1" +version = "0.3.2" authors = [ {name="Hrushikesh Vaidya", email="hrushikeshrv@gmail.com"}, ]