-
Notifications
You must be signed in to change notification settings - Fork 0
/
MoveChooser.py
183 lines (165 loc) · 6.61 KB
/
MoveChooser.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
"""
Different methods for the AI to choose the next move.
"""
import random
import operator
COLOURS = ["WHITE","BLACK"]
def other_colour(my_colour):
"""
Get the other colour.
"""
my_colour_index = COLOURS.index(my_colour)
other_colour_index = (my_colour_index + 1) % 2
other_colour = COLOURS[other_colour_index]
return other_colour
class RandomMovePlayer(object):
"""
Choose a move randomly
"""
def __init__(self, colour):
self.colour = colour
print("{} will choose moves randomly.".format(colour))
def choose_move(self, game):
all_possible_moves = []
for p in game.board.pieces:
if p.colour == self.colour:
for m in p.available_moves:
if game.is_legal_move(self.colour, p.current_position, m):
all_possible_moves.append((p.current_position,m))
move_index = random.randint(0,len(all_possible_moves)-1)
start, end = all_possible_moves[move_index]
return start, end
class BestNextPointsPlayer(object):
"""
Evaluate points for takes and losses for next move
"""
def __init__(self, colour):
self.colour = colour
print("{} will choose moves according to simple points total for the next move.".format(colour))
def choose_move(self, game):
all_possible_moves = []
for p in game.board.pieces:
start_pos = p.current_position
if p.colour == self.colour:
for m in p.available_moves:
if game.is_legal_move(self.colour, start_pos, m):
all_possible_moves.append((start_pos,m))
best_points = -999
best_moves = []
print(game.board)
for move in all_possible_moves:
points = self.potential_points_for_move(game, self.colour, move)
if points > best_points:
best_points = points
best_moves = [move]
elif points == best_points:
best_moves.append(move)
## we now have a list best_moves which contains the one
## or more top-scoring possible moves. Pick one at random.
start,end = best_moves[random.randint(0,len(best_moves)-1)]
print(game.board)
return start, end
def potential_points_for_move(self, game, colour, move):
"""
return a points value based on:
(value of any piece taken at end_pos)
- (value of this piece if threatened at end_pos)
+ (value of this piece if threatened at start_pos)
"""
points = 0
start_pos, end_pos = move
this_piece_value = game.board.piece_at(start_pos).value
if not game.board.is_empty(end_pos):
points += game.board.piece_at(end_pos).value
for p in game.board.pieces:
if p.colour == colour:
continue
if start_pos in p.threatens:
points += this_piece_value
if end_pos in p.threatens:
points -= this_piece_value
return points
class MinimaxPlayer(object):
"""
Use minimax algorithm to choose moves.
"""
def __init__(self, colour, depth=2):
self.colour = colour
self.depth = depth
print("{} will use minimax algorithm to choose moves.".format(colour))
def get_points_for_position(self, game):
""""
points for pieces, and heuristics for position
"""
points = 0.
next_to_play = game.next_to_play
centre_squares = {
"WHITE": [("D",5),("E",5)],
"BLACK": [("D",4),("E",4)]
}
if game.is_checkmate(next_to_play):
points = 1000. if self.colour == next_to_play else -1000.
return points
for p in game.board.pieces:
sign = 1 if p.colour == self.colour else -1
points += sign * p.value
points += sign * 0.005 * len(p.available_moves)
if p.piece_type == "King" and p.has_castled:
points += sign * 0.2
for cs in centre_squares[self.colour]:
if cs in p.threatens:
points += sign * 0.1
return points
def minimax(self, game, depth, maximizingPlayer, move_str):
game.board.save_snapshot(move_str)
if depth == 0:
return self.get_points_for_position(game), move_str
next_depth = depth - 1
best_move_str = None
if maximizingPlayer:
game.next_to_play = self.colour
best_value = -999.
for move in game.get_all_possible_moves(self.colour):
game.board.load_snapshot(move_str)
game.move(move[0],move[1])
new_move_str = "{}{}{}{}{}".format(move_str,
move[0][0],
move[0][1],
move[1][0],
move[1][1])
value = self.minimax(game, next_depth, False, new_move_str)[0]
if value > best_value:
best_value = value
best_move_str = new_move_str
return best_value, best_move_str
else:
game.next_to_play = other_colour(self.colour)
best_value = 999.
for move in game.get_all_possible_moves(other_colour(self.colour)):
game.board.load_snapshot(move_str)
game.move(move[0], move[1])
new_move_str = "{}{}{}{}{}".format(move_str,
move[0][0],
move[0][1],
move[1][0],
move[1][1])
value = self.minimax(game, next_depth, True, new_move_str)[0]
if value < best_value:
best_value = value
best_move_str = new_move_str
return best_value, best_move_str
def choose_move(self, game):
"""
Return start and end position based on minimax
"""
game_history = game.get_history_str()
game.save_snapshot()
move_str = self.minimax(game, self.depth, True, game_history)[1]
game.load_snapshot(game_history)
start = (move_str[-4],int(move_str[-3]))
end = (move_str[-2], int(move_str[-1]))
return start, end
methods = {"Random": RandomMovePlayer,
"BestNextPoints" : BestNextPointsPlayer,
"Minimax": MinimaxPlayer
}