-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbots.py
More file actions
executable file
·467 lines (416 loc) · 17.8 KB
/
bots.py
File metadata and controls
executable file
·467 lines (416 loc) · 17.8 KB
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
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#!/usr/bin/python
import numpy as np
from tronproblem import *
from trontypes import CellType, PowerupType
import random, math
from queue import Queue
import copy
# Throughout this file, ASP means adversarial search problem.
class TronStateInfo:
def __init__(self, asp, state, powerup1, powerup2):
self.p1_win = 0
self.p2_win = 0
self.ptm = -1
self.powerup1 = powerup1
self.powerup2 = powerup2
self.p1_closest_num = 0
self.p2_closest_num = 0
self.p1_closest_powerups = {}
self.p2_closest_powerups = {}
self._extract_state_info(asp, state)
def cmp(self, other):
"""
Output: [x, y],
x is the compare result of two states for player1,
y is the compare result of two states for player2,
can be -1, 0 or 1
"""
# is terminate state
if self.p1_win or other.p2_win:
return [1, -1]
if self.p2_win or other.p1_win:
return [-1, 1]
x = y = 0
#x
#player has no safe actions
if self.p1_closest_num == 0:
if self.ptm == 0:
x = -1
elif other.p1_closest_num == 0 and self.p2_closest_num < other.p2_closest_num:
x = 1
else:
x = -1
#TRAP
if x == 0 and self.p1_closest_num >= self.p2_closest_num and other.p1_closest_num >= other.p2_closest_num:
traps = []
if self.p1_closest_num >= self.p2_closest_num and other.p1_closest_num >= other.p2_closest_num:
traps = [CellType.TRAP, CellType.BOMB, CellType.ARMOR]
else:
traps = [CellType.BOMB, CellType.ARMOR, CellType.TRAP]
if self.powerup1 in traps and other.powerup1 not in traps:
x = 1
elif self.powerup1 not in traps and other.powerup1 in traps:
x = -1
elif self.powerup1 in traps and other.powerup1 in traps:
if traps.index(self.powerup1) < traps.index(other.powerup1):
x = 1
elif traps.index(self.powerup1) > traps.index(other.powerup1):
x = -1
if x == 0:
for trap in traps:
if x != 0:
break
if trap in self.p1_closest_powerups and trap not in other.p1_closest_powerups:
x = 1
elif trap not in self.p1_closest_powerups and trap in other.p1_closest_powerups:
x = -1
elif trap in self.p1_closest_powerups and trap in other.p1_closest_powerups:
if self.p1_closest_powerups[trap][0] > other.p1_closest_powerups[trap][0]:
x = 1
elif self.p1_closest_powerups[trap][0] < other.p1_closest_powerups[trap][0]:
x = -1
else:
if self.p1_closest_powerups[trap][1] < other.p1_closest_powerups[trap][1]:
x = 1
elif self.p1_closest_powerups[trap][1] > other.p1_closest_powerups[trap][1]:
x = -1
#closest number
if x == 0:
if self.p1_closest_num >= self.p2_closest_num and other.p1_closest_num >= other.p2_closest_num:
if self.p1_closest_num - self.p2_closest_num > other.p1_closest_num - other.p2_closest_num:
x = 1
elif self.p1_closest_num - self.p2_closest_num < other.p1_closest_num - other.p2_closest_num:
x = -1
elif self.p1_closest_num >= self.p2_closest_num and other.p1_closest_num < other.p2_closest_num:
x = 1
elif self.p1_closest_num < self.p2_closest_num and other.p1_closest_num >= other.p2_closest_num:
x = -1
else:
if self.p1_closest_num > other.p1_closest_num:
x = 1
elif self.p1_closest_num < other.p1_closest_num:
x = -1
#y
#player has no safe actions
if self.p2_closest_num == 0:
if self.ptm == 1:
y = -1
elif other.p2_closest_num == 0 and self.p1_closest_num < other.p1_closest_num:
y = 1
else:
y = -1
#TRAP
if y == 0 and self.p2_closest_num >= self.p1_closest_num and other.p2_closest_num >= other.p1_closest_num:
traps = []
if self.p2_closest_num >= self.p1_closest_num and other.p2_closest_num >= other.p1_closest_num:
traps = [CellType.TRAP, CellType.BOMB, CellType.ARMOR]
else:
traps = [CellType.BOMB, CellType.ARMOR, CellType.TRAP]
if self.powerup2 in traps and other.powerup2 not in traps:
y = 1
elif self.powerup2 not in traps and other.powerup2 in traps:
y = -1
elif self.powerup2 in traps and other.powerup2 in traps:
if traps.index(self.powerup2) < traps.index(other.powerup2):
y = 1
elif traps.index(self.powerup2) > traps.index(other.powerup2):
y = -1
if y == 0:
for trap in traps:
if y != 0:
break
if trap in self.p2_closest_powerups and trap not in other.p2_closest_powerups:
y = 1
elif trap not in self.p2_closest_powerups and trap in other.p2_closest_powerups:
y = -1
elif trap in self.p2_closest_powerups and trap in other.p2_closest_powerups:
if self.p2_closest_powerups[trap][0] > other.p2_closest_powerups[trap][0]:
y = 1
elif self.p2_closest_powerups[trap][0] < other.p2_closest_powerups[trap][0]:
y = -1
else:
if self.p2_closest_powerups[trap][1] < other.p2_closest_powerups[trap][1]:
y = 1
elif self.p2_closest_powerups[trap][1] > other.p2_closest_powerups[trap][1]:
y = -1
#closest number
if y == 0:
if self.p2_closest_num >= self.p1_closest_num and other.p2_closest_num >= other.p1_closest_num:
if self.p2_closest_num - self.p1_closest_num > other.p2_closest_num - other.p1_closest_num:
y = 1
elif self.p2_closest_num - self.p1_closest_num < other.p2_closest_num - other.p1_closest_num:
y = -1
elif self.p2_closest_num >= self.p1_closest_num and other.p2_closest_num < other.p1_closest_num:
y = 1
elif self.p2_closest_num < self.p1_closest_num and other.p2_closest_num >= other.p1_closest_num:
y = -1
else:
if self.p2_closest_num > other.p2_closest_num:
y = 1
elif self.p2_closest_num < other.p2_closest_num:
y = -1
return [x, y]
def _extract_state_info(self, asp, state):
if asp.is_terminal_state(state):
self.p1_win, self.p2_win = asp.evaluate_state(state)
return
ptm = state.ptm
self.ptm = ptm
loc1, loc2 = state.player_locs
board = state.board
q1 = Queue()
q1.put(loc1 if ptm == 0 else loc2)
d1, n1, n2, n = 1, 1, 0, 0
powerups1 = {}
q2 = Queue()
q2.put(loc2 if ptm == 0 else loc1)
d2, m1, m2, m = 1, 1, 0, 0
powerups2 = {}
s = set()
while not q1.empty() or not q2.empty():
while n1 > 0:
loc = q1.get()
n1 -= 1
for action in TronProblem.get_safe_actions(board, loc):
next_loc = TronProblem.move(loc, action)
if tuple(next_loc) in s:
continue
s.add(tuple(next_loc))
q1.put(next_loc)
n2 += 1
# powerups
r, c = next_loc
if board[r][c] == CellType.TRAP or board[r][c] == CellType.BOMB or board[r][c] == CellType.ARMOR:
name = board[r][c]
if name not in powerups1:
powerups1[name] = [1, d1]
else:
powerups1[name][0] += 1
n += n2
n1, n2 = n2, 0
d1 += 1
while m1 > 0:
loc = q2.get()
m1 -= 1
for action in TronProblem.get_safe_actions(board, loc):
next_loc = TronProblem.move(loc, action)
if tuple(next_loc) in s:
continue
s.add(tuple(next_loc))
q2.put(next_loc)
m2 += 1
# powerups
r, c = next_loc
if board[r][c] == CellType.TRAP or board[r][c] == CellType.BOMB or board[r][c] == CellType.ARMOR:
name = board[r][c]
if name not in powerups2:
powerups2[name] = [1, d2]
else:
powerups2[name][0] += 1
m += m2
m1, m2 = m2, 0
d2 += 1
self.p1_closest_num = n if ptm == 0 else m
self.p2_closest_num = m if ptm == 0 else n
self.p1_closest_powerups = copy.deepcopy(powerups1) if ptm == 0 else copy.deepcopy(powerups2)
self.p2_closest_powerups = copy.deepcopy(powerups2) if ptm == 0 else copy.deepcopy(powerups1)
class StudentBot:
""" Write your student bot here"""
def __init__(self):
self.BOT_NAME = "tea bot"
def decide(self, asp):
"""
Input: asp, a TronProblem
Output: A direction in {'U','D','L','R'}
To get started, you can get the current
state by calling asp.get_start_state()
"""
max_depth = 2
def maxvalue(asp, state, depth, b1, b2):
nonlocal max_depth
locs = state.player_locs
board = state.board
ptm = state.ptm
loc = locs[ptm]
maxval = act = None
for action in asp.get_available_actions(state):
r, c = TronProblem.move(loc, action)
powerup1 = powerup2 = None
if board[r][c] == CellType.TRAP or board[r][c] == CellType.BOMB or board[r][c] == CellType.ARMOR:
powerup1 = board[r][c]
if ptm == 1:
powerup1, powerup2 = powerup2, powerup1
next_state = asp.transition(state, action)
info = None
if asp.is_terminal_state(next_state) or depth > max_depth or (ptm == 0 and powerup1 or ptm == 1 and powerup2):
info = TronStateInfo(asp, next_state, powerup1, powerup2)
else:
info, _ = maxvalue(asp, next_state, depth + 1, b1, b2)
flag = 0
if not maxval:
maxval = info
act = action
flag = 1
else:
res = info.cmp(maxval)
x, y = res[ptm], res[0 if ptm == 1 else 1]
if x == 1 or (x == 0 and y == -1) or (x == 0 and y == 0 and len(TronProblem.get_safe_actions(board, [r, c])) < 3):
maxval = info
act = action
flag = 1
if flag:
if ptm == 0:
if b1:
res = maxval.cmp(b1)
if res[0] == 1 or (res[0] == 0 and res[1] == -1):
return maxval, act
if not b2:
b2 = maxval
else:
res = maxval.cmp(b2)
if res[0] == 1 or (res[0] == 0 and res[1] == -1):
b2 = maxval
else:
if b2:
res = maxval.cmp(b2)
if res[1] == 1 or (res[1] == 0 and res[0] == -1):
return maxval, act
if not b1:
b1 = maxval
else:
res = maxval.cmp(b1)
if res[1] == 1 or (res[1] == 0 and res[0] == -1):
b1 = maxval
return maxval, act
start_state = asp.get_start_state()
locs = start_state.player_locs
if abs(locs[0][0] - locs[1][0]) + abs(locs[0][0] - locs[1][0]) <= 4:
max_depth = 3
_, act = maxvalue(asp, start_state, 1, None, None)
return act
def cleanup(self):
"""
Input: None
Output: None
This function will be called in between
games during grading. You can use it
to reset any variables your bot uses during the game
(for example, you could use this function to reset a
turns_elapsed counter to zero). If you don't need it,
feel free to leave it as "pass"
"""
pass
# def alpha_beta_cutoff(asp, cutoff_ply):
# def max_value(asp, state, a, b, cutoff_ply, player):
# if asp.is_terminal_state(state):
# return TronStateInfo(state)
# if cutoff_ply == 0:
# return TronStateInfo(state)
# actions = asp.get_available_actions(state)
# cur_max = None
# for action in actions:
# next_state_info = min_value(asp, asp.transition(state, action), a, b, cutoff_ply - 1, player)
# if not cur_max:
# cur_max = next_state_info
# cmp_result = cur_max.cmp(next_state_info)
# if cmp_result[player] == -1:
# cur_max = next_state_info
# else if cmp_result[player] == 0:
# if cmp_result[1 - player] == 1:
# cur_max = next_state_info
# if cur_max.cmp(b)[player] == 1:
# return cur_max
# if cur_max.cmp(a)[player] == 1:
# a = cur_max
# return cur_max
# def min_value(asp, state, a, b, cutoff_ply, player):
# if asp.is_terminal_state(state):
# return TronStateInfo(state)
# if cutoff_ply == 0:
# return TronStateInfo(state)
# actions = asp.get_available_actions(state)
# cur_min = None
# for action in actions:
# next_state_info = max_value(asp, asp.transition(state, action), a, b, cutoff_ply - 1, player)
# if not cur_min:
# cur_min = next_state_info
# cmp_result = cur_min.cmp(next_state_info)
# if cmp_result[player] == 1:
# cur_min = next_state_info
# else if cmp_result[player] == 0:
# if cmp_result[1 - player] == -1:
# cur_min = next_state_info
# if cur_min.cmp(a)[player] == -1:
# return cur_min
# if cur_max.cmp(b)[player] == -1:
# b = cur_min
# return cur_min
# cur_state = asp.get_start_state()
# player = cur_state.player_to_move()
# actions = asp.get_available_actions(cur_state)
# ret_a = None
# a, b, cur_max = None, None, None
# for action in actions:
# next_state_info = min_value(asp, asp.transition(cur_state, action), a, b, cutoff_ply - 1, player)
# cur_max = next_state_info if not cur_max
# a = cur_max if not a
# b = cur_max if not b
# cmp_result = cur_max.cmp(next_state_info)
# if cmp_result[player] == -1:
# cur_max = next_state_info
# ret_a = action
# if cur_max.cmp(b)[player] == 1:
# return ret_a
# if cur_max.cmp(a)[player] == 1:
# a = cur_max
# return ret_a
class RandBot:
"""Moves in a random (safe) direction"""
def decide(self, asp):
"""
Input: asp, a TronProblem
Output: A direction in {'U','D','L','R'}
"""
state = asp.get_start_state()
locs = state.player_locs
board = state.board
ptm = state.ptm
loc = locs[ptm]
possibilities = list(TronProblem.get_safe_actions(board, loc))
if possibilities:
return random.choice(possibilities)
return "U"
def cleanup(self):
pass
class WallBot:
"""Hugs the wall"""
def __init__(self):
order = ["U", "D", "L", "R"]
random.shuffle(order)
self.order = order
def cleanup(self):
order = ["U", "D", "L", "R"]
random.shuffle(order)
self.order = order
def decide(self, asp):
"""
Input: asp, a TronProblem
Output: A direction in {'U','D','L','R'}
"""
state = asp.get_start_state()
locs = state.player_locs
board = state.board
ptm = state.ptm
loc = locs[ptm]
possibilities = list(TronProblem.get_safe_actions(board, loc))
if not possibilities:
return "U"
decision = possibilities[0]
for move in self.order:
if move not in possibilities:
continue
next_loc = TronProblem.move(loc, move)
if len(TronProblem.get_safe_actions(board, next_loc)) < 3:
decision = move
break
return decision