def test_surround_player_with_conquers(self): # fmt: off gm = create_map_with([ [1, 1, 1, E, E], [1, E, 1, E, E], [E, E, E, E, E], [E, E, E, 2, 2], [E, E, E, 2, 2], ]) # fmt: on p1 = PlayerState(id=1, name="p1", game_map=gm, position=Position(1, 3), direction=Direction(Direction.RIGHT)) p2 = PlayerState(id=2, name="p2", game_map=gm, position=Position(4, 4), direction=Direction(Direction.LEFT)) gs = GameState(gm, [p1, p2]) gs.apply_action(0, p2, Action.FORWARD) gs.apply_action(0, p2, Action.FORWARD) gs.apply_action(0, p2, Action.TURN_RIGHT) gs.apply_action(0, p2, Action.FORWARD) self.assertEqual(Position(2, 2), p2.position) self.assertEqual(5, len(p2.tail)) gs.apply_action(0, p1, Action.FORWARD) # walk on tail, p2 killed self.assertTrue(p2.killed) self.assertFalse(p1.killed) self.assertEqual(0, p2.stats.stats[PlayerStats.CONQUERED])
def test_fill_planet_to_planet_2(self): # fmt: off game_map = create_map_with([[E, E, E, P1, 1], [E, E, E, 1, P1], [E, E, E, E, E], [E, E, E, E, E], [E, E, E, E, E]]) # fmt: on ps = PlayerState(id=1, name="dummy", game_map=game_map, position=Position(4, 1)) gs = GameState(game_map, [ps]) ps.tail = [ Position(4, 1), Position(3, 1), Position(2, 1), Position(2, 2), Position(2, 3), Position(2, 4), Position(3, 4), Position(4, 4), Position(5, 4), Position(5, 3), Position(5, 2), ] self.assertEqual(len(gs.fill(ps)), 12) # fmt: off self.assertEqual( game_map, create_map_with([[E, 1, 1, P1, 1], [E, 1, 1, 1, P1], [E, 1, 1, 1, 1], [E, 1, 1, 1, 1], [E, E, E, E, E]])) # fmt: on self.assertEqual(ps.score, 12)
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_fill_island(self): # fmt: off game_map = create_map_with([[1, 1, E, 1], [1, 1, E, 1], [E, E, E, E], [E, E, E, E]]) # fmt: on ps = PlayerState(id=1, name="dummy", game_map=game_map, position=Position(2, 2)) gs = GameState(game_map, [ps]) ps.tail = [ ps.spawn_position, Position(2, 3), Position(3, 3), Position(4, 3), Position(4, 2) ] self.assertEqual(len(gs.fill(ps)), 3) # fmt: off self.assertEqual( game_map, create_map_with([[1, 1, E, 1], [1, 1, E, 1], [E, 1, 1, 1], [E, E, E, E]])) # fmt: on self.assertEqual(ps.score, 3)
def test_is_closed_tail(self): # fmt: off gm = create_map_with([[1, E, 1], [E, E, E], [1, E, E]]) # fmt: on # player without tail player = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(player.tail, [Position(1, 1)]) self.assertFalse(GameState.is_closed_tail(player, gm)) # player with tail player.tail = [Position(1, 1), Position(2, 1)] self.assertFalse(GameState.is_closed_tail(player, gm)) player.tail = [Position(1, 1), Position(2, 1), Position(3, 1)] player.direction = Direction(Direction.UP) self.assertTrue(GameState.is_closed_tail(player, gm)) player.tail = [Position(1, 1), Position(2, 1), Position(2, 2)] self.assertFalse(GameState.is_closed_tail(player, gm)) player.tail = [ Position(1, 1), Position(2, 1), Position(2, 2), Position(1, 2), Position(1, 1) ] self.assertTrue(GameState.is_closed_tail(player, gm))
def test_add_player_should_respect_orientation(self): gc = GameConfig(GameMap(20), spawn_positions=[Position(1, 1)], spawn_directions=[Direction(Direction.LEFT)]) gs = GameState(gc, players=None) self.assertEqual(len(gs.players), 0) gs.add_player("Karl Marx") self.assertEqual(Direction(Direction.LEFT), gs.players[0].direction)
def test_add_player(self): gs = GameState(GameMap(20), players=None) self.assertEqual(len(gs.players), 0) nb_players = 10 for i in range(nb_players): gs.add_player(str(i)) self.assertEqual(len(gs.players), nb_players) # no two players at the same place self.assertEqual(nb_players, len(set([p.spawn_position for p in gs.players])))
def test_relocate_item_map_full(self): # fmt: off gm = create_map_with([[E, W], [W, W]]) # fmt: on gs = GameState(gm, []) black_hole_pos = Position(1, 1) gm.set_tile(black_hole_pos, GameMap.BLACK_HOLE) self.assertTrue(gm.is_black_hole(black_hole_pos)) new_black_hole_pos = gs.relocate_item(black_hole_pos) self.assertEqual(None, new_black_hole_pos)
def test_walk_on_tail_suicide(self): gm = GameMap(5) p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(p1.direction, Direction.RIGHT) gs = GameState(gm, players=[p1]) # loop around gs.apply_action(1, p1, Action.FORWARD) gs.apply_action(2, p1, Action.FORWARD) gs.apply_action(3, p1, Action.TURN_RIGHT) gs.apply_action(4, p1, Action.TURN_RIGHT) self.assertEqual(p1.position, Position(2, 2)) self.assertEqual(p1.tail, [ p1.spawn_position, Position(2, 1), Position(3, 1), Position(3, 2), Position(2, 2) ]) self.assertFalse(p1.killed) # walk on tail = suicide gs.apply_action(5, p1, Action.TURN_RIGHT) self.assertTrue(p1.killed) self.assertEqual(len(p1.tail), 1) self.assertEqual(1, p1.stats.stats[PlayerStats.SUICIDES])
def test_kill_player(self): # fmt: off gm = create_map_with([[E, E, E], [E, E, E], [1, 1, 1]]) # fmt: on p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) gs = GameState(gm, [p1]) p1.tail = [Position(1, 1), Position(1, 2)] p1.position = p1.tail[-1] gs.kill_player(p1) self.assertEqual(p1.tail, [p1.spawn_position]) self.assertEqual(p1.position, p1.spawn_position) self.assertTrue(p1.killed) self.assertEqual(0, p1.stats.stats[PlayerStats.CONQUERED])
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 test_walk_on_blitzium(self): gm = GameMap(5) p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(p1.direction, Direction.RIGHT) gs = GameState(gm, players=[p1]) gm.set_tile(Position(2, 1), GameMap.BLITZIUM) gs.apply_action(1, p1, Action.FORWARD) self.assertFalse(p1.killed) self.assertEqual(p1.position, Position(2, 1)) self.assertEqual(len(p1.tail), 2) self.assertEqual(1, p1.stats.stats[PlayerStats.BLITZIUMS]) self.assertFalse(gm.is_blitzium(Position(2, 1))) if not GameState.relocate_blitzium: for y in range(gm.size): for x in range(gm.size): self.assertFalse(gm.is_blitzium(Position(x, y)))
def test_walk_on_asteroids_suicide(self): gm = GameMap(5) p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(p1.direction, Direction.RIGHT) gs = GameState(gm, players=[p1]) # validate that a turn left should walk on asteroids pos = p1.position.copy().move( Direction(Direction.RIGHT).change_direction(Action.TURN_LEFT)) self.assertEqual(pos, Position(1, 0)) self.assertTrue(gm.is_asteroids(pos)) gs.apply_action(1, p1, Action.TURN_LEFT) # walk on tail = suicide, respawn self.assertEqual(p1.position, Position(1, 1)) self.assertEqual(len(p1.tail), 1) self.assertTrue(p1.killed) self.assertEqual(1, p1.stats.stats[PlayerStats.SUICIDES])
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_conquer(self): gm = GameMap(5) gm.conquer_tile(Position(2, 1), 1) p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(p1.tail, [p1.spawn_position]) self.assertTrue(gm.is_conquered_by(Position(1, 1), player_id=1)) self.assertEqual(p1.direction, Direction.RIGHT) p1.stats.set_stat(PlayerStats.CONQUERED, gm.count_tiles_owned_by(player_id=1)) gs = GameState(gm, players=[p1]) # loop around gs.apply_action(1, p1, Action.FORWARD) self.assertEqual(p1.tail, [Position(2, 1)]) gs.apply_action(2, p1, Action.TURN_RIGHT) self.assertEqual(p1.position, Position(2, 2)) self.assertEqual(p1.tail, [Position(2, 1), Position(2, 2)]) self.assertEqual(gm.count_tiles_owned_by(player_id=1), 2) self.assertEqual(2, p1.stats.stats[PlayerStats.CONQUERED]) # walk into a conquered tile gs.apply_action(4, p1, Action.TURN_RIGHT) self.assertEqual(p1.position, Position(1, 2)) self.assertEqual( p1.tail, [Position(2, 1), Position(2, 2), Position(1, 2)]) gs.apply_action(1, p1, Action.TURN_RIGHT) self.assertEqual(p1.position, Position(1, 1)) self.assertEqual(p1.tail, [Position(1, 1)]) self.assertFalse(p1.killed) self.assertEqual(gm.count_tiles_owned_by(player_id=1), 4) self.assertEqual(4, p1.stats.stats[PlayerStats.CONQUERED]) for p in [ Position(1, 1), Position(2, 1), Position(2, 2), Position(1, 2) ]: self.assertTrue(gm.is_conquered_by(p, player_id=1))
def test_respawn_player(self): gs = GameState(GameMap(5)) player = gs.add_player("1") gs.move_player(player, Action.FORWARD) self.assertNotEqual(player.position, player.spawn_position) player.killed = True gs.respawn_player(player) self.assertEqual(player.position, player.spawn_position) self.assertFalse(player.killed)
def test_move_player(self): gm = GameMap(5) player = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) player.direction = Direction(Direction.RIGHT) gs = GameState(gm, [player]) gs.move_player(player, Action.FORWARD) gs.move_player(player, Action.TURN_RIGHT) gs.move_player(player, Action.TURN_RIGHT) gs.move_player(player, Action.TURN_LEFT) self.assertEqual(Position(1, 3), player.position)
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_fill_with_asteroids(self): # fmt: off game_map = create_map_with([[E, E, E, E, E], [E, 1, E, 1, E], [E, 1, W, 1, E], [E, 1, 1, 1, E], [E, E, E, E, E]]) # fmt: on ps = PlayerState(id=1, name="dummy", game_map=game_map, position=Position(2, 2)) ps.tail = [ps.spawn_position, Position(3, 2), Position(4, 2)] gs = GameState(game_map, [ps]) self.assertEqual(len(gs.fill(ps)), 1) # fmt: off self.assertEqual( game_map, create_map_with([[E, E, E, E, E], [E, 1, 1, 1, E], [E, 1, W, 1, E], [E, 1, 1, 1, E], [E, E, E, E, E]])) # fmt: on self.assertEqual(ps.score, 1)
def test_walk_on_tail_kill(self): # player 1 has some conquered tiles n the map # fmt: off gm = create_map_with([[E, E, E], [E, E, E], [1, 1, 1]]) # fmt: on p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) p2 = PlayerState(id=2, name="2", game_map=gm, position=Position(3, 2)) gs = GameState(gm, players=[p1, p2]) self.assertEqual(gm.count_tiles_owned_by(player_id=1), 4) self.assertEqual(gm.count_tiles_owned_by(player_id=2), 1) self.assertEqual(p1.direction, Direction.RIGHT) self.assertEqual(p2.direction, Direction.LEFT) # create some tail gs.apply_action(1, p1, Action.FORWARD) gs.apply_action(2, p1, Action.FORWARD) # p2 walk on p1 tail and kill it gs.apply_action(3, p2, Action.TURN_RIGHT) self.assertEqual(p2.position, Position(3, 1)) self.assertTrue(p1.killed) self.assertEqual(gm.count_tiles_owned_by(player_id=1), 1) self.assertEqual(gm.count_tiles_owned_by(player_id=2), 1) self.assertEqual(1, p1.stats.stats[PlayerStats.KILLED]) self.assertEqual(p2.name, p1.stats.stats[PlayerStats.NEMESIS]) self.assertEqual(1, p2.stats.stats[PlayerStats.KILLS])
def test_fill_kill_other_player_tail(self): # fmt: off game_map = create_map_with([[E, E, E, E], [E, E, E, E], [0, 0, 0, 0], [E, 1, E, E]]) # fmt: on p0 = PlayerState(id=0, name="dummy", game_map=game_map, position=Position(1, 3)) p1 = PlayerState(id=1, name="dummy", game_map=game_map, position=Position(2, 4)) gs = GameState(game_map, [p0, p1]) p0.tail = [ p0.spawn_position.copy(), Position(1, 2), Position(1, 1), Position(2, 1), Position(3, 1), Position(4, 1), Position(4, 2), ] p0.position = p0.tail[-1].copy() p0.direction = Direction(Direction.DOWN) p1.tail = [ p1.spawn_position.copy(), Position(2, 3), Position(2, 2), Position(3, 2), Position(3, 3), Position(3, 4), ] p1.position = p1.tail[-1].copy() p1.direction = Direction(Direction.DOWN) # print(game_state_to_dict(0, 0, gs, 999)['game']['pretty_map']) gs.apply_action(0, p0, Action.FORWARD) # print(game_state_to_dict(0, 0, gs, 999)['game']['pretty_map']) self.assertTrue(p1.killed)
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_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_conquer_some_player_tile(self): # fmt: off gm = create_map_with([ [1, 1, E], [1, 2, 2], [E, 2, 2], ]) # fmt: on p1 = PlayerState(id=1, name="p1", game_map=gm, position=Position(1, 1)) p2 = PlayerState(id=2, name="p2", game_map=gm, position=Position(2, 2)) gs = GameState(gm, [p1, p2]) p1.position = Position(2, 2) p1.tail = [Position(1, 2), Position(2, 2)] p2.position = Position(2, 3) p2.tail = [Position(2, 3)] p1.direction = Direction(Direction.RIGHT) gs.apply_action(0, p1, Action.TURN_LEFT) self.assertFalse(p2.killed) self.assertFalse(p1.killed)
def test_walk_on_black_hole_suicide(self): gm = GameMap(5) p1 = PlayerState(id=1, name="1", game_map=gm, position=Position(1, 1)) self.assertEqual(p1.direction, Direction.RIGHT) gs = GameState(gm, players=[p1]) gm.set_tile(Position(2, 1), GameMap.BLACK_HOLE) gs.apply_action(1, p1, Action.FORWARD) self.assertTrue(p1.killed) self.assertEqual(p1.position, Position(1, 1)) self.assertEqual(len(p1.tail), 1) self.assertEqual(1, p1.stats.stats[PlayerStats.SUICIDES]) if GameState.relocate_black_hole: self.assertFalse(gm.is_black_hole(Position(2, 1))) black_hole_at = None for y in range(gm.size): for x in range(gm.size): pos = Position(x, y) if gm.is_black_hole(pos): black_hole_at = pos self.assertTrue(black_hole_at is not None) else: self.assertTrue(gm.is_black_hole(Position(2, 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_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_relocate_item(self): # fmt: off gm = create_map_with([[1, E, E], [E, W, E], [E, E, E]]) # fmt: on ps = PlayerState(id=1, name="dummy", game_map=gm, position=Position(1, 1)) gs = GameState(gm, [ps]) ps.position = Position(3, 1) ps.tail = [Position(2, 1), Position(3, 1)] asteroids_pos = Position(2, 2) self.assertTrue(gm.is_asteroids(asteroids_pos)) planet_pos = Position(3, 3) gm.set_tile(planet_pos, GameMap.PLANET) self.assertTrue(gm.is_planet(planet_pos)) black_hole_pos = Position(1, 2) gm.set_tile(black_hole_pos, GameMap.BLACK_HOLE) self.assertTrue(gm.is_black_hole(black_hole_pos)) blitzium_pos = Position(1, 3) gm.set_tile(blitzium_pos, GameMap.BLITZIUM) self.assertTrue(gm.is_blitzium(blitzium_pos)) # Cannot relocate asteroids and planets with self.assertRaises(Exception): gs.relocate_item(asteroids_pos) with self.assertRaises(Exception): gs.relocate_item(planet_pos) # relocate black holes and blitziums for i in range(30): new_black_hole_pos = gs.relocate_item(black_hole_pos) self.assertTrue(new_black_hole_pos not in list( {asteroids_pos, planet_pos, black_hole_pos, blitzium_pos}) + ps.tail) black_hole_pos = new_black_hole_pos new_blitzium_pos = gs.relocate_item(blitzium_pos) self.assertTrue(new_blitzium_pos != blitzium_pos)
def test_add_player_with_game_config(self): game_config = GameConfig.from_str("WWWW\nW 2W\nW 1W\nWWWW") gs = GameState(game_config) self.assertEqual(len(gs.players), 0) ps0 = gs.add_player("0") self.assertEqual(Position(2, 2), ps0.spawn_position) ps1 = gs.add_player("1") self.assertEqual(Position(2, 1), ps1.spawn_position) with self.assertRaises(Exception): gs.add_player("2")
def test_game_state_to_json_viewer(self): gm = create_map_with([[E]]) gs = GameState(gm) self.maxDiff = 999999 expected = { "type": "tick", "game": { "map": [["W", "W", "W"], ["W", " ", "W"], ["W", "W", "W"]], "player_id": None, # fmt: off "pretty_map": '[[W W W ]\n' ' [W W ]\n' ' [W W W ]]\n' 'DISCLAMER: this map does not have the same content as ' 'the json game map. Symbols are combined to help you ' 'visualize every spot on this turn. Hyphen are also ' 'removed. See the documentation for the json map ' 'symbol signification.\n' 'Symbols added or modified on this map for ' 'visualization purpose are:\n' 'Px: Position of player x - Cx: Conquered by player x ' '- Tx: Tail of player x', # fmt: on "tick": 123, "ticks_left": 500, }, "players": [], } # viewers do not have player id message = game_state_to_json(game_tick=123, player_id=None, game_state=gs, ticks_left=500) data = json.loads(message) self.assertEqual(data, expected)