-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalgorithm.py
251 lines (187 loc) · 7.63 KB
/
algorithm.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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
import math
from tqdm import tqdm
import pieces
import multiprocessing as m
import pieces
class GameAI:
def __init__(self, board, view, color, enemy):
self.board = board
self.view = view
self.color = color
self.enemy = enemy
def alpha_beta(self, state, depth, alpha, beta, ai_playing):
# calcs the score of the current board
if depth == 0 or not self.board.check_for_king():
return self.calculate_board_value(state)
if ai_playing:
ai_value = -math.inf
self.board.currently_playing = "White"
# calcs the score of every possible move
for next_move in self.get_possible_moves(self.enemy, state):
x_move, y_move = next_move
temp = self.board.get_copy_board_state(state)
change_position = None
try:
change_position = temp[x_move].position
temp[x_move].position = y_move
temp[y_move] = temp[x_move]
temp[x_move] = None
except AttributeError:
pass
# calcs the score of the current board
value = self.alpha_beta(temp, depth - 1, alpha, beta, False)
if change_position is not None:
temp[y_move].position = change_position
self.board.currently_playing = "Black"
# White want the score as high as possible
ai_value = max(ai_value, value)
alpha = max(alpha, value)
if beta <= alpha:
break
return ai_value
player_value = math.inf
self.board.currently_playing = "Black"
for next_move in self.get_possible_moves(self.color, state):
x_move, y_move = next_move
temp = self.board.get_copy_board_state(state)
change_position = None
try:
change_position = temp[x_move].position
temp[x_move].position = y_move
temp[y_move] = temp[x_move]
temp[x_move] = None
except AttributeError:
pass
value = self.alpha_beta(temp, depth - 1, alpha, beta, True)
if change_position is not None:
temp[y_move].position = change_position
# Black wants the score as low as possible
player_value = min(player_value, value)
beta = min(beta, value)
if beta <= alpha:
# Splits the list possible_moves in as many chunks as the PC has cores
break
return player_value
@staticmethod
def get_score_pieces(current_game_state):
black = 0
white = 0
for i in current_game_state:
if isinstance(i, pieces.Rook):
if i.colour == "White":
white += 500
else:
black += 500
if isinstance(i, pieces.Pawn):
if i.colour == "White":
white += 100
else:
black += 100
if isinstance(i, pieces.Knight):
if i.colour == "White":
white += 320
else:
black += 320
if isinstance(i, pieces.Bishop):
if i.colour == "White":
white += 330
else:
black += 330
if isinstance(i, pieces.King):
if i.colour == "White":
white += 20000
else:
black += 20000
if isinstance(i, pieces.Queen):
if i.colour == "White":
white += 900
else:
black += 900
return white - black
def score_position(self, pieces_type, table, piece_val, current_game_state):
white = 0
black = 0
count = 0
for i in current_game_state:
if type(i) is pieces_type:
if i.colour == "White":
white += piece_val
else:
y = math.floor(count/8)
x = count - (y * 7) - y
black += table[7-x][y]
count += 1
return white-black
def calculate_board_value(self, current_game_state):
piece = self.get_score_pieces(current_game_state)
pawn = self.score_position(pieces.Pawn, pieces.Pawn.table, 100, current_game_state)
Knight = self.score_position(pieces.Knight, pieces.Knight.table, 320, current_game_state)
bishop = self.score_position(pieces.Bishop, pieces.Bishop.table, 330, current_game_state)
rook = self.score_position(pieces.Rook, pieces.Rook.table, 500, current_game_state)
queen = self.score_position(pieces.Queen, pieces.Queen.table, 900, current_game_state)
return piece + pawn + rook + Knight + bishop + queen
@staticmethod
def get_possible_moves(color, state):
move = []
for i in state:
try:
if i.colour == color:
possible_move = i.check_legal_move(i.position, state, True)
if len(possible_move) > 0:
for moves in possible_move:
if 0 < moves < 64:
move.append([i.position, moves])
except AttributeError:
continue
return move
def calc_best_move(self, moves, queue, state):
best_score = math.inf
final_move = None
for next_move in moves:
temp = self.board.get_copy_board_state(state)
x_move, y_move = next_move
change_position = None
try:
# if a pieces got the attribute position, it has to be saved and changed
change_position = temp[x_move].position
temp[x_move].position = y_move
temp[y_move] = temp[x_move]
temp[x_move] = None
except AttributeError:
pass
# calcs the score of the current move
current_score = self.alpha_beta(temp, 3, -math.inf, math.inf, True)
if change_position is not None:
temp[y_move].position = change_position
if current_score < best_score:
best_score = current_score
final_move = next_move
queue.put([final_move, best_score])
def move(self):
state = self.board.get_copy_board_state()
possible_moves = self.get_possible_moves(self.color, state)
result = []
k, a = divmod(len(possible_moves), m.cpu_count())
process_moves = list(possible_moves[i * k + min(i, a):
(i + 1) * k + min(i + 1, a)] for i in range(m.cpu_count()))
output = tqdm(total=m.cpu_count())
processes = []
queue = m.Queue()
for i in process_moves:
processes.append(m.Process(target=self.calc_best_move, args=(i, queue, state,)))
processes[len(processes) - 1].start()
for i in processes:
i.join()
output.update()
for _ in range(queue.qsize()):
result.append(queue.get())
result = sorted(result, key=lambda x: x[1])
same_score = []
lower_score = result[0][1]
for i in result:
if i[1] == lower_score:
same_score.append(i)
same_score.sort()
x_move, y_move = same_score[0][0]
output.close()
return x_move, y_move