forked from bengsky13/Chess-Bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stockfishpy.py
135 lines (117 loc) · 5.09 KB
/
stockfishpy.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
import subprocess
import sys
import re
class Engine(subprocess.Popen):
def __init__(self, stockfish_path='./stockfish', depth=16, param={}):
try:
subprocess.Popen.__init__(self, stockfish_path, universal_newlines=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
except Exception:
sys.exit('Install correct Stockfish PATH ')
default_param = {
"Write Debug Log": "false",
"Contempt": 0,
"Threads": 1,
"Hash": 16,
"Min Split Depth": 0,
"Ponder": "false",
"MultiPV": 1,
"Skill Level": 20,
"Move Overhead": 30,
"Minimum Thinking Time": 20,
"Slow Mover": 80,
"Nodestime": 0,
"UCI_Chess960": "false",
"SyzygyPath": "",
"SyzygyProbeDepth": 1,
"Syzygy50MoveRule": 'true',
"SyzygyProbeLimit": 6
}
default_param.update(param)
self.param = default_param
for name, value in list(default_param.items()):
self.setoption(name, value)
self.uci()
self.depth = str(depth)
def send(self, command):
self.stdin.write(command + '\n')
self.stdin.flush()
def flush(self):
self.stdout.flush()
def uci(self):
self.send('uci')
while True:
line = self.stdout.readline().strip()
if line == 'uciok':
return line
def setoption(self, optionname, value):
""" Update default_param dict """
self.send('setoption name %s value %s' % (optionname, str(value)))
stdout = self.isready()
if stdout.find('No such') >= 0:
print("stockfish was unable to set option %s" % optionname)
def setposition(self, position):
try:
if isinstance(position, list):
self.send('position startpos moves {}'.format(
self.__listtostring(position)))
self.isready()
elif re.match('\s*^(((?:[rnbqkpRNBQKP1-8]+\/){7})[rnbqkpRNBQKP1-8]+)\s([b|w])\s([K|Q|k|q|-]{1,4})\s(-|[a-h][1-8])\s(\d+\s\d+)$', position):
regexList = re.match('\s*^(((?:[rnbqkpRNBQKP1-8]+\/){7})[rnbqkpRNBQKP1-8]+)\s([b|w])\s([K|Q|k|q|-]{1,4})\s(-|[a-h][1-8])\s(\d+\s\d+)$', position).groups()
fen = regexList[0].split("/")
if len(fen) != 8:
raise ValueError("expected 8 rows in position part of fen: {0}".format(repr(fen)))
for fenPart in fen:
field_sum = 0
previous_was_digit, previous_was_piece = False, False
for c in fenPart:
if c in ["1", "2", "3", "4", "5", "6", "7", "8"]:
if previous_was_digit:
raise ValueError("two subsequent digits in position part of fen: {0}".format(repr(fen)))
field_sum += int(c)
previous_was_digit = True
previous_was_piece = False
elif c == "~":
if not previous_was_piece:
raise ValueError("~ not after piece in position part of fen: {0}".format(repr(fen)))
previous_was_digit, previous_was_piece = False, False
elif c.lower() in ["p", "n", "b", "r", "q", "k"]:
field_sum += 1
previous_was_digit = False
previous_was_piece = True
else:
raise ValueError("invalid character in position part of fen: {0}".format(repr(fen)))
if field_sum != 8:
raise ValueError("expected 8 columns per row in position part of fen: {0}".format(repr(fen)))
self.send('position fen {}'.format(position))
self.isready()
else: raise ValueError("fen doesn`t match follow this example: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 ")
except ValueError as e:
print('\nCheck position correctness\n')
sys.exit(e.message)
@staticmethod
def __listtostring(move):
return ' '.join(move).strip()
def go(self):
self.send('go depth {}'.format(self.depth))
def isready(self):
self.send('isready')
while True:
line = self.stdout.readline().strip()
if line == 'readyok':
return line
def ucinewgame(self):
self.send('ucinewgame')
self.isready()
def bestmove(self):
info = ""
self.go()
while True:
line = self.stdout.readline().strip().split(' ')
if line[0] == 'bestmove':
if self.param['Ponder'] == 'true':
ponder = line[3]
else:
ponder = None
return {'bestmove': line[1], 'ponder': ponder, 'info': ' '.join(info)}