def test_setup_game_bad_number_of_bots(bots_hidden): """ setup_game should fail when a wrong number of bots is given. """ test_layout = """ ################## #0#. . # . # #2##### #####3# # . # . .#1# ################## """ # remove bot x when bots_hidden[x] is True for x in range(4): if bots_hidden[x]: test_layout = test_layout.replace(str(x), ' ') parsed_layout = layout.parse_layout(test_layout) # dummy player stopping = lambda bot, s: (bot.position, s) if list(bots_hidden) == [False] * 4: # no bots are hidden. it should succeed setup_game([stopping, stopping], layout_dict=parsed_layout, max_rounds=10) else: with pytest.raises(ValueError): setup_game([stopping, stopping], layout_dict=parsed_layout, max_rounds=10)
def test_multiple_enemies_killing(): """ Check that you can kill multiple enemies at once. """ l0 = """ ######## # .. # # 210 # ######## ######## # .. # # 3 # ######## """ l1 = """ ######## # .. # # 103 # ######## ######## # .. # # 2 # ######## """ # dummy bots stopping = lambda bot, s: (bot.position, s) parsed_l0 = layout.parse_layout(l0) for bot in (0, 2): game_state = setup_game([stopping, stopping], layout_dict=parsed_l0) game_state['turn'] = bot # get position of bots 1 (and 3) kill_position = game_state['bots'][1] assert kill_position == game_state['bots'][3] new_state = apply_move(game_state, kill_position) # team 0 scores twice assert new_state['score'] == [10, 0] # bots 1 and 3 are back to origin assert new_state['bots'][1::2] == [(6, 2), (6, 1)] parsed_l1 = layout.parse_layout(l1) for bot in (1, 3): game_state = setup_game([stopping, stopping], layout_dict=parsed_l1) game_state['turn'] = bot # get position of bots 0 (and 2) kill_position = game_state['bots'][0] assert kill_position == game_state['bots'][2] new_state = apply_move(game_state, kill_position) # team 1 scores twice assert new_state['score'] == [0, 10] # bots 0 and 2 are back to origin assert new_state['bots'][0::2] == [(1, 1), (1, 2)]
def test_too_few_registered_teams(self): test_layout_4 = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) team_1 = stopping_player with pytest.raises(ValueError): setup_game([team_1], layout_dict=parse_layout(test_layout_4), max_rounds=300)
def test_too_many_registered_teams(self): test_layout_4 = ( """ ################## #a#. . # . # #b##### #####x# # . # . .#y# ################## """) team_1 = stopping_player with pytest.raises(ValueError): setup_game([team_1] * 3, layout_dict=parse_layout(test_layout_4), max_rounds=300)
def test_requested_moves(move_request, expected_prev, expected_req, expected_success): # test the possible return values of gamestate['requested_moves'] test_layout = """ ###### #a#.y# #.bx # ###### """ def move(bot, state): return move_request teams = [move, stopping_player] state = setup_game(teams, layout_dict=layout.parse_layout(test_layout), max_rounds=2) assert state['requested_moves'] == [None, None, None, None] state = play_turn(state) assert state['requested_moves'][1:] == [None, None, None] assert state['requested_moves'][0] == { 'previous_position': (1, 1), 'requested_position': expected_req, 'success': expected_success }
def test_shorthand(self): test_layout = (""" ############ #a . . y# #b x# ############ """) num_rounds = 5 teams = [ stepping_player('>v<^-', '-----'), stepping_player('<^>v-', '-----') ] state = setup_game(teams, layout_dict=parse_layout(test_layout), max_rounds=5) player0_expected_positions = [(1, 1), (2, 1), (2, 2), (1, 2), (1, 1), (1, 1)] player1_expected_positions = [(10, 2), (9, 2), (9, 1), (10, 1), (10, 2), (10, 2)] assert state['bots'][0] == player0_expected_positions[0] assert state['bots'][1] == player1_expected_positions[0] for i in range(1, num_rounds + 1): for step in range(4): state = play_turn(state) assert state['bots'][0] == player0_expected_positions[i] assert state['bots'][1] == player1_expected_positions[i]
def test_suicide_win(): # Test how a bot eats a food pellet that the enemy sits on # Since it is the last pellet, the game will end directly test_layout = """ ###### #a .x# #. # #b y# ###### """ teams = [stepping_player('>>', '--'), stepping_player('<-', '--')] state = setup_game(teams, layout_dict=layout.parse_layout(test_layout), max_rounds=2) assert state['bots'] == [(1, 1), (4, 1), (1, 3), (4, 3)] assert state['food'] == [{(1, 2)}, {(3, 1)}] # play until finished state = run_game(teams, layout_dict=layout.parse_layout(test_layout), max_rounds=2) # bot 0 has been reset assert state['bots'] == [(1, 2), (3, 1), (1, 3), (4, 3)] assert state['food'] == [{(1, 2)}, set()] assert state['gameover'] == True assert state['whowins'] == 1 assert state['round'] == 2 assert state['turn'] == 0 assert state['score'] == [1, game.KILL_POINTS]
def test_double_suicide(): # Test how a bot can be killed when it runs into two bots test_layout = """ ###### # bx # #. y.# ###### """ teams = [stepping_player('-', '-'), stepping_player('<', '-')] state = setup_game(teams, layout_dict=layout.parse_layout(test_layout, bots={'a': (2, 1)}), max_rounds=2) assert state['bots'] == [(2, 1), (3, 1), (2, 1), (3, 2)] assert state['food'] == [{(1, 2)}, {(4, 2)}] # play a two turns so that 1 moves state = play_turn(state) state = play_turn(state) # bot 1 has been reset assert state['bots'] == [(2, 1), (4, 2), (2, 1), (3, 2)] assert state['food'] == [{(1, 2)}, {(4, 2)}] assert state['gameover'] == False assert state['round'] == 1 assert state['turn'] == 1 # only a single KILL_POINT has been given assert state['score'] == [game.KILL_POINTS, 0]
def test_round_based_players(self): test_layout = (""" ############ #a . . x# #b y# ############ """) # index 0 can be ignored movements_0 = [None, east, east] movements_1_0 = {1: west, 3: west} movements_1_1 = {3: west} teams = [ round_based_player(movements_0, movements_0), round_based_player(movements_1_0, movements_1_1) ] state = setup_game(teams, layout_dict=parse_layout(test_layout), max_rounds=3) assert state['bots'][0] == (1, 1) assert state['bots'][1] == (10, 1) assert state['bots'][2] == (1, 2) assert state['bots'][3] == (10, 2) state = run_game(teams, layout_dict=parse_layout(test_layout), max_rounds=3) assert state['bots'][0] == (3, 1) assert state['bots'][1] == (8, 1) assert state['bots'][2] == (3, 2) assert state['bots'][3] == (9, 2)
def test_cascade_kill_2(): """ Checks that killing occurs only for the bot whose turn it is or for any bot that this bot moves onto. If a bot respawns on an enemy, it will only be killed when it is its own or the enemy’s turn (and neither of them moves). """ cascade = [ (""" ######## #ya.. b# #x # ######## """, {}), (""" ######## #a .. b# #x # ######## """, { 'y': (6, 1) }), (""" ######## #a .. y# #x # ######## """, { 'b': (1, 2) }), (""" ######## #a .. y# #b x# ######## """, {}), ] def move(bot, state): if bot.is_blue and bot.turn == 0 and bot.round == 1: return (1, 1) return bot.position layouts = [layout.parse_layout(l, bots=b) for l, b in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layouts[0]) assert state['bots'] == layouts[0]['bots'] state = game.play_turn( state) # Bot 0 moves, kills 3. Bot 2 and 3 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn(state) # Bot 1 stands. Bot 2 and 3 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn( state) # Bot 2 stands, gets killed. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 3 stands. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 0 stands. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 1 stands, kills 2. assert state['bots'] == layouts[3]['bots']
def test_suicide(): """ Check that suicide works. """ l0 = """ ######## # .. # #ybxa # ######## """ l1 = """ ######## # .. # # xayb# ######## """ # dummy bots stopping = lambda bot, s: (bot.position, s) parsed_l0 = layout.parse_layout(l0) for bot in (1, 3): game_state = setup_game([stopping, stopping], layout_dict=parsed_l0) game_state['turn'] = bot # get position of bot 2 suicide_position = game_state['bots'][2] new_state = apply_move(game_state, suicide_position) # team 0 scores assert new_state['score'] == [5, 0] # # bots 1 and 3 are back to origin if bot == 1: assert new_state['bots'][1::2] == [(6, 2), (1, 2)] elif bot == 3: assert new_state['bots'][1::2] == [(3, 2), (6, 1)] parsed_l1 = layout.parse_layout(l1) for bot in (0, 2): game_state = setup_game([stopping, stopping], layout_dict=parsed_l1) game_state['turn'] = bot # get position of bot 3 suicide_position = game_state['bots'][3] new_state = apply_move(game_state, suicide_position) # team 0 scores assert new_state['score'] == [0, 5]
def test_cascade_kill(): cascade = [ """ ######## #1 ..30# # 2# ######## """, """ ######## #0 .. 3# # 2# ######## ######## #1 .. # # # ######## """, """ ######## #0 .. 3# # 1# ######## ######## # .. # # 2# ######## """, """ ######## #0 .. 3# #2 1# ######## """ ] def move(bot, state): if not bot.is_blue and bot.turn == 1 and bot.round == 1: return (6, 1), state return bot.position, state layouts = [layout.parse_layout(l) for l in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layout.parse_layout(cascade[0])) assert state['bots'] == layouts[0]['bots'] state = game.play_turn(state) # Bot 0 stands assert state['bots'] == layouts[0]['bots'] state = game.play_turn(state) # Bot 1 stands state = game.play_turn(state) # Bot 2 stands state = game.play_turn( state) # Bot 3 moves, kills 0. Bot 0 and 1 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn( state) # Bot 0 stands, kills 1. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 1 stands, kills 2. assert state['bots'] == layouts[3]['bots']
def test_invalid_setup_game_closes_players(): layout_name, layout_string = layout.get_random_layout() l = layout.parse_layout(layout_string) # setup a remote demo game with "0" and "1" but bad max rounds state = setup_game(["0", "1"], layout_dict=l, max_rounds=0, allow_exceptions=True) assert state["gameover"] # Check that both processes have exited assert state["teams"][0].proc[0].wait(timeout=3) == 0 assert state["teams"][1].proc[0].wait(timeout=3) == 0
def test_cascade_suicide(): cascade = [ """ ######## #1 ..03# # 2# ######## """, """ ######## #0 .. 3# # 2# ######## ######## #1 .. # # # ######## """, """ ######## #0 .. 3# # 1# ######## ######## # .. # # 2# ######## """, """ ######## #0 .. 3# #2 1# ######## """ ] def move(bot, state): if bot.is_blue and bot.turn == 0 and bot.round == 1: return (6, 1), state return bot.position, state layouts = [layout.parse_layout(l) for l in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layout.parse_layout(cascade[0])) assert state['bots'] == layouts[0]['bots'] state = game.play_turn( state ) # Bot 0 moves onto 3. Gets killed. Bot 0 and 1 are on same spot. assert state['bots'] == layouts[1]['bots'] state = game.play_turn( state) # Bot 1 moves, gets killed. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 2 moves, gets killed. assert state['bots'] == layouts[3]['bots']
def test_setup_game_with_different_number_of_bots(self, bots): layout = """ ###### # . # # .# # ###### """ bot_pos, should_succeed = bots parsed = parse_layout(layout) parsed['bots'] = bot_pos if should_succeed: state = setup_game([stopping_player] * 2, layout_dict=parsed, max_rounds=5) assert state['bots'] == bot_pos state = run_game([stopping_player] * 2, layout_dict=parsed, max_rounds=5) assert state['fatal_errors'] == [[], []] assert state['errors'] == [{}, {}] else: with pytest.raises(ValueError): setup_game([stopping_player] * 2, layout_dict=parsed, max_rounds=300)
def setup_random_basic_gamestate(*, round=1, turn=0): """helper function for testing play turn""" l = layout.get_layout_by_name("small_100") parsed_l = layout.parse_layout(l) stopping = lambda bot, s: (bot.position, s) game_state = setup_game([stopping, stopping], layout_dict=parsed_l) game_state['round'] = round game_state['turn'] = turn return game_state
def test_cascade_kill(): cascade = [ (""" ######## #x ..ya# # b# ######## """, {}), (""" ######## #a .. y# # b# ######## """, { 'x': (1, 1) }), (""" ######## #a .. y# # x# ######## """, { 'b': (6, 2) }), (""" ######## #a .. y# #b x# ######## """, {}), ] def move(bot, state): if not bot.is_blue and bot.turn == 1 and bot.round == 1: return (6, 1) return bot.position layouts = [layout.parse_layout(l, bots=b) for l, b in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layouts[0]) assert state['bots'] == layouts[0]['bots'] state = game.play_turn(state) # Bot 0 stands assert state['bots'] == layouts[0]['bots'] state = game.play_turn(state) # Bot 1 stands state = game.play_turn(state) # Bot 2 stands state = game.play_turn( state) # Bot 3 moves, kills 0. Bot 0 and 1 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn( state) # Bot 0 stands, kills 1. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 1 stands, kills 2. assert state['bots'] == layouts[3]['bots']
def test_cascade_kill_rescue_1(): """ Checks that killing occurs only for the bot whose turn it is or for any bot that this bot moves onto. If a bot respawns on an enemy, it will only be killed when it is its own or the enemy’s turn (and neither of them moves). If bot moves before it is the enemy’s turn. Bot is rescued. """ cascade = [ """ ######## #30.. 2# #1 # ######## """, """ ######## #0 .. 2# #1 # ######## ######## # .. 3# # # ######## """, """ ######## #0 ..23# #1 # ######## """ ] def move(bot, state): if bot.is_blue and bot.turn == 0 and bot.round == 1: return (1, 1), state if bot.is_blue and bot.turn == 1 and bot.round == 1: return (5, 1), state return bot.position, state layouts = [layout.parse_layout(l) for l in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layout.parse_layout(cascade[0])) assert state['bots'] == layouts[0]['bots'] state = game.play_turn( state) # Bot 0 moves, kills 3. Bot 2 and 3 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn(state) # Bot 1 stands. Bot 2 and 3 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn(state) # Bot 2 moves. Rescues itself assert state['bots'] == layouts[2]['bots']
def test_cascade_suicide(): cascade = [ (""" ######## #x ..ay# # b# ######## """, {}), (""" ######## #a .. y# # b# ######## """, { 'x': (1, 1) }), (""" ######## #a .. y# # x# ######## """, { 'b': (6, 2) }), (""" ######## #a .. y# #b x# ######## """, {}), ] def move(bot, state): if bot.is_blue and bot.turn == 0 and bot.round == 1: return (6, 1) return bot.position layouts = [layout.parse_layout(l, bots=b) for l, b in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layouts[0]) assert state['bots'] == layouts[0]['bots'] state = game.play_turn( state ) # Bot 0 moves onto 3. Gets killed. Bot 0 and 1 are on same spot. assert state['bots'] == layouts[1]['bots'] state = game.play_turn( state) # Bot 1 moves, gets killed. Bot 1 and 2 are on same spot assert state['bots'] == layouts[2]['bots'] state = game.play_turn(state) # Bot 2 moves, gets killed. assert state['bots'] == layouts[3]['bots']
def test_manual_remote_game_closes_players(): layout_name, layout_string = layout.get_random_layout() l = layout.parse_layout(layout_string) # run a remote demo game with "0" and "1" state = setup_game(["0", "1"], layout_dict=l, max_rounds=10, allow_exceptions=True) assert not state["gameover"] while not state["gameover"]: # still running # still running assert state["teams"][0].proc[0].poll() is None assert state["teams"][1].proc[0].poll() is None state = play_turn(state) # Check that both processes have exited assert state["teams"][0].proc[0].wait(timeout=3) == 0 assert state["teams"][1].proc[0].wait(timeout=3) == 0
def test_bot_does_not_eat_own_food(): test_layout = """ ###### #a .y# #.bx # ###### """ teams = [stepping_player('v', '<'), stepping_player('^', '<')] state = setup_game(teams, layout_dict=layout.parse_layout(test_layout), max_rounds=2) assert state['bots'] == [(1, 1), (3, 2), (2, 2), (4, 1)] assert state['food'] == [{(1, 2)}, {(3, 1)}] for i in range(4): state = play_turn(state) assert state['bots'] == [(1, 2), (3, 1), (1, 2), (3, 1)] assert state['food'] == [{(1, 2)}, {(3, 1)}]
def test_cascade_kill_rescue_2(): """ Checks that killing occurs only for the bot whose turn it is or for any bot that this bot moves onto. If a bot respawns on an enemy, it will only be killed when it is its own or the enemy’s turn (and neither of them moves). If enemy moves before it is the bot’s turn. Bot is rescued. """ cascade = [ (""" ######## #y .. # #xa b# ######## """, {}), (""" ######## #y .. # #a x# ######## """, { 'b': (6, 2) }), (""" ######## #y .. # #a xb# ######## """, {}), ] def move(bot, state): if bot.is_blue and bot.turn == 0 and bot.round == 1: return (1, 2) if not bot.is_blue and bot.turn == 0 and bot.round == 1: return (5, 2) return bot.position layouts = [layout.parse_layout(l, bots=b) for l, b in cascade] state = setup_game([move, move], max_rounds=5, layout_dict=layouts[0]) assert state['bots'] == layouts[0]['bots'] state = game.play_turn( state) # Bot 0 moves, kills 1. Bot 1 and 2 are on same spot assert state['bots'] == layouts[1]['bots'] state = game.play_turn(state) # Bot 1 moves. Bot 2 is rescued. assert state['bots'] == layouts[2]['bots']
def test_demo_players(self): test_layout = (""" ################ #b y# # # # # # a x # # # # # # # #. .# ################ """) teams = [random_player, random_player] state = setup_game(teams, layout_dict=parse_layout(test_layout), max_rounds=20, seed=20) assert state['bots'][0] == (4, 4) assert state['bots'][1] == (4 + 7, 4) state = run_game(teams, layout_dict=parse_layout(test_layout), max_rounds=20, seed=20) pos_left_bot = state['bots'][0] pos_right_bot = state['bots'][1] # running again to test seed: state = run_game(teams, layout_dict=parse_layout(test_layout), max_rounds=20, seed=20) assert state['bots'][0] == pos_left_bot assert state['bots'][1] == pos_right_bot # running again with other seed: state = run_game(teams, layout_dict=parse_layout(test_layout), max_rounds=20, seed=200) # most probably, either the left bot or the right bot or both are at # a different position assert not (state['bots'][0] == pos_left_bot and state['bots'][1] == pos_right_bot)
def test_stepping_players(self): test_layout = (""" ############ #a . . x# #b y# ############ """) movements_0 = [east, east] movements_1 = [west, west] teams = [ stepping_player(movements_0, movements_0), stepping_player(movements_1, movements_1) ] state = setup_game(teams, layout_dict=parse_layout(test_layout), max_rounds=2) assert state['bots'] == [(1, 1), (10, 1), (1, 2), (10, 2)] state = run_game(teams, layout_dict=parse_layout(test_layout), max_rounds=2) assert state['bots'] == [(3, 1), (8, 1), (3, 2), (8, 2)]
def setup_specific_basic_gamestate(round=0, turn=0): """helper function for testing play turn""" l = """ ################## #. ... .##. y# # # # . .### #x# # # ##. . # # . .## # # #a# ###. . # # # #b .##. ... .# ################## """ parsed_l = layout.parse_layout(l) stopping = lambda bot, s: (bot.position, s) game_state = setup_game([stopping, stopping], layout_dict=parsed_l) game_state['round'] = round game_state['turn'] = turn return game_state
def test_team_names(): test_layout = (""" ################## #a#. . # . # #b##### #####x# # . # . .#y# ################## """) def team_pattern(fn): # The pattern for a local team. return f'local-team ({fn})' def team_1(bot, state): assert bot.team_name == team_pattern('team_1') assert bot.other.team_name == team_pattern('team_1') assert bot.enemy[0].team_name == team_pattern('team_2') assert bot.enemy[1].team_name == team_pattern('team_2') return bot.position def team_2(bot, state): assert bot.team_name == team_pattern('team_2') assert bot.other.team_name == team_pattern('team_2') assert bot.enemy[0].team_name == team_pattern('team_1') assert bot.enemy[1].team_name == team_pattern('team_1') return bot.position state = setup_game([team_1, team_2], layout_dict=parse_layout(test_layout), max_rounds=3) assert state['team_names'] == [ team_pattern('team_1'), team_pattern('team_2') ] state = play_turn(state) # check that player did not fail assert state['errors'] == [{}, {}] assert state['fatal_errors'] == [[], []] state = play_turn(state) # check that player did not fail assert state['errors'] == [{}, {}] assert state['fatal_errors'] == [[], []]
def make_gamestate(): def dummy_team(bot, state): return bot.position, state # get layout layout = """ ################## #. ... .##. 3# # # # . .### #1# # # ##. . # # . .## # # #0# ###. . # # # #2 .##. ... .# ################## """ lt_dict = parse_layout(layout) game_state = setup_game([dummy_team, dummy_team], layout_dict=lt_dict, max_rounds=1) return game_state
def test_track_and_kill_count(): # for each team, we track whether they have been eaten at least once # and count the number of times they have been killed bot_states = { 0: [{ 'track': [], 'eaten': False, 'times_killed': 0, 'deaths': 0 }, { 'track': [], 'eaten': False, 'times_killed': 0, 'deaths': 0 }], 1: [{ 'track': [], 'eaten': False, 'times_killed': 0, 'deaths': 0 }, { 'track': [], 'eaten': False, 'times_killed': 0, 'deaths': 0 }] } def trackingBot(bot, state): turn = bot.turn other = bot.other # first move. get the state from the global cache if state == {}: team_idx = 0 if bot.is_blue else 1 state.update(enumerate(bot_states[team_idx])) if bot.round == 1 and turn == 0: assert bot.track[0] == bot.position if bot.was_killed: state[turn]['eaten'] = True # if bot.deaths has increased from our last known value, # we add a kill # this avoids adding two kills as the eaten attribute could # be True in two consecutive turns if state[turn]['deaths'] != bot.deaths: state[turn]['times_killed'] += 1 state[turn]['deaths'] = bot.deaths if other.was_killed: state[1 - turn]['eaten'] = True if state[1 - turn]['deaths'] != bot.other.deaths: state[1 - turn]['times_killed'] += 1 state[1 - turn]['deaths'] = bot.other.deaths if bot.was_killed or not state[turn]['track']: state[turn]['track'] = [bot.position] if other.was_killed or not state[1 - turn]['track']: state[1 - turn]['track'] = [other.position] else: state[1 - turn]['track'].append(other.position) # The assertion is that the first position in bot.track # is always the respawn position. # However, in our test case, this will only happen, once # a bot has been eaten. if state[turn]['eaten']: assert bot.track[0] == bot._initial_position assert bot.track == state[turn]['track'] # bot.round * 2 + 1 + turn assert bot.track[-1] == bot.position # just move randomly. hopefully, this means some bots will be killed return randomBot(bot, state) layout = """ ########## # ab .y x# # ######## #.##. .### ########## """ team = [trackingBot, trackingBot] state = setup_game(team, max_rounds=300, layout_dict=parse_layout(layout)) while not state['gameover']: # Check that our count is consistent with what the game thinks # for the current and previous bot, we have to subtract the deaths that have just respawned # as they have not been passed to the bot yet # therefore, we only update old_deaths for the current team if state['turn'] is not None: old_deaths[state['turn']] = state['deaths'][state['turn']] old_deaths = state['deaths'][:] state = play_turn(state) deaths = state['deaths'][:] team = state['turn'] % 2 # The current bot knows about its deaths, *unless* it made suicide, # so we have to subtract 1 if bot_was_killed is True suicide_correction = [0] * 4 suicide_correction[state['turn']] = 1 if state['bot_was_killed'][ state['turn']] else 0 # The other team knows about its deaths, *unless* one of the bots got eaten # just now, or the previous bot made suicide other_team_correction = [0] * 4 for idx in range(1 - team, 4, 2): if old_deaths[idx] != deaths[idx]: other_team_correction[idx] = 1 # suicide prev_idx = state['turn'] - 1 if old_deaths[prev_idx] == deaths[prev_idx] and state[ 'bot_was_killed'][prev_idx]: other_team_correction[prev_idx] = 1 assert bot_states[0][0]['times_killed'] == deaths[ 0] - suicide_correction[0] - other_team_correction[0] assert bot_states[1][0]['times_killed'] == deaths[ 1] - suicide_correction[1] - other_team_correction[1] assert bot_states[0][1]['times_killed'] == deaths[ 2] - suicide_correction[2] - other_team_correction[2] assert bot_states[1][1]['times_killed'] == deaths[ 3] - suicide_correction[3] - other_team_correction[3] # assertions might have been caught in run_game # check that all is good assert state['fatal_errors'] == [[], []] # check that the game has run at all assert state['round'] >= 1 # check that someone has been killed, or the whole test is not doing anything assert sum(state['deaths']) > 0 # check that each single bot has been eaten, or we are not testing the full range of possibilities assert all(state['deaths'])
def test_moving_through_maze(): test_start = """ ###### #a . # #.. x# #b y# ###### """ parsed = layout.parse_layout(test_start) teams = [ stepping_player('>-v>>>-', '-^^->->'), stepping_player('<<-<<<-', '-------') ] state = setup_game(teams, layout_dict=parsed, max_rounds=8) # play first round for i in range(4): state = game.play_turn(state) test_first_round = layout.parse_layout(""" ###### # a. # #..x # #b y# ###### """) assert test_first_round['bots'] == state['bots'] assert test_first_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [0, 0] for i in range(4): state = game.play_turn(state) test_second_round = layout.parse_layout(""" ###### # a. # #bx # # y# ###### """, bots={'b': (1, 2)}, food=[(1, 2)]) # b sitting on food assert test_second_round['bots'] == state['bots'] assert test_second_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [0, 1] for i in range(4): state = game.play_turn(state) test_third_round = layout.parse_layout(""" ###### #b . # #.a x# # y# ###### """) assert test_third_round['bots'] == state['bots'] assert test_third_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [game.KILL_POINTS, 1] for i in range(4): state = game.play_turn(state) test_fourth_round = layout.parse_layout(""" ###### #b . # #a x # # y# ###### """, bots={'a': (1, 2)}, food=[(1, 2)]) # a sitting on food assert test_fourth_round['bots'] == state['bots'] assert test_fourth_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [game.KILL_POINTS, game.KILL_POINTS + 1] for i in range(4): state = game.play_turn(state) test_fifth_round = layout.parse_layout(""" ###### # b. # #.a x# # y# ###### """) assert test_fifth_round['bots'] == state['bots'] assert test_fifth_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [game.KILL_POINTS * 2, game.KILL_POINTS + 1] for i in range(4): state = game.play_turn(state) test_sixth_round = layout.parse_layout(""" ###### # b. # #a x # # y# ###### """, bots={'a': (1, 2)}, food=[(1, 2)]) # a sitting on food assert test_sixth_round['bots'] == state['bots'] assert test_sixth_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [game.KILL_POINTS * 2, game.KILL_POINTS * 2 + 1] for i in range(3): # !! Only move three bots state = game.play_turn(state) test_seventh_round = layout.parse_layout(""" ###### # b # #a x # # y# ###### """, bots={'a': (1, 2)}, food=[(1, 2) ]) # a sitting on food assert test_seventh_round['bots'] == state['bots'] assert test_seventh_round['food'] == list(state['food'][0]) + list( state['food'][1]) assert state['score'] == [ game.KILL_POINTS * 2 + 1, game.KILL_POINTS * 2 + 1 ] assert state['gameover'] == True assert state['whowins'] == 2 with pytest.raises(ValueError): state = game.play_turn(state)
def test_no_food(layout_str): with pytest.warns(NoFoodWarning): parsed = layout.parse_layout(layout_str) setup_game([stopping_player, stopping_player], layout_dict=parsed, max_rounds=300)