def simple_flood(self): map_size = 21 flooded_tiles = [[1] * map_size for _ in range(map_size)] flooded_tiles[5][5] = 0 flooded_tiles[5][6] = 0 flooded_tiles[6][5] = 0 flooded_tiles[6][6] = 0 flood(flooded_tiles, 1, 0)
def test_open_path(self): tiles = [ # fmt: off [1, 1, 1, 1, 1], [1, 0, 1, 1, 1], [1, 0, 1, 1, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1] # fmt: on ] size = len(tiles) flood(tiles, 1, 0) self.assertEqual(tiles, [[0] * size for _ in range(size)])
def test_closed_box(self): tiles = [ # fmt: off [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1] # fmt: on ] flood(tiles, 1, 0) expected = [ # fmt: off [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] # fmt: on ] self.assertEqual(tiles, expected)
def test_closed_box_corner(self): # This test case is not possible by construction wince we have an asteroids around the map tiles = [ # fmt: off [1, 0, 1, 1, 1], [1, 0, 1, 1, 1], [1, 0, 1, 1, 1], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1] # fmt: on ] flood(tiles, 1, 0) expected = [ # fmt: off [0, 0, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] # fmt: on ] self.assertEqual(tiles, expected)
def fill(self, player: PlayerState) -> Set[Position]: id = player.id # tail have the starting and ending tiles (last tile before going in the empty zone and first captured tile) assert len(player.tail) >= 3 assert self.game_map.is_conquered_by(player.tail[0], id) assert self.game_map.is_conquered_by(player.tail[-1], id) # new captured tiles minus start and end tiles (already captured) new_conquers = set(player.tail[1:-1]) # check if we have a closed loop to fill: find shortest path from start to end of tail while walking only on conquered tiles closed_loop, shortest_path_to_close_tail = self.game_map.find_path( player.tail[0], player.tail[-1], id) if closed_loop: # Conquer the closed shape made by the tail map_size = self.game_map.size flooded_tiles = [[1] * map_size for _ in range(map_size)] for p in player.tail: flooded_tiles[p.y][p.x] = 0 for p in shortest_path_to_close_tail: flooded_tiles[p.y][p.x] = 0 # flooding work by changing the value to 0 for every reachable tiles from the top left of the map (skipping bombs, # walls and other players) The remainder are the tiles that will be flooded. Using the closest path from start # to end of the tail make sure that we are filling only the smallest zone when wrap around and also make sure we # do not re-kill any players walking inside our captured zone. flood(flooded_tiles, target=1, replacement=0) for y in range(map_size): for x in range(map_size): if flooded_tiles[y][x] == 1: p = Position(x, y) # skip already conquered tiles or walls (asteroids) if not self.game_map.is_conquered_by( p, id) and not self.game_map.is_asteroids(p): if self.game_map.is_black_hole(p): # if we happen to surround a black hole, we die instantly self.stepped_on_a_black_hole(p, player) return set() for y in range(map_size): for x in range(map_size): if flooded_tiles[y][x] == 1: p = Position(x, y) # skip already conquered tiles or walls (asteroids) if not self.game_map.is_conquered_by( p, id) and not self.game_map.is_asteroids(p): if self.game_map.is_blitzium(p): # surrounding a coin (blitzium) will give us more points. self.check_if_captured_a_blitzium(p, player) # add tile to new conquered tiles for later scoring new_conquers.add(p) self.game_map.conquer_tile(p, id) # capture the tail (no-op to recapture start and end tiles) for t in player.tail: self.game_map.conquer_tile(t, id) player.tail = [player.position.copy()] # adjust stats nb_conquers = len(new_conquers) self.logger.info( f"Player '{player.name_str()}' is capturing {nb_conquers} new tiles.." ) player.stats.set_stat( PlayerStats.CONQUERED, player.stats.stats[PlayerStats.CONQUERED] + nb_conquers) player.score += GameState.SCORE_NEW_CONQUERED * nb_conquers player.add_history(self.game_tick, f"Conquered {nb_conquers} new tiles.") return new_conquers
def test_all(self): size = 10 tiles = [[1] * size for _ in range(size)] flood(tiles, 1, 0) self.assertEqual(tiles, [[0] * size for _ in range(size)])