def test_eq(self): self.assertEqual(GameMap(5), GameMap(5)) self.assertNotEqual(GameMap(5), GameMap(6)) map_data1 = [[E, W, W], [E, 1, 2], [E, 3, E]] map_data2 = [[E, W, W], [E, 2, 3], [E, 1, E]] self.assertEqual(create_map_with(map_data1), create_map_with(map_data1)) self.assertNotEqual(create_map_with(map_data1), create_map_with(map_data2))
def get_game(map_size=10, max_nb_ticks=20, move_timeout: float = 2): game_map = GameMap(map_size) game_state = GameState(game_map) game = Game(game_state=game_state, max_nb_ticks=max_nb_ticks, move_timeout=move_timeout) return game
def create_state(self): game_map = GameMap(21) game_state = GameState(game_map) p0 = game_state.add_player("0") p0.stats.kill_player("p1") p0.stats.killed_by_player("p2") p0.stats.add_stat(PlayerStats.SUICIDES) p0.stats.add_stat(PlayerStats.BLITZIUMS) p0.stats.add_stat(PlayerStats.CONQUERED) p0.tail = [Position(1, 2), Position(2, 3), Position(4, 5)] p0.history.append( HistoryItem(11, "message-11", datetime.datetime(1900, 1, 1, 13, 14, 15, 555))) p0.history.append( HistoryItem(10, "message-10", datetime.datetime(1900, 1, 1, 13, 14, 15, 444))) p1 = game_state.add_player("1") p1.stats.kill_player("p1") p1.stats.killed_by_player("p2") p1.stats.add_stat(PlayerStats.SUICIDES) p1.stats.add_stat(PlayerStats.BLITZIUMS) p1.stats.add_stat(PlayerStats.CONQUERED) p1.tail = [Position(1, 2), Position(2, 3), Position(4, 5)] p1.history.append( HistoryItem(11, "message-11", datetime.datetime(1900, 1, 1, 13, 14, 15, 555))) p1.history.append( HistoryItem(10, "message-10", datetime.datetime(1900, 1, 1, 13, 14, 15, 444))) return game_state
def test_init_with_direction(self): game_map = GameMap(5) pos = Position(1, 1) ps = PlayerState(id=1, name="dummy", game_map=game_map, position=pos, direction=Direction(Direction.DOWN)) self.assertEqual(ps.direction, Direction(Direction.DOWN))
def test_record_tick(self): server = Mock() server.game.max_nb_ticks = 500 recorder = JsonRecorder(server.game, "/tmp/out.json") gs = GameState(GameMap(3)) nb = 10 for i in range(nb): recorder.record_tick(100 + i, gs) self.assertEqual(len(recorder.ticks), nb)
def test_init(self): game_map = GameMap(5) pos = Position(1, 1) ps = PlayerState(id=1, name="dummy", game_map=game_map, position=pos) self.assertFalse(ps.killed) self.assertEqual(ps.score, 0) self.assertEqual(ps.spawn_position, pos) self.assertEqual(ps.position, pos) self.assertEqual(ps.tail, [ps.spawn_position]) self.assertEqual(ps.direction, Direction.RIGHT) self.assertTrue(ps.game_map.is_conquered_by(pos, 1))
def test_send_tick_socket_closed(self): server = Mock() server.game.max_nb_ticks = 500 socket = AsyncMock() socket.send.side_effect = websockets.ConnectionClosed(0, "") viewer = SocketViewer(server, socket) viewer.logger = Mock() gs = GameState(GameMap(3)) asyncio.run(viewer.send_tick(123, gs)) viewer.logger.warning.assert_called_once() server.game.unregister_viewer.assert_called_once()
def test_send_winner_socket_closed(self): server = Mock() socket = AsyncMock() socket.send.side_effect = websockets.ConnectionClosed(0, "") viewer = SocketViewer(server, socket) viewer.logger = Mock() gs = GameState(GameMap(3)) ps = PlayerState(1, "p1", gs.game_map, Position(1, 1)) asyncio.run(viewer.send_winner(123, ps)) viewer.logger.warning.assert_called_once() server.game.unregister_viewer.assert_called_once()
def test_send_tick(self): server = Mock() server.game.max_nb_ticks = 500 socket = AsyncMock() viewer = SocketViewer(server, socket) gs = GameState(GameMap(3)) nb = 10 for i in range(nb): asyncio.run(viewer.send_tick(100 + i, gs)) self.assertEqual(nb, socket.send.call_count) data = json.loads(socket.send.call_args[0][0]) self.assertEqual(data["type"], "tick") self.assertEqual(data["game"]["tick"], 100 + nb - 1)
def test_send_winner(self): server = Mock() server.game.max_nb_ticks = 500 socket = AsyncMock() viewer = SocketViewer(server, socket) gs = GameState(GameMap(3)) ps = PlayerState(1, "p1", gs.game_map, Position(1, 1)) asyncio.run(viewer.send_winner(123, ps)) socket.send.assert_called_once() data = json.loads(socket.send.call_args[0][0]) self.assertEqual(data["type"], "winner") self.assertEqual(data["tick"], 123) self.assertEqual(data["winner"]["name"], "p1")
def test_get_random_empty_position(self): positions = set() map_size = 10 game_map = GameMap(map_size) for i in range(25): pos = game_map.get_random_empty_position() self.assertNotIn(pos, positions) self.assertTrue(game_map.is_empty(pos)) game_map.conquer_tile(pos, i) positions.add(pos)
def __init__(self, max_nb_ticks: int, game_config: GameConfig = None, game_delay: int = 0, move_timeout: int = 1): self.logger = logging.getLogger("AbstractServer") if game_config is not None: self.game_map: GameMap = game_config.game_map self.game_state: GameState = GameState(game_config) else: self.game_map = GameMap(25) self.game_state = GameState(self.game_map) self.game: Game = Game(self.game_state, max_nb_ticks=max_nb_ticks, delay=game_delay, move_timeout=move_timeout)
def test_add_history(self): game_map = GameMap(5) pos = Position(1, 1) ps = PlayerState(id=1, name="dummy", game_map=game_map, position=pos) for tick in range(10): # add 1 or 2 messages per tick for j in range(1 + tick % 2): ps.add_history(tick, f"message-{tick}-{j}") self.assertEqual(15, len(ps.history)) # adding one message will pop one oldest ps.add_history(11, "message-11") self.assertEqual(15, len(ps.history)) self.assertEqual("message-11", ps.history[0].message) self.assertEqual("message-1-1", ps.history[-2].message) self.assertEqual("message-1-0", ps.history[-1].message) # adding a second message will pop two oldests ps.add_history(12, "message-12") self.assertEqual(14, len(ps.history)) self.assertEqual("message-12", ps.history[0].message) self.assertEqual("message-2-0", ps.history[-1].message)
def from_str(cls, data: str) -> "GameConfig": lines = data.strip().split("\n") map_size = len(lines) game_map = GameMap(map_size) spawn_positions = [] spawn_directions = [] spawn_direction_markers = [] for y, line in enumerate(lines): line = line.strip() if len(line) != map_size: raise Exception(f"Map is not square! (line {y} as length {len(line)})") for x, tile in enumerate(line): pos = Position(x, y) if tile == GameMap.EMPTY: game_map.set_tile(pos, GameMap.EMPTY, None) elif tile == GameMap.ASTEROIDS: game_map.set_tile(pos, GameMap.ASTEROIDS, None) elif tile == GameMap.BLACK_HOLE: game_map.set_tile(pos, GameMap.BLACK_HOLE, None) elif tile == GameMap.BLITZIUM: game_map.set_tile(pos, GameMap.BLITZIUM, None) elif tile == GameMap.PLANET: game_map.set_tile(pos, GameMap.PLANET, None) elif tile == GameMap.DIRECTION: # Directions are meta information not visible on the map game_map.set_tile(pos, GameMap.EMPTY, None) spawn_direction_markers.append(pos) elif tile.isdigit(): player_id = int(tile) spawn_positions.append((player_id, pos)) else: raise Exception(f"Invalid tile '{tile}' as position {pos}.") spawn_positions.sort() if len(spawn_direction_markers) > 0: # for each player we find the closest direction marker # this algorithm won't work if a direction marker is # close to 2 spawn_positions for player_id, spawn_position in spawn_positions: for direction_marker in spawn_direction_markers: if spawn_position.is_next_to(direction_marker): direction = spawn_position.direction_to(direction_marker) spawn_directions.append(direction) return GameConfig(game_map, [p for i, p in spawn_positions], spawn_directions)
def get_player(server, socket): gs = GameState(GameMap(3)) player = SocketPlayer(server, "p1", socket) player.set_player_state(PlayerState(1, "p1", gs.game_map, Position(1, 1))) return gs, player
def is_closed_tail(cls, player: PlayerState, game_map: GameMap) -> bool: # check if adjacent to a conquered node if len(player.tail) >= 3: return game_map.is_conquered_by(player.tail[-1], player.id) return False
def dict_to_game_map(data: List[List[str]]) -> GameMap: map_size = len(data) game_map = GameMap(map_size) for y in range(1, map_size - 1): for x in range(1, map_size - 1): splitted = data[y][x].split("-") tile = splitted[0] owner = None if len(splitted) > 1: owner = int(splitted[1]) pos = Position(x, y) if tile == " ": game_map.set_tile(pos, GameMap.EMPTY, None) elif tile == "W": game_map.set_tile(pos, GameMap.ASTEROIDS, None) elif tile == "!": game_map.set_tile(pos, GameMap.BLACK_HOLE, None) elif tile == "$": game_map.set_tile(pos, GameMap.BLITZIUM, None) elif tile == "%": game_map.set_tile(pos, GameMap.PLANET, owner) elif tile == "C": game_map.set_tile(pos, GameMap.EMPTY, owner) return game_map
def setUp(self): self.map_size = 10 self.my_map = GameMap(self.map_size)
class TestMap(unittest.TestCase): def setUp(self): self.map_size = 10 self.my_map = GameMap(self.map_size) def test_init_with_empty_map(self): """ Test that a new map will be empty and the correct size """ self.assertEqual(self.my_map.size, self.map_size) self.assertEqual(len(self.my_map.tiles), self.my_map.size) [ self.assertEqual(len(self.my_map.tiles[y]), self.my_map.size) for y in range(self.my_map.size) ] # there is an asteroids around the map self.assertEqual(self.my_map.empty_tiles, (self.map_size - 2)**2) for y in range(self.map_size): for x in range(self.map_size): pos = Position(x=x, y=y) self.assertFalse(self.my_map.is_out_of_bound(pos)) if x == 0 or x == self.map_size - 1 or y == 0 or y == self.map_size - 1: # check asteroids self.assertFalse(self.my_map.is_empty(pos)) self.assertEqual(self.my_map.tiles[y][x], (GameMap.ASTEROIDS, None)) self.assertTrue(self.my_map.is_asteroids(pos)) self.assertEqual(self.my_map.get_tile(Position(x=x, y=y)), (GameMap.ASTEROIDS, None)) else: # must be empty self.assertTrue(self.my_map.is_empty(pos)) self.assertFalse(self.my_map.is_asteroids(pos)) self.assertEqual(self.my_map.get_tile(Position(x=x, y=y)), (GameMap.EMPTY, None)) def test_eq(self): self.assertEqual(GameMap(5), GameMap(5)) self.assertNotEqual(GameMap(5), GameMap(6)) map_data1 = [[E, W, W], [E, 1, 2], [E, 3, E]] map_data2 = [[E, W, W], [E, 2, 3], [E, 1, E]] self.assertEqual(create_map_with(map_data1), create_map_with(map_data1)) self.assertNotEqual(create_map_with(map_data1), create_map_with(map_data2)) def test_str(self): map = create_map_with([ # fmt: off [W, E, E], [E, 0, E], [E, E, 1] # fmt: on ]) map.set_tile(Position(2, 1), state=GameMap.PLANET, player_id=0) map.set_tile(Position(3, 1), state=GameMap.BLACK_HOLE) self.assertTrue(map.is_black_hole(Position(3, 1))) map.set_tile(Position(3, 2), state=GameMap.BLITZIUM) self.assertTrue(map.is_blitzium(Position(3, 2))) str_map = str(map) expected = "\n".join([ # fmt: off 'WWWWW', 'WW%!W', 'W 0$W', 'W 1W', 'WWWWW' # fmt: on ]) self.assertEqual(str_map, expected) def test_cannot_overwrite_asteroids(self): # Ok to write an asteroids on an asteroids self.my_map.set_tile(Position(x=0, y=0), state=GameMap.ASTEROIDS) # Invalid to overwrite an asteroids with something else with self.assertRaises(InvalidStateException): self.my_map.set_tile(Position(x=0, y=0), state=GameMap.EMPTY, player_id=0) with self.assertRaises(InvalidStateException): self.my_map.set_tile(Position(x=0, y=0), state=GameMap.EMPTY) def test_cannot_overwrite_planet(self): # Ok to write a planet on a planet (take ownership) pos = Position(x=1, y=1) self.my_map.set_tile(pos, state=GameMap.PLANET, player_id=None) self.my_map.set_tile(pos, state=GameMap.PLANET, player_id=1) self.my_map.set_tile(pos, state=GameMap.PLANET, player_id=2) self.my_map.set_tile(pos, state=GameMap.PLANET, player_id=None) self.my_map.set_tile(pos, state=GameMap.PLANET, player_id=3) # Invalid to overwrite a planet with something else with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.BLACK_HOLE) with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.ASTEROIDS) with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.BLITZIUM) with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.EMPTY) def test_invalid_set_title(self): pos = Position(x=1, y=1) # cannot have player id with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.ASTEROIDS, player_id=1) with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.BLITZIUM, player_id=1) with self.assertRaises(InvalidStateException): self.my_map.set_tile(pos, state=GameMap.BLACK_HOLE, player_id=1) def test_get_set_tile(self): """ Test that you can set a tile and get it back """ position = Position(x=2, y=1) old_is_empty = self.my_map.empty_tiles self.assertTrue(self.my_map.is_empty(position)) self.assertEqual(self.my_map.get_tile(position), GameMap.empty_tile) # conquer empty tile is the same as setting an owner on it self.my_map.set_tile(position, GameMap.EMPTY, 1) self.assertFalse(self.my_map.is_empty(position)) self.assertTrue(self.my_map.is_conquered_by(position, 1)) self.assertEqual(self.my_map.get_owner(position), 1) self.assertEqual(self.my_map.get_tile(position), (GameMap.EMPTY, 1)) self.assertEqual(self.my_map.empty_tiles, old_is_empty - 1) # clear tile remove owner self.my_map.clear_tile(position) self.assertTrue(self.my_map.is_empty(position)) self.assertEqual(self.my_map.get_tile(position)[0], GameMap.EMPTY) self.assertEqual(self.my_map.empty_tiles, old_is_empty) with self.assertRaises(OutOfBoundExeption): self.my_map.get_tile( Position(self.map_size + 10, self.map_size + 10)) with self.assertRaises(OutOfBoundExeption): self.my_map.set_tile( Position(self.map_size + 10, self.map_size + 10), GameMap.EMPTY, 1) def test_get_owner(self): """ Test that you can get the tile owner """ position = Position(1, 1) self.assertTrue(self.my_map.is_empty(position)) self.assertEqual(self.my_map.get_owner(position), None) self.my_map.conquer_tile(position, player_id=1) self.assertEqual(self.my_map.get_owner(position), 1) self.my_map.conquer_tile(position, player_id=0) self.assertEqual(self.my_map.get_owner(position), 0) self.my_map.set_tile(position, GameMap.PLANET, player_id=None) self.assertEqual(self.my_map.get_owner(position), None) self.my_map.conquer_tile(position, player_id=0) self.assertEqual(self.my_map.get_owner(position), 0) with self.assertRaises(OutOfBoundExeption): self.my_map.get_owner( Position(self.map_size + 10, self.map_size + 10)) def test_is_conquered_by(self): """ Test that you can identify tiles owned by you """ position = Position(1, 1) self.assertTrue(self.my_map.is_empty(position)) self.assertFalse(self.my_map.is_conquered_by(position, player_id=1)) self.my_map.conquer_tile(position, player_id=1) self.assertTrue(self.my_map.is_conquered_by(position, player_id=1)) self.assertFalse(self.my_map.is_conquered_by(position, player_id=0)) self.my_map.set_tile(position, GameMap.PLANET, player_id=None) self.my_map.conquer_tile(position, player_id=1) self.assertTrue(self.my_map.is_conquered_by(position, player_id=1)) self.assertEqual(self.my_map.get_tile(position), (GameMap.PLANET, 1)) with self.assertRaises(OutOfBoundExeption): self.my_map.is_conquered_by(Position(self.map_size + 10, self.map_size + 10), player_id=0) def test_is_out_of_bound(self): """ Test that a position is out of bound for the current map """ self.assertTrue( self.my_map.is_out_of_bound(Position(-self.map_size, 5))) self.assertTrue(self.my_map.is_out_of_bound(Position(self.map_size, 5))) self.assertTrue( self.my_map.is_out_of_bound(Position(5, -self.map_size))) self.assertTrue(self.my_map.is_out_of_bound(Position(5, self.map_size))) self.assertTrue( self.my_map.is_out_of_bound(Position(self.map_size, self.map_size))) self.assertTrue( self.my_map.is_out_of_bound( Position(-self.map_size, -self.map_size))) self.assertFalse(self.my_map.is_out_of_bound(Position(0, 0))) self.assertFalse(self.my_map.is_out_of_bound(Position(5, 5))) self.assertFalse( self.my_map.is_out_of_bound( Position(self.map_size - 1, self.map_size - 1))) def test_clear_tile_owned_by(self): """ Tests that test_clear_tile_owned_by only clear tiles owned by the right player """ self.my_map.set_tile(Position(5, 5), GameMap.PLANET, player_id=None) self.my_map.conquer_tile(Position(5, 5), player_id=1) self.my_map.conquer_tile(Position(5, 6), player_id=1) self.my_map.conquer_tile(Position(5, 7), player_id=1) self.my_map.conquer_tile(Position(1, 5), player_id=2) self.assertEqual(self.my_map.count_tiles_owned_by(player_id=1), 3) self.my_map.clear_tile_owned_by(player_id=1) self.assertEqual(self.my_map.count_tiles_owned_by(player_id=1), 0) self.assertFalse(self.my_map.is_empty(Position(5, 5))) self.assertEqual(self.my_map.get_tile(Position(5, 5)), (GameMap.PLANET, None)) self.assertTrue(self.my_map.is_empty(Position(7, 5))) self.assertEqual(self.my_map.get_tile(Position(1, 5)), (GameMap.EMPTY, 2)) self.assertEqual(self.my_map.get_owner(Position(1, 5)), 2) def test_find_path_empty_tiles(self): map = create_map_with([ # fmt: off [1, E, E, E], [W, W, E, E], [W, E, E, W], [2, E, W, E] # fmt: on ]) found, path = map.find_path(start=Position(1, 1), goal=Position(4, 1)) self.assertTrue(found) self.assertEqual(len(path), 4) self.assertEqual( path, [Position(1, 1), Position(2, 1), Position(3, 1), Position(4, 1)]) found, path = map.find_path(start=Position(1, 1), goal=Position(1, 4)) self.assertTrue(found) self.assertEqual(len(path), 8) found, path = map.find_path(start=Position(1, 1), goal=Position(4, 4)) self.assertFalse(found) def test_find_path_conquered_tiles(self): map = create_map_with([ # fmt: off [1, 1, E, 1], [E, 1, E, 2], [E, 1, E, 1], [E, 1, 1, E] # fmt: on ]) found, path = map.find_path(start=Position(1, 1), goal=Position(3, 4), player_id=1) self.assertTrue(found) self.assertEqual(len(path), 6) self.assertEqual(path, [ Position(1, 1), Position(2, 1), Position(2, 2), Position(2, 3), Position(2, 4), Position(3, 4) ]) found, path = map.find_path(start=Position(1, 1), goal=Position(4, 1), player_id=1) self.assertFalse(found) found, path = map.find_path(start=Position(4, 1), goal=Position(4, 3), player_id=1) self.assertFalse(found) with self.assertRaises(Exception): map.find_path(start=Position(4, 1), goal=Position(4, 2), player_id=1) with self.assertRaises(Exception): map.find_path(start=Position(3, 1), goal=Position(4, 1), player_id=1) def test_get_random_empty_position(self): positions = set() map_size = 10 game_map = GameMap(map_size) for i in range(25): pos = game_map.get_random_empty_position() self.assertNotIn(pos, positions) self.assertTrue(game_map.is_empty(pos)) game_map.conquer_tile(pos, i) positions.add(pos) def test_get_empty_tiles(self): map = GameMap(4) self.assertEqual( map.get_empty_tiles(), [Position(1, 1), Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 1), GameMap.PLANET) self.assertEqual( map.get_empty_tiles(), [Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 1), GameMap.PLANET, 1) self.assertEqual( map.get_empty_tiles(), [Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 2), GameMap.ASTEROIDS) self.assertEqual(map.get_empty_tiles(), [Position(2, 1), Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.BLITZIUM) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.BLACK_HOLE) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.EMPTY, 1) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)])
def test_get_empty_tiles(self): map = GameMap(4) self.assertEqual( map.get_empty_tiles(), [Position(1, 1), Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 1), GameMap.PLANET) self.assertEqual( map.get_empty_tiles(), [Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 1), GameMap.PLANET, 1) self.assertEqual( map.get_empty_tiles(), [Position(1, 2), Position(2, 1), Position(2, 2)]) map.set_tile(Position(1, 2), GameMap.ASTEROIDS) self.assertEqual(map.get_empty_tiles(), [Position(2, 1), Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.BLITZIUM) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.BLACK_HOLE) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)]) map.set_tile(Position(2, 1), GameMap.EMPTY, 1) self.assertEqual(map.get_empty_tiles(), [Position(2, 2)])
def create_map_with(map_data: List[List[int]]) -> GameMap: data_size = len(map_data) assert data_size == len(map_data[0]) game_map = GameMap(data_size + 2) for y in range(data_size): for x in range(data_size): pos = Position(x + 1, y + 1) if map_data[y][x] == W: game_map.set_tile(pos, GameMap.ASTEROIDS, player_id=None) elif map_data[y][x] == E: game_map.set_tile(pos, GameMap.EMPTY, player_id=None) elif map_data[y][x] == P: game_map.set_tile(pos, GameMap.PLANET, player_id=None) elif map_data[y][x] == P1: game_map.set_tile(pos, GameMap.PLANET, player_id=1) else: game_map.conquer_tile(pos, player_id=map_data[y][x]) return game_map
def test_dict_to_player_state(self): data = state_test["players"][0] gm = GameMap(20) ps = dict_to_player_state(data, gm) dict = player_state_to_dict(ps) self.assertEqual(data, dict)