-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmovegeneration.py
114 lines (98 loc) · 3.14 KB
/
movegeneration.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
from typing import Dict, List, Any
import chess
import sys
import time
from evaluate import evaluate_board, move_value, check_end_game
debug_info: Dict[str, Any] = {}
MATE_SCORE = 1000000000
MATE_THRESHOLD = 999000000
def next_move(depth: int, board: chess.Board, debug=True) -> chess.Move:
debug_info.clear()
debug_info["nodes"] = 0
t0 = time.time()
move = minimax_root(depth, board)
debug_info["time"] = time.time() - t0
if debug == True:
print(f"info {debug_info}")
return move
def get_ordered_moves(board: chess.Board) -> List[chess.Move]:
end_game = check_end_game(board)
def orderer(move):
return move_value(board, move, end_game)
in_order = sorted(
board.legal_moves, key=orderer, reverse=(board.turn == chess.WHITE)
)
return list(in_order)
def minimax_root(depth: int, board: chess.Board) -> chess.Move:
maximize = board.turn == chess.WHITE
best_move = -float("inf")
if not maximize:
best_move = float("inf")
moves = get_ordered_moves(board)
best_move_found = moves[0]
for move in moves:
board.push(move)
if board.can_claim_draw():
value = 0.0
else:
value = minimax(depth - 1, board, -float("inf"), float("inf"), not maximize)
board.pop()
if maximize and value >= best_move:
best_move = value
best_move_found = move
elif not maximize and value <= best_move:
best_move = value
best_move_found = move
return best_move_found
def minimax(
depth: int,
board: chess.Board,
alpha: float,
beta: float,
is_maximising_player: bool,
) -> float:
debug_info["nodes"] += 1
if board.is_checkmate():
return -MATE_SCORE if is_maximising_player else MATE_SCORE
elif board.is_game_over():
return 0
if depth == 0:
return evaluate_board(board)
if is_maximising_player:
best_move = -float("inf")
moves = get_ordered_moves(board)
for move in moves:
board.push(move)
curr_move = minimax(depth - 1, board, alpha, beta, not is_maximising_player)
if curr_move > MATE_THRESHOLD:
curr_move -= 1
elif curr_move < -MATE_THRESHOLD:
curr_move += 1
best_move = max(
best_move,
curr_move,
)
board.pop()
alpha = max(alpha, best_move)
if beta <= alpha:
return best_move
return best_move
else:
best_move = float("inf")
moves = get_ordered_moves(board)
for move in moves:
board.push(move)
curr_move = minimax(depth - 1, board, alpha, beta, not is_maximising_player)
if curr_move > MATE_THRESHOLD:
curr_move -= 1
elif curr_move < -MATE_THRESHOLD:
curr_move += 1
best_move = min(
best_move,
curr_move,
)
board.pop()
beta = min(beta, best_move)
if beta <= alpha:
return best_move
return best_move