Skip to content

Commit

Permalink
Merge pull request #58 from hrushikeshrv/better_score
Browse files Browse the repository at this point in the history
Implemented better evaluation function, fixed en passant detection bug, added early stopping to `Board.identify_piece_at`.
  • Loading branch information
hrushikeshrv committed Jan 16, 2023
2 parents 49132f0 + 9cadf7d commit 1452274
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 20 deletions.
44 changes: 25 additions & 19 deletions chessengine/bitboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
coords_to_pos,
pos_to_coords,
san_piece_map,
piece_square_table,
)
from chessengine.utils import (
get_bit_positions,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
"""
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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 = []
Expand Down
138 changes: 138 additions & 0 deletions chessengine/lookup_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion chessengine/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand Down

0 comments on commit 1452274

Please sign in to comment.