-
Notifications
You must be signed in to change notification settings - Fork 0
/
Engine.py
145 lines (120 loc) · 4.46 KB
/
Engine.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
from multiprocessing import freeze_support
import chess
PIECE_VALUES = {
chess.PAWN: 1.0,
chess.BISHOP: 3.0,
chess.KNIGHT: 3.0,
chess.ROOK: 5.0,
chess.QUEEN: 9.0,
chess.KING: 0.0
}
class Engine:
def __init__(self, board: chess.Board, pool, manager):
self.board = board
self.pool = pool
self.manager = manager
def analyze_concurrent(self):
if self.board.turn == chess.WHITE:
maximize = True
else:
maximize = False
best_move = None
best_score = float('-inf') if maximize else float('inf')
pos_map = {} #self.manager.dict()
depth = 5
moves = list(self.board.legal_moves)
tasks = [(move, depth, maximize, self.board.copy(), pos_map) for move in moves]
for args in tasks:
move, score = call_analyze(args)
if maximize and score >= best_score:
best_score = score
best_move = move
elif not maximize and score <= best_score:
best_score = score
best_move = move
return best_move, best_score
def evaluate(board: chess.Board):
if outcome := board.outcome():
if outcome.winner == chess.BLACK:
return -1000.0
if outcome.winner == chess.WHITE:
return 1000.0
if outcome.result == '1/2-1/2':
return 0.0
score = 0.0
for (square, piece) in board.piece_map().items():
if piece.color == chess.WHITE:
score += PIECE_VALUES[piece.piece_type]
else:
score -= PIECE_VALUES[piece.piece_type]
#if piece.piece_type == chess.PAWN:
# file_index = chess.square_file(square)
# rank_index = chess.square_rank(square)
# # Isolated Pawn Check
# if not any(board.piece_at(neighbor) for neighbor in chess.SquareSet(chess.BB_FILES[file_index]) & chess.SquareSet(chess.BB_RANKS[rank_index])):
# isolated_pawns += 1 if piece.color == chess.WHITE else -1
#
# # Doubled Pawn Check
# if len(chess.SquareSet(board.pieces(piece.piece_type, piece.color) & chess.BB_FILES[rank_index])) > 1:
# doubled_pawns += 1 if piece.color == chess.WHITE else -1
#
# # Blocked Pawn Check
# if board.piece_at(square + 8) is not None: # Check if there's a piece in front of the pawn
# blocked_pawns += 1 if piece.color == chess.WHITE else -1
#white_mobility = len(list(board.legal_moves))
#board.turn = chess.BLACK
#black_mobility = len(list(board.legal_moves))
#board.turn = chess.WHITE
##score -= 0.5 * (doubled_pawns + blocked_pawns + isolated_pawns)
#score += 0.1 * (white_mobility - black_mobility)
return score
def call_analyze(args):
move, depth, maximize, board, pos_map = args
board.push(move)
return move, alpha_beta(depth, float('-inf'), float('inf'), maximize, board, pos_map)
def alpha_beta(depth, alpha, beta, maximize, board: chess.Board, pos_map):
# If we already have an evaluation for the position return that instead
if bhash := hash_board(board) in pos_map.keys():
return pos_map[bhash]
if depth == 0 or board.is_game_over():
score = evaluate(board)
pos_map[bhash] = score
return evaluate(board)
if maximize:
score = float('-inf')
for move in list(board.legal_moves):
board.push(move)
score = max(score, alpha_beta(depth - 1, alpha, beta, False, board, pos_map))
if score > beta:
board.pop()
break
alpha = max(alpha, score)
board.pop()
pos_map[bhash] = score
return score
else:
score = float('inf')
for move in list(board.legal_moves):
board.push(move)
score = min(score, alpha_beta(depth - 1, alpha, beta, True, board, pos_map))
if score < alpha:
board.pop()
break
beta = min(beta, score)
board.pop()
pos_map[bhash] = score
return score
# Converts fen into hashmap key
def hash_board(board: chess.Board):
hash = board.pawns
hash ^= board.rooks
hash ^= board.knights
hash ^= board.bishops
hash ^= board.queens
hash ^= board.kings
hash ^= board.castling_rights
hash ^= board.ep_square if board.ep_square else 0
hash ^= board.turn
return hash
if __name__ == '__main__':
freeze_support()