forked from bcorfman/raven-checkers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
evaluators.py
160 lines (128 loc) · 6.05 KB
/
evaluators.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
__author__ = 'brandon_corfman'
from csp import CSP, different_values_constraint, backtracking_search, forward_checking, mrv
from globalconst import BLACK, MAN
from goalevaluator import GoalEvaluator
from formation import BLACK_MAP, WHITE_MAP
from goalformation import GoalShortDyke, GoalLongDyke, GoalPhalanx, GoalPyramid, GoalMill, GoalEchelon
from crossboard import GoalCrossboard
def formation_csp(variables, board):
"""Return an instance of the CSP to see if the formation can be obtained."""
domains = {}
player = board.to_move
pos_map = BLACK_MAP if player == BLACK else WHITE_MAP
neighbors = {}
for var in variables:
domains[var] = [item for item in pos_map[var] if board.squares[item] == player + MAN]
neighbors[var] = list(set(variables) - {var})
return CSP(variables, domains, neighbors, different_values_constraint)
class ShortDykeEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "ShortDykeEvaluator::calculate_desirability"
short_dyke_csp = formation_csp(self.thinker.board.short_dyke, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(short_dyke_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 1.0
else:
return 0.0
def set_goal(self):
print "ShortDykeEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalShortDyke(self.thinker))
class LongDykeEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "LongDykeEvaluator::calculate_desirability"
long_dyke_csp = formation_csp(self.thinker.board.short_dyke, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(long_dyke_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 0.9
else:
return 0.0
def set_goal(self):
print "LongDykeEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalLongDyke(self.thinker))
class PyramidEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "PyramidEvaluator::calculate_desirability"
pyramid_csp = formation_csp(self.thinker.board.pyramid, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(pyramid_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 0.9
else:
return 0.0
def set_goal(self):
print "PyramidEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalPyramid(self.thinker))
class PhalanxEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "PhalanxEvaluator::calculate_desirability"
phalanx_csp = formation_csp(self.thinker.board.phalanx, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(phalanx_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 0.9
else:
return 0.0
def set_goal(self):
print "PhalanxEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalPhalanx(self.thinker))
# TODO: Consider partial mill formations. Pask says: "TIP: Don't dismiss the opportunity to develop just one of these
# TODO: segments, as it still may be effective.", Starting Out in Checkers, page 104.
class MillEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "MillEvaluator::calculate_desirability"
mill_csp = formation_csp(self.thinker.board.mill, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(mill_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 0.9
else:
return 0.0
def set_goal(self):
print "MillEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalMill(self.thinker))
class EchelonEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
print "EchelonEvaluator::calculate_desirability"
echelon_csp = formation_csp(self.thinker.board.echelon, self.thinker.board)
# all formations are desirable if they can be achieved, and undesirable if they can't.
if backtracking_search(echelon_csp, select_unassigned_variable=mrv, inference=forward_checking):
return 0.9
else:
return 0.0
def set_goal(self):
print "EchelonEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalEchelon(self.thinker))
class CrossboardEvaluator(GoalEvaluator):
def __init__(self, thinker):
GoalEvaluator.__init__(self)
self.thinker = thinker
def calculate_desirability(self):
""" Make crossboard play slightly less desirable than other strategies.
That way, it will only get used if nothing else is applicable. """
print "CrossboardEvaluator::calculate_desirability"
return 0.9
def set_goal(self):
print "CrossboardEvaluator::set_goal"
self.thinker.remove_all_subgoals()
self.thinker.add_subgoal(GoalCrossboard(self.thinker))