def test_map_pathfinding(self): pathmap = Map((10, 10), []) self.assertEquals([(9, 9)], pathmap.get_shortest_path((0, 0), (9, 9))) pathmap = Map((10, 5), [ Obstacle('SOLID', (0, 1), (9, 1)), Obstacle('IMPASSABLE', (1, 3), (9, 1)) ]) v_map = "0000000000\n" + \ "0111111111\n" + \ "0000000000\n" + \ "2222222220\n" + \ "0000000000\n" self.assertEquals(pathmap.get_grid_display(), v_map) self.assertEquals( [(8, 0), (9, 1), (8, 2), (1, 2), (0, 3), (1, 4), (9, 4)], pathmap.get_shortest_path((0, 0), (9, 4)) ) pathmap = Map((10, 5), [ Obstacle('SOLID', (0, 2), (10, 1)), ]) v_map = "0000000000\n" + \ "0000000000\n" + \ "2222222222\n" + \ "0000000000\n" + \ "0000000000\n" self.assertEquals(pathmap.get_grid_display(), v_map) self.assertEquals([], pathmap.get_shortest_path((0, 0), (9, 4)))
def parse_game_state(self, json_game_state, parse_map=False): """ json_game_state structure Populate self with the json_game_state. :param json_game_state: Json object of the current game state """ self.time_remaining = json_game_state['timeRemaining'] if parse_map: map_size = json_game_state['map']['size'][0], json_game_state['map']['size'][1] map_obstacles = [] for terrain in json_game_state['map']['terrain']: map_obstacles.append( Obstacle(terrain['type'], terrain['boundingBox']['corner'], terrain['boundingBox']['size']) ) self.map = Map(map_size, map_obstacles) self.players = [] for player in json_game_state['players']: score = player['score'] name = player['name'] tanks = [] for tank in player['tanks']: id = tank['id'] health = tank['health'] hit_radius = tank['hitRadius'] collision_radius = tank['collisionRadius'] type = tank['type'] position = tank['position'] tracks = tank['tracks'] turret = tank['turret'] speed = tank['speed'] projectiles = [] for projectile in tank['projectiles']: p_id = projectile['id'] p_position = projectile['position'] p_direction = projectile['direction'] p_speed = projectile['speed'] p_damage = projectile['damage'] p_range = projectile['range'] projectiles.append(Projectile(p_id, p_position, p_direction, p_speed, p_damage, p_range)) tanks.append( Tank(id, health, hit_radius, collision_radius, type, position, tracks, turret, speed, projectiles)) self.players.append(Player(name, score, tanks))
def test_map_grid_creation(self): t_map = Map((10, 75), []) self.assertEqual(len(t_map.grid), 10) # X values self.assertEqual(len(t_map.grid[0]), 75) # Y values t_map = Map( (10, 50), [ Obstacle('SOLID', [1, 1], [3, 5]), # Start at map (1, 1), 3 wide 5 tall Obstacle('IMPASSABLE', [4, 6], [6, 20]), # Start at map (4, 6), 6 wide 20 tall Obstacle('NORMAL', [0, 4], [10, 10]), # Ignore this, Normal obstacles are 0 Obstacle('SOLID', [0, 40], [30, 1]) # Start at map (0, 20), 30 wide 1 tall (test oob objects) ] ) ref_v_map = "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "2222222222\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000000000\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0000111111\n" + \ "0222000000\n" + \ "0222000000\n" + \ "0222000000\n" + \ "0222000000\n" + \ "0222000000\n" + \ "0000000000\n" self.assertEquals(t_map.get_grid_display(), ref_v_map)
class Algorithm: """ Calculates the actions for the current game state. TODO: This algorithm only works when the map is small and there are a few number of tanks! So that one swirl map with two tanks, it seems to be fine. For larger maps, this algorithm will occasionally make the tanks spin around in circles and just nuke itself. It might be a memory error? When running the naive section of the code without performing the pathfinding computation it behaves fine, but if you run the pathfinding computation the naive algorithm no longer functions. """ team_name = "" client_token = "" time_remaining = "" map = None players = [] def __init__(self, team_name, client_token): self.team_name = team_name self.client_token = client_token def parse_game_state(self, json_game_state, parse_map=False): """ json_game_state structure Populate self with the json_game_state. :param json_game_state: Json object of the current game state """ self.time_remaining = json_game_state['timeRemaining'] if parse_map: map_size = json_game_state['map']['size'][0], json_game_state['map']['size'][1] map_obstacles = [] for terrain in json_game_state['map']['terrain']: map_obstacles.append( Obstacle(terrain['type'], terrain['boundingBox']['corner'], terrain['boundingBox']['size']) ) self.map = Map(map_size, map_obstacles) self.players = [] for player in json_game_state['players']: score = player['score'] name = player['name'] tanks = [] for tank in player['tanks']: id = tank['id'] health = tank['health'] hit_radius = tank['hitRadius'] collision_radius = tank['collisionRadius'] type = tank['type'] position = tank['position'] tracks = tank['tracks'] turret = tank['turret'] speed = tank['speed'] projectiles = [] for projectile in tank['projectiles']: p_id = projectile['id'] p_position = projectile['position'] p_direction = projectile['direction'] p_speed = projectile['speed'] p_damage = projectile['damage'] p_range = projectile['range'] projectiles.append(Projectile(p_id, p_position, p_direction, p_speed, p_damage, p_range)) tanks.append( Tank(id, health, hit_radius, collision_radius, type, position, tracks, turret, speed, projectiles)) self.players.append(Player(name, score, tanks)) def generate_actions(self): actions = [] my_player = None enemy_player = None for player in self.players: if player.name == self.team_name: my_player = player else: enemy_player = player for my_tank in my_player.tanks: # print "Calculating for %s" % my_tank.id s_path_len = 9999999999 s_path = [] s_path_tank = None for enemy_dist, enemy_tank in my_tank.get_all_dist_tank(enemy_player.tanks): # print "\t %s" % enemy_tank.id temp_s_path = self.map.get_shortest_path(my_tank.position, enemy_tank.position) if s_path_len > len(temp_s_path) > 0: s_path = temp_s_path s_path_tank = enemy_tank s_path_len = len(temp_s_path) if len(s_path) >= 1: tur_dir, tur_rad = my_tank.get_direction_rotation_turret_to_tank(s_path_tank) tra_dir, tra_rad = my_tank.get_direction_rotation_track_to_point(s_path[0]) dist = my_tank.get_dist_to_point(s_path[0]) actions.append(Command.get_turret_rotation_command(my_tank.id, tur_dir, tur_rad, self.client_token)) actions.append(Command.get_tank_rotation_command(my_tank.id, tra_dir, tra_rad, self.client_token)) actions.append(Command.get_movement_command(my_tank.id, 'FWD', dist, self.client_token)) if my_tank.no_friendly_fire(my_player.tanks, my_tank.get_dist_to_tank(s_path_tank), s_path_tank): actions.append(Command.get_fire_command(my_tank.id, self.client_token)) else: # don't shoot friend from queued bullet actions.append(Command.get_stop_command(my_tank.id, CommType.FIRE, self.client_token)) else: dist, tank = my_tank.get_closest_dist_tank(enemy_player.tanks) tur_dir, tur_rad = my_tank.get_direction_rotation_turret_to_tank(tank) tra_dir, tra_rad = my_tank.get_direction_rotation_track_to_tank(tank) actions.append(Command.get_turret_rotation_command(my_tank.id, tur_dir, tur_rad, self.client_token)) actions.append(Command.get_tank_rotation_command(my_tank.id, tra_dir, tra_rad, self.client_token)) actions.append(Command.get_movement_command(my_tank.id, 'FWD', dist, self.client_token)) if my_tank.no_friendly_fire(my_player.tanks, dist, tank): actions.append(Command.get_fire_command(my_tank.id, self.client_token)) else: # don't shoot friend from queued bullet actions.append(Command.get_stop_command(my_tank.id, CommType.FIRE, self.client_token)) return actions