/
computer_player.py
110 lines (94 loc) · 3.99 KB
/
computer_player.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
import random
import chess
import curses
import locale; locale.setlocale(locale.LC_ALL, '')
import functools
import itertools as it
import sys
import gmpy2
import time
import copy
logfile = open('_', 'w', 1)
def eval_board(board, gameover=False):
white_mask = board.occupied_co[chess.WHITE]
black_mask = board.occupied_co[chess.BLACK]
material = ((gmpy2.popcount((board.pawns & white_mask)) - gmpy2.popcount((board.pawns & black_mask)))*1 +
(gmpy2.popcount((board.knights & white_mask)) - gmpy2.popcount((board.knights & black_mask)))*3 +
(gmpy2.popcount((board.bishops & white_mask)) - gmpy2.popcount((board.bishops & black_mask)))*3 +
(gmpy2.popcount((board.rooks & white_mask)) - gmpy2.popcount((board.rooks & black_mask)))*5 +
(gmpy2.popcount((board.queens & white_mask)) - gmpy2.popcount((board.queens & black_mask)))*9 +
(gmpy2.popcount((board.kings & white_mask)) - gmpy2.popcount((board.kings & black_mask)))*1000)
if gameover or abs(material) >= 9 or (gmpy2.popcount(white_mask) + gmpy2.popcount(black_mask)) < 9:
if board.is_checkmate():
if board.turn:
return -10000
else:
return 10000
return material
class OuttaTime(Exception): pass
def negamaxalphabeta(board, depth, alpha, beta, color, starttime=None, maxtime=30):
assert alpha < beta
if starttime is not None:
if time.time() > starttime + maxtime:
raise OuttaTime('Ran out of time')
if depth == 0:
return color * eval_board(board)
best = float('-inf')
for move in board.pseudo_legal_moves:
board.push(move)
score = -negamaxalphabeta(board, depth-1, -beta, -alpha, -color, starttime, maxtime)
best = max(best, score)
alpha = max(alpha, score)
board.pop()
if alpha >= beta:
break
return best
def branch_first(board, depth, color, starttime):
maxscore = float('-inf')
bestmoves = []
for move in sorted(board.legal_moves, key = lambda x: iscapture(board, x), reverse=True):
board.push(move)
val = -negamaxalphabeta(board, depth-1, float('-inf'), float('inf'), -color, starttime)
logfile.write('val {}, color {} move {}\n'.format(val, color, move))
board.pop()
if val > maxscore:
maxscore = val
bestmoves = [move]
elif val == maxscore:
bestmoves.append(move)
logfile.write('color {}, best moves {} max {} \n'.format(color, bestmoves, maxscore))
logfile.write('********\n')
return maxscore, bestmoves
def computer_player(maximizing_player, look_ahead=[2, 4, 5, 6, 8]):
if maximizing_player:
color = 1
else:
color = -1
def f(board):
bestmoves = list(board.legal_moves)
starttime = time.time()
for depth in look_ahead:
try:
_, bestmoves = branch_first(copy.deepcopy(board), depth, color, starttime)
logfile.write('Got to depth %s in %ss\n' % (depth, time.time()-starttime))
except OuttaTime:
logfile.write('Couldn\'t do depth %s\n' % depth)
break
logfile.write('#'*80 + '\n')
assert len(bestmoves) > 0
random.shuffle(bestmoves)
for criteria in [lambda x: board.is_castling(x),
lambda x: (x.from_square in range(16) and x.to_square not in range(16) or
x.from_square in range(48, 64) and not x.to_square in range(48,64)),
lambda x: not (board.piece_at(x.from_square).piece_type == chess.KING),
lambda x: True]:
filtered_bestmoves = filter(criteria, bestmoves)
try:
move = next(iter(filtered_bestmoves))
board.push(move)
return False
except StopIteration:
pass
return f
def iscapture(board, move):
return board.is_capture(move)