-
Notifications
You must be signed in to change notification settings - Fork 2
/
strategies.py
104 lines (77 loc) · 2.98 KB
/
strategies.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
"""
Some example strategies for people who want to create a custom, homemade bot.
And some handy classes to extend
"""
import chess
from chess.engine import PlayResult
import random
from engine_wrapper import EngineWrapper
class FillerEngine:
"""
Not meant to be an actual engine.
This is only used to provide the property "self.engine"
in "MinimalEngine" which extends "EngineWrapper"
"""
def __init__(self, main_engine, name=None):
self.id = {
"name": name
}
self.name = name
self.main_engine = main_engine
def __getattr__(self, method_name):
main_engine = self.main_engine
def method(*args, **kwargs):
nonlocal main_engine
nonlocal method_name
return main_engine.notify(method_name, *args, **kwargs)
return method
class MinimalEngine(EngineWrapper):
"""
Subclass this to prevent a few random errors
Even though MinimalEngine extends EngineWrapper,
you don't have to actually wrap an engine.
At minimum, just implement `search`,
however you can also change other methods like
`notify`, `first_search`, `get_time_control`, etc.
"""
def __init__(self, commands, options, stderr, draw_or_resign, name=None):
super().__init__(commands, options, stderr, draw_or_resign)
self.engine_name = self.__class__.__name__ if name is None else name
self.engine = FillerEngine(self, name=self.name)
self.engine.id = {
"name": self.engine_name
}
def search(self, board, time_limit, ponder, draw_offered):
"""
The method to be implemented in your homemade engine
NOTE: This method must return an instance of "chess.engine.PlayResult"
"""
raise NotImplementedError("The search method is not implemented")
def notify(self, method_name, *args, **kwargs):
"""
The EngineWrapper class sometimes calls methods on "self.engine".
"self.engine" is a filler property that notifies <self>
whenever an attribute is called.
Nothing happens unless the main engine does something.
Simply put, the following code is equivalent
self.engine.<method_name>(<*args>, <**kwargs>)
self.notify(<method_name>, <*args>, <**kwargs>)
"""
pass
class ExampleEngine(MinimalEngine):
pass
# Strategy names and ideas from tom7's excellent eloWorld video
class RandomMove(ExampleEngine):
def search(self, board, *args):
return PlayResult(random.choice(list(board.legal_moves)), None)
class Alphabetical(ExampleEngine):
def search(self, board, *args):
moves = list(board.legal_moves)
moves.sort(key=board.san)
return PlayResult(moves[0], None)
class FirstMove(ExampleEngine):
"""Gets the first move when sorted by uci representation"""
def search(self, board, *args):
moves = list(board.legal_moves)
moves.sort(key=str)
return PlayResult(moves[0], None)