-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbrain.py
357 lines (338 loc) · 11.5 KB
/
brain.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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
import numpy as np
from random import choice
def global_variables(mode: str = "default"):
'''
This functions gives information on the gain and
loss behaviour for the battlesnake. Eg. - The gain
it will be having by eating a food item or the loss
it will be having if it hits other snake etc.
'''
food_val = 3
corner_val = -1
food_surr_val = 2
other_snake_damage_val = 400
impossible = 2000
prioritize_food_row = False
prioritize_food_col = False
if(mode == "survival"):
prioritize_food_row = True
prioritize_food_col = True
corner_val = -2
food_val = 4
food_surr_val = 3
return (food_val, corner_val, food_surr_val, other_snake_damage_val, impossible, prioritize_food_row, prioritize_food_col)
def generate_smart_move(data: dict, mode: str = "default") -> str:
'''
Generates the smartest move by identifying the
move with maximum profit ( or minimum loss ) by
evaluating the board
'''
food_val, corner_val, food_surr_val, other_snake_damage_val, impossible, prioritize_food_row, prioritize_food_col = global_variables(
mode)
height = data["board"]["height"]
width = data["board"]["width"]
food = data["board"]["food"]
hazards = data["board"]["hazards"]
snakes = data["board"]["snakes"]
you = data["you"]
# Build board function builds a board matrix with all the given information
board = build_board(height, width, food, hazards, snakes, you, mode)
# log the board matrix
print(board.astype('int'))
# classify invalid move as an impossible move by making its value highly negative
# the value is stored in global variable as "impossible"
x = you["head"]["x"]
y = you["head"]["y"]
# get the 3x3 matrix around the head
surr = surrSq(x, y, board)
print(f"\nSurrounding 3x3 board :\n{surr}")
surr[0][0] = - impossible
surr[2][0] = -impossible
surr[1][1] = -impossible
surr[0][2] = -impossible
surr[2][2] = -impossible
# predict the moves with maximum profit/minimum loss
# ( move with most +ve value in the 3x3 matrix )
result = np.where(surr == np.amax(surr))
possibleMoves = []
listOfCordinates = list(zip(result[0], result[1]))
# initialize "future" variable caz we will be predicting future
# Note : No ML/AI used, predicting future basically means
# predicting the next best move and identify if it's
# in our battlesnake's favour or not
def surrMatrixMean(arr, value=-1700):
'''
Returns the mean of surrounding matrix excluding the outbounds
'''
return np.nanmean(np.where(arr == value, np.nan, arr))
future = []
superFuture = []
for cord in listOfCordinates:
if cord == (0, 1):
possibleMoves.append("up")
you["head"] = {"x": x, "y": y+1}
you["body"].append({"x": x, "y": y+1})
board = build_board(height, width, food,
hazards, snakes, you, mode)
if(y != height-1):
futureSurr = surrSq(x, y+1, board)
else:
futureSurr = surrSq(x, y, board)
future.append(np.amax(futureSurr))
superFuture.append(surrMatrixMean(futureSurr))
elif cord == (1, 2):
you["head"] = {"x": x+1, "y": y}
you["body"].append({"x": x+1, "y": y})
board = build_board(height, width, food,
hazards, snakes, you, mode)
possibleMoves.append("right")
if(x != width-1):
futureSurr = surrSq(x+1, y, board)
else:
futureSurr = surrSq(x, y, board)
future.append(np.amax(futureSurr))
superFuture.append(surrMatrixMean(futureSurr))
elif cord == (1, 0):
you["head"] = {"x": x-1, "y": y}
you["body"].append({"x": x-1, "y": y})
board = build_board(height, width, food,
hazards, snakes, you, mode)
possibleMoves.append("left")
if x != 0:
futureSurr = surrSq(x-1, y, board)
else:
futureSurr = surrSq(x-1, y, board)
future.append(np.amax(futureSurr))
superFuture.append(surrMatrixMean(futureSurr))
elif cord == (2, 1):
you["head"] = {"x": x, "y": y-1}
you["body"].append({"x": x, "y": y-1})
board = build_board(height, width, food,
hazards, snakes, you, mode)
possibleMoves.append("down")
if y != 0:
futureSurr = surrSq(x, y-1, board)
else:
futureSurr = surrSq(x, y, board)
future.append(np.amax(futureSurr))
superFuture.append(surrMatrixMean(futureSurr))
try:
# Predicting self future
future = np.array(future)
indices = np.array(np.where(future == np.amax(future)))
priority = []
for i in indices[0]:
i = int(i)
pM = possibleMoves[i]
priority.append(pM)
possibleMoves = priority
except:
# never encountered this but just in case...
print("Sad things happened while predicting future!")
finally:
# After predicting the future predict the super-future
# to reduce the degree of randomness! super-future is
# just a name I made up for predicting a better future
try:
indices = np.array(np.where(superFuture == np.amax(superFuture)))
superPriority = []
for i in indices:
i = int(i)
pM = possibleMoves[i]
superPriority.append(pM)
possibleMoves = superPriority
print(
f"Future Prediction : {priority}\nSuperFuture Prediction : {superPriority}")
except:
print("Sad things happened while predicting super future!!")
move = choice(possibleMoves)
print(f"Moving {move}!")
return move
def surrSq(x: int, y: int, board):
'''
Gets the surrounding 3x3 board around the given
coordinate (x, y)
'''
y = board.shape[1]-1-y
fakeError = "This is not an error, but I'm just taking advantage of errors!"
arr = np.full(shape=(3, 3), fill_value=-1700)
# make sure indices are non negative as they will
# result to the some value accoridngly but I want
# to declare those entry as invalid
try:
if(y-1 < 0 or x-1 < 0):
raise fakeError
f1 = board[y-1][x-1]
except:
f1 = -1700
try:
if(y < 0 or x-1 < 0):
raise fakeError
f2 = board[y][x-1]
except:
f2 = -1700
try:
if(y+1 < 0 or x-1 < 0):
raise fakeError
f3 = board[y+1][x-1]
except:
f3 = -1700
try:
if(y-1 < 0 or x < 0):
raise fakeError
g1 = board[y-1][x]
except:
g1 = -1700
try:
if(y < 0 or x < 0):
raise fakeError
g2 = board[y][x]
except:
g2 = -1700
try:
if(y+1 < 0 or x < 0):
raise fakeError
g3 = board[y+1][x]
except:
g3 = -1700
try:
if(y-1 < 0 or x+1 < 0):
raise fakeError
h1 = board[y-1][x+1]
except:
h1 = -1700
try:
if(y < 0 or x+1 < 0):
raise fakeError
h2 = board[y][x+1]
except:
h2 = -1700
try:
if(y+1 < 0 or x+1 < 0):
raise fakeError
h3 = board[y+1][x+1]
except:
h3 = -1700
# finally create the 3x3 matrix and return
arr = np.array([
[f1, f2, f3, ],
[g1, g2, g3, ],
[h1, h2, h3, ]]).T
return arr.astype('int')
def build_board(height, width, food, hazards, snakes, you, mode):
'''
Takes in the information about the game and
generates a matrix ( numpy array ) for the
board containg the gain and loss information
at every point
'''
food_val, corner_val, food_surr_val, other_snake_damage_val, impossible, prioritize_food_row, prioritize_food_col = global_variables(
mode)
board = np.ones((height, width))
# remove edges from priority by lowering it's gain value
board[0][:] = corner_val
board[:][height-1] = corner_val
for i in range(height):
board[i][0] = corner_val
board[i][width-1] = corner_val
for i in food:
board[height - 1 - i["y"], i["x"]] += food_val
try:
board[height-1-i["y"]+1, i["x"]] += food_surr_val
except:
None
try:
board[height-1-i["y"]-1, i["x"]] += food_surr_val
except:
None
try:
board[height-1-i["y"], i["x"]+1] += food_surr_val
except:
None
try:
board[height-1-i["y"]+1, i["x"]+1] += food_surr_val
except:
None
try:
board[height-1-i["y"]-1, i["x"]+1] += food_surr_val
except:
None
try:
board[height-1-i["y"]-1, i["x"]-1] += food_surr_val
except:
None
try:
board[height-1-i["y"], i["x"]-1] += food_surr_val
except:
None
try:
board[height-1-i["y"]+1, i["x"]-1] += food_surr_val
except:
None
try:
board[height-1-i["y"], i["x"]] += food_surr_val
except:
None
if prioritize_food_col:
try:
for x in range(width):
try:
board[i["y"]][x] += food_surr_val-1
except:
print(f"Failed to prioritize ({x, i['y']})")
except:
print("Failed to prioritize food column")
if prioritize_food_row:
try:
for y in range(height):
try:
board[y][i["x"]] += food_surr_val-1
except:
print(f"Failed to prioritize ({i['x'], y})")
except:
print("Failed to prioritize food row")
for i in hazards:
board[height - 1 - i["y"], i["x"]] -= food_val
for snake in snakes:
# snake's head can be a potential danger in near future!
try:
board[height-1-snake["head"]["y"]+1,
snake["head"]["x"]] -= food_val
except:
None
try:
board[height-1-snake["head"]["y"]-1,
snake["head"]["x"]] -= food_val
except:
None
try:
board[height-1-snake["head"]["y"],
snake["head"]["x"]+1] -= food_val
except:
None
try:
board[height-1-snake["head"]["y"],
snake["head"]["x"]-1] -= food_val
except:
None
for i in snake["body"]:
board[height-1 - i["y"], i["x"]] -= other_snake_damage_val * 2.5
try:
board[height-1 - i["y"]+1, i["x"]] -= food_val-1
except:
None
try:
board[height-1 - i["y"]-1, i["x"]] -= food_val-1
except:
None
try:
board[height-1 - i["y"], i["x"]+1] -= food_val-1
except:
None
try:
board[height-1 - i["y"], i["x"]-1] -= food_val-1
except:
None
for i in you["body"]:
board[height-1 - i["y"], i["x"]] -= other_snake_damage_val+100
return board