-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflee_bot.py
209 lines (167 loc) · 6.45 KB
/
flee_bot.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
'''
This is a random flee bot.
It places bombs and runs away from them.
Hopefully it escapes safely.
'''
import time
import random
class agent:
def __init__(self, player_num, env):
self.name = "new flee bot" ###### give your bot a name ######
self.player_num = player_num
self.env = env
def give_next_move(self, solid_state):
'''
This method is called each time the player needs to choose an
action
solid_state: is a dictionary containing all the information about the board
'''
#transfering a single solid_state
self.board = solid_state["board"]
self.done = solid_state["done"]
self.bombs = solid_state["bombs"]
self.turn = solid_state["turn"]
self.player = solid_state["players"][self.player_num-1]
########################
### VARIABLES ###
########################
# as player 1, the map representation of us standing on a tile with a bomb
# is different to player 2's - so we'll store this value here for reference
if self.player.number == 0:
player_on_bomb_id = 6 # we are player 1
else:
player_on_bomb_id = 7 # we are player 2
rows = self.board.shape[0]
cols = self.board.shape[1]
actions = ['none','left','right','up','down','bomb']
action_id = [0,1,2,3,4,5]
d_actions = dict(zip(actions,action_id))
########################
### HELPERS ###
########################
# given a tile location as an (x,y) tuple, this function
# will return the surrounding tiles up, down, left and to the right as a list
# (i.e. [(x1,y1), (x2,y2),...])
# as long as they do not cross the edge of the map
def get_surrounding_tiles(board, position):
# store some useful information about our environment
rows = board.shape[0]
cols = board.shape[1]
# find all the surrounding tiles relative to us
# position[0] = row index; position[1] = col index
tile_up = (position[0]-1,position[1])
tile_down = (position[0]+1, position[1])
tile_left = (position[0],position[1]-1)
tile_right = (position[0],position[1]+1)
# combine these into a list
surrounding_tiles = [tile_up, tile_down, tile_left, tile_right]
# create a list to store tiles we can't move to
# (ones that cross the borders of the map, and holes)
tiles_to_remove = []
# loop through surrounding tiles
for tile in surrounding_tiles:
# i.e. that tile would go off the edge of the map
if (tile[0] < 0 or tile[1] < 0 or tile[0] >= rows or tile[1] >= cols or
board[tile] == 4):
# add illegal tiles to our list
tiles_to_remove.append(tile)
# loop through the tiles we're going to exclude
# and remove them from our original list of tiles
for tile in tiles_to_remove:
surrounding_tiles.remove(tile)
return surrounding_tiles
# given a list of tiles
# return the ones which are actually empty
def get_empty_tiles(board, list_of_tiles):
# make a list where we'll store our empty tiles
empty_tiles = []
for tile in list_of_tiles:
if board[tile] == 0:
# that tile is empty, so add it to the list
empty_tiles.append(tile)
return empty_tiles
# given a list of tiles, and the bomb's position on the map
# return only the tiles which are not within 1 tile of the bomb
def get_safe_tiles(list_of_tiles, bomb_pos):
# make a list where we'll store our safe tiles
safe_tiles = []
# loop the tiles
for tile in list_of_tiles:
# subtract the coordinates of the current tile and bomb
# diff will give us the 'distance' to the bomb
diff = tuple(x-y for x, y in zip(tile, bomb_pos))
if diff in [(0,1),(1,0),(0,-1),(-1,0),(0,0)]:
# this tile is adjacent to a bomb
pass
else:
# otherwise, the tile should be safe
safe_tiles.append(tile)
return safe_tiles
# given an adjacent tile location, move us there
def move_to_tile(position, tile):
# a useful dictionary for our actions
actions = ['none','left','right','up','down','bomb']
action_id = [0,1,2,3,4,5]
d_actions = dict(zip(actions,action_id))
# see where the tile is relative to our current location
diff = tuple(x-y for x, y in zip(position, tile))
# return the action that moves in the direction of the tile
if diff == (0,1):
action = d_actions['left']
elif diff == (1,0):
action = d_actions['up']
elif diff == (0,-1):
action = d_actions['right']
elif diff == (-1,0):
action = d_actions['down']
return action
########################
### AGENT ###
########################
# first, check if we've placed some bombs on the map
if self.player.bombs:
# if our 'player' object has bomb objects on them
# that means we've placed a bomb, so let's run away.
# get the bomb's position
bomb_pos = self.player.bombs[0].position
# get a list of our surrounding tiles
surrounding_tiles = get_surrounding_tiles(self.board, self.player.position)
# get a list of the available tiles we can actually move to
empty_tiles = get_empty_tiles(self.board, surrounding_tiles)
# get a list of the safe tiles we should move to
safe_tiles = get_safe_tiles(empty_tiles, bomb_pos)
# check if we're on the bomb
if self.board[self.player.position] == player_on_bomb_id:
# we're on a bomb
# let's move to an empty slot
if empty_tiles:
random_tile = random.choice(empty_tiles)
action = move_to_tile(self.player.position, random_tile)
else:
# there aren't any empty tiles to go to
# we're probably done for.
action = d_actions['none']
else:
# we're not on a bomb
# check if we're next to a bomb
for tile in surrounding_tiles:
if (tile[0] == bomb_pos[0]) and (tile[1] == bomb_pos[1]):
# we're next to a bomb
# move to a random safe tile (if there are any)
if safe_tiles:
random_tile = random.choice(safe_tiles)
action = move_to_tile(self.player.position, random_tile)
break
else:
# there isn't a guaranteed safe tile near us
# choose a move at random
action = d_actions[random.choice(actions)]
break
else:
# there isn't a bomb nearby
# we're probably safe so lets stay here
action = d_actions['none']
else:
# no bombs in play, take a random action
action = random.choice([0,1,2,3,4,5])
return action