def get_move(self, gameboard, player, opponent): start = millitime() dbout2("##### Turn: " + str(gameboard.current_turn) + " #####") dbout("") dbout("") # Initialize bot params if gameboard.current_turn == 0: self.dieTurrets = TurretHunter() self.generate_graph(gameboard) dbout("graph generated!") #dbout(nx.shortest_path(self.G, (player.y, player.x), (pu.y, pu.x))) self.dieTurrets.getTurretFARC(gameboard) dbout("Calculated turret firing arcs") # Update turret list to check for dead turrets self.dieTurrets.updateTurretList(gameboard) if player.laser_count>0 and self.should_fire_laser(gameboard, player, opponent): return Move.LASER avoid_list = self.avoid_opponent_fire(gameboard, opponent) avoid_list += self.TilesToAvoid(gameboard, player, opponent) if (player.y, player.x) in avoid_list: try: path, nmoves = self.path_to_next_safest_spot(gameboard, player, opponent, avoid_list) except: pass if nmoves == 1: return self.movement_direction(path, gameboard, player) else: if player.shield_count > 0: return Move.SHIELD elif player.teleport_count > 0: return Move.TELEPORT else: pass yesno, path = self.opponent_is_in_los(gameboard, player, opponent) if yesno: mmove = self.movement_direction(path, gameboard, player) if mmove == Move.FORWARD: return Move.SHOOT return mmove path = self.path_to_enemy(gameboard, player, opponent, avoid_list) try: if opponent.laser_count > 0: avoid_list.extend(self.avoid_opponent_laser(gameboard, opponent)) dbout(avoid_list) to_avoid = [] while True: if len(gameboard.power_ups) > 0: path = self.closest_power_up(gameboard, player, to_avoid) else: path = self.path_to_enemy(gameboard, player, opponent, to_avoid) if path[1] not in avoid_list: break to_avoid.append(path[1]) except: dbout("EXCEPTION: UNABLE TO FIND PATH") dbout(self.G.edges()) path = [] if ((player.y, player.x) in avoid_list and self.movement_direction(path, gameboard, player) != Move.FORWARD): if player.shield_count > 0: return Move.SHIELD elif player.teleport_count > 0: return Move.TELEPORT # Debug for printing bullet specs # if len(gameboard.bullets) > 0: # for i, b in enumerate(gameboard.bullets): # dbout(str(i) + ":" + str(b.x) + "," + str(b.y) + "," + str(b.direction)+ "\t") end = millitime() print("Time elapsed:" + str(end - start)) # Hardcode movements # moves = [Move.SHOOT, Move.NONE] # self.i = self.i+1 if self.i<len(moves)-1 else len(moves)-1 # return moves[self.i] dbout("Attempting to Follow path: ") dbout(path) if (self.none_counter > 3): return Move.LEFT if len(path)>1: next_move = self.movement_direction(path, gameboard, player) if next_move == Move.NONE: ++self.none_counter; return next_move ++self.none_counter; return Move.NONE
class PlayerAI: def __init__(self): # Initialize any objects or variables you need here. self.i = -1; self.dieTurrets = None self.none_counter = 0; pass def should_fire_laser(self, gameboard, player, opponent): path = self.get_shortest_path(player, opponent, []) if len(path)<=5 and (player.x==opponent.x or player.y==opponent.y): return True return False def closest_power_up(self, gameboard, player, avoid_list): paths = [] for ps in gameboard.power_ups: paths.append(self.get_shortest_path(player, ps, avoid_list)) #TO ADD - AVOID mind = 1000000 cur_index = 0 for i in range(0, len(paths)): if len(paths[i]) < mind: mind = len(paths[i]) cur_index = i return paths[cur_index] def opponent_is_in_los(self, gameboard, player, opponent): if opponent.x==player.x or opponent.y==player.y: path = self.get_shortest_path(player, opponent, []) if self.is_direct_path(path): return True, path return False, [] def avoid_opponent_fire(self, gameboard, opponent): avoid_list = [] isWall = [False, False, False, False] for i in range(1, 4): if not isWall[0] and not gameboard.is_wall_at_tile(opponent.x, (opponent.y-i)%gameboard.height): if opponent.laser_count > 0: avoid_list.append(((opponent.y-i)%gameboard.height, opponent.x)) # go up elif opponent.direction == Direction.UP and i < 3: avoid_list.append(((opponent.y-i)%gameboard.height, opponent.x)) # go up else: isWall[0] = True if not isWall[1] and not gameboard.is_wall_at_tile(opponent.x, (opponent.y+i)%gameboard.height): if opponent.laser_count > 0: avoid_list.append(((opponent.y+i)%gameboard.height, opponent.x)) # down elif opponent.direction == Direction.DOWN and i < 3: avoid_list.append(((opponent.y+i)%gameboard.height, opponent.x)) # down else: isWall[1] = True if not isWall[2] and not gameboard.is_wall_at_tile((opponent.x+i)%gameboard.width, opponent.y): if opponent.laser_count > 0: avoid_list.append((opponent.y, (opponent.x+i)%gameboard.width)) #right elif opponent.direction == Direction.RIGHT and i < 3: avoid_list.append((opponent.y, (opponent.x+i)%gameboard.width)) #right else: isWall[2] = True if not isWall[3] and not gameboard.is_wall_at_tile((opponent.x-i)%gameboard.width, opponent.y): if opponent.laser_count > 0: avoid_list.append((opponent.y, (opponent.x-i)%gameboard.width)) #left elif opponent.direction == Direction.LEFT and i < 3: avoid_list.append((opponent.y, (opponent.x-i)%gameboard.width)) #left else: isWall[3] = True avoid_list.append((opponent.y, opponent.x)) return avoid_list def TilesToAvoid(self, gameboard, player, opponent): # Checks if a tile is dangerous, given that tile argument is # dictionary of form {"x":x, "y":y} avoid = [] # Check for incoming turret fire avoid += self.dieTurrets.buildAvoidanceListYX(gameboard) # Check for incoming bullets for i, b in enumerate(gameboard.bullets): # Predict next position of all bullets dbout(str(i) + ":" + str(b.x) + "," + str(b.y) + "," + str(b.direction)+ "\t") if (b.direction == Direction.UP): avoid.append(((b.y-1)%gameboard.height, b.x)) elif (b.direction == Direction.DOWN): avoid.append(((b.y+1)%gameboard.height, b.x)) elif (b.direction == Direction.RIGHT): avoid.append((b.y, (b.x+1)%gameboard.width)) elif (b.direction == Direction.LEFT): avoid.append((b.y, (b.x-1)%gameboard.width)) avoid.append((opponent.y, opponent.x)) return avoid def get_shortest_path(self, player, target, avoid): """ avoid ([nodes]): nodes to temporarily avoid, (y,x) """ temp_edge_storage = [] dbout("AVOID LIST:") dbout(avoid) temp_edge_storage = [] path = [] for node in avoid: neighbors = list(nx.all_neighbors(self.G, node)) for neighbor in neighbors: self.G.remove_edge(node, neighbor) temp_edge_storage.extend([(node, neighbor) for neighbor in neighbors]) try: path = nx.shortest_path(self.G, (player.y, player.x), (target.y, target.x)) except: dbout("EXCEPTION: UNABLE TO FIND SHORTEST PATH") for edge in temp_edge_storage: self.G.add_edge(edge[0], edge[1]) raise Exception("Except") for edge in temp_edge_storage: self.G.add_edge(edge[0], edge[1]) dbout("PATH FROM PLAYER TO TARGET GIVEN AVOID LIST:") dbout(path) return path def single_source_shortest_path(self, player, avoid): """ avoid ([nodes]): nodes to temporarily avoid, (y,x) """ temp_edge_storage = [] dbout("AVOID LIST:") dbout(avoid) temp_edge_storage = [] paths = [] for node in avoid: neighbors = list(nx.all_neighbors(self.G, node)) for neighbor in neighbors: self.G.remove_edge(node, neighbor) temp_edge_storage.extend([(node, neighbor) for neighbor in neighbors]) try: paths = nx.single_source_shortest_path(self.G, (player.y, player.x), cutoff=10) paths = list(paths.values()) del paths[0] except: dbout("EXCEPTION: UNABLE TO FIND SHORTEST PATH") for edge in temp_edge_storage: self.G.add_edge(edge[0], edge[1]) raise Exception("Except") for edge in temp_edge_storage: self.G.add_edge(edge[0], edge[1]) dbout("PATH FROM PLAYER TO TARGET GIVEN AVOID LIST:") dbout(paths) return paths def movement_direction(self, path, gameboard, player): y1 = path[0][0] x1 = path[0][1] y2 = path[1][0] x2 = path[1][1] cur_direction = player.direction if y1==y2: if (x2<x1 and not (x1==gameboard.width-1 and x2==0)) or (x1==0 and x2==gameboard.width-1): if cur_direction == Direction.LEFT: return Move.FORWARD else: return Move.FACE_LEFT elif (x2>x1 and not (x1==0 and x2==gameboard.width-1)) or (x1==gameboard.width-1 and x2==0): if cur_direction == Direction.RIGHT: return Move.FORWARD else: return Move.FACE_RIGHT else: return Move.NONE elif x1==x2: if (y2<y1 and not(y1==gameboard.height-1 and y2==0)) or (y1==0 and y2==gameboard.height-1): if cur_direction == Direction.UP: return Move.FORWARD else: return Move.FACE_UP elif (y2>y1 and not(y1==0 and y2==gameboard.height-1)) or (y1==gameboard.height-1 and y2==0): if cur_direction == Direction.DOWN: return Move.FORWARD else: return Move.FACE_DOWN else: return Move.NONE def generate_graph(self, gb): G = nx.Graph() nodes = [] for y in range(0, gb.height): for x in range(0, gb.width): G.add_node((y, x)) nodes.append((y, x)) for i in range(0, gb.height): # for every row row_nodes = nodes[i*gb.width:(i+1)*gb.width] #dbout(str(row_nodes)) G.add_edge(row_nodes[0], row_nodes[-1]) # connect from and last cell #dbout("connected: " + str(G.edges()[-1])) for j in range(0, gb.width-1): G.add_edge(row_nodes[j], row_nodes[j+1]) #dbout("connected: " + str(G.edges()[-1])) for i in range(0, gb.width): # for every column G.add_edge(nodes[i], nodes[(gb.height-1)*gb.width+i]) #dbout("connected: " + str(G.edges()[-1])) for j in range(0, gb.height-1): G.add_edge(nodes[i+j*gb.width], nodes[i+(j+1)*gb.width]) #dbout("connected: " + str(G.edges()[-1])) for wall in gb.walls: G.remove_node((wall.y, wall.x)) for turret in gb.turrets: G.remove_node((turret.y, turret.x)) self.G = G def is_direct_path(self, path): sety = set([node[0] for node in path]) if len(sety)==1: return True setx = set([node[1] for node in path]) if len(setx)==1: return True return False def argmin(self, mlist): minval = mlist[0] minindex = 0 for i in range(1, len(mlist)): if mlist[i] < minval: minval = mlist[i] minindex = i return minindex def path_to_enemy(self, gameboard, player, opponent, avoid): end_nodes = list(nx.all_neighbors(self.G, (opponent.y, opponent.x))) opp_front_node = None if opponent.direction == Direction.UP: opp_front_node = (opponent.y-1, opponent.x) if opponent.direction == Direction.DOWN: opp_front_node = (opponent.y+1, opponent.x) if opponent.direction == Direction.RIGHT: opp_front_node = (opponent.y, opponent.x+1) if opponent.direction == Direction.LEFT: opp_front_node = (opponent.y, opponent.x-1) if opp_front_node in end_nodes: end_nodes.remove(opp_front_node) dbout((player.y, player.x)) for end_node in end_nodes: dbout(end_node) paths = [self.get_shortest_path(player, GameObject(end_node[1], end_node[0]), avoid) for end_node in end_nodes] if len(paths)==0: return [] return paths[self.argmin([len(path) for path in paths])] def enemy_is_pointed_toward_us(self, gameboard, opponent, path_to_opponent): mmove = self.movement_direction(list(reversed(path_to_opponent)), gameboard, opponent) if mmove == Move.FORWARD: return True return False def num_moves_to_execute_path(self, path, gameboard, player): num_moves = 0 for i in range(0, len(path)-1): mmove = self.movement_direction(path[i::], gameboard, player) if mmove==Move.FORWARD: num_moves = num_moves+1 else: num_moves = num_moves+2 # requires rotation and movement return num_moves def path_to_next_safest_spot(self, gameboard, player, opponent, avoid): if (player.y, player.x) in avoid: avoid.remove((player.y, player.x)) paths = self.single_source_shortest_path(player, avoid) path_lengths = [] for path in paths: dbout("111111111111111") dbout(path) if len(path) <= 1: continue path_lengths.append(self.num_moves_to_execute_path(path, gameboard, player)) return paths[self.argmin(path_lengths)], self.argmin(path_lengths) def get_move(self, gameboard, player, opponent): start = millitime() dbout2("##### Turn: " + str(gameboard.current_turn) + " #####") dbout("") dbout("") # Initialize bot params if gameboard.current_turn == 0: self.dieTurrets = TurretHunter() self.generate_graph(gameboard) dbout("graph generated!") #dbout(nx.shortest_path(self.G, (player.y, player.x), (pu.y, pu.x))) self.dieTurrets.getTurretFARC(gameboard) dbout("Calculated turret firing arcs") # Update turret list to check for dead turrets self.dieTurrets.updateTurretList(gameboard) if player.laser_count>0 and self.should_fire_laser(gameboard, player, opponent): return Move.LASER avoid_list = self.avoid_opponent_fire(gameboard, opponent) avoid_list += self.TilesToAvoid(gameboard, player, opponent) if (player.y, player.x) in avoid_list: try: path, nmoves = self.path_to_next_safest_spot(gameboard, player, opponent, avoid_list) except: pass if nmoves == 1: return self.movement_direction(path, gameboard, player) else: if player.shield_count > 0: return Move.SHIELD elif player.teleport_count > 0: return Move.TELEPORT else: pass yesno, path = self.opponent_is_in_los(gameboard, player, opponent) if yesno: mmove = self.movement_direction(path, gameboard, player) if mmove == Move.FORWARD: return Move.SHOOT return mmove path = self.path_to_enemy(gameboard, player, opponent, avoid_list) try: if opponent.laser_count > 0: avoid_list.extend(self.avoid_opponent_laser(gameboard, opponent)) dbout(avoid_list) to_avoid = [] while True: if len(gameboard.power_ups) > 0: path = self.closest_power_up(gameboard, player, to_avoid) else: path = self.path_to_enemy(gameboard, player, opponent, to_avoid) if path[1] not in avoid_list: break to_avoid.append(path[1]) except: dbout("EXCEPTION: UNABLE TO FIND PATH") dbout(self.G.edges()) path = [] if ((player.y, player.x) in avoid_list and self.movement_direction(path, gameboard, player) != Move.FORWARD): if player.shield_count > 0: return Move.SHIELD elif player.teleport_count > 0: return Move.TELEPORT # Debug for printing bullet specs # if len(gameboard.bullets) > 0: # for i, b in enumerate(gameboard.bullets): # dbout(str(i) + ":" + str(b.x) + "," + str(b.y) + "," + str(b.direction)+ "\t") end = millitime() print("Time elapsed:" + str(end - start)) # Hardcode movements # moves = [Move.SHOOT, Move.NONE] # self.i = self.i+1 if self.i<len(moves)-1 else len(moves)-1 # return moves[self.i] dbout("Attempting to Follow path: ") dbout(path) if (self.none_counter > 3): return Move.LEFT if len(path)>1: next_move = self.movement_direction(path, gameboard, player) if next_move == Move.NONE: ++self.none_counter; return next_move ++self.none_counter; return Move.NONE