def test_lose_on_eating_all(self): test_start = ( """ ###### #0 . # # . 1# ###### """ ) # bot 1 eats all the food and the game stops gm = GameMaster(test_start, 2, 100) # players do nothing gm.register_team(SimpleTeam(StoppingPlayer())) gm.register_team(SimpleTeam(TestPlayer('<<<'))) gm.universe.teams[0].score = 2 # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertEqual(tv.cache[-1]["round_index"], 1) self.assertEqual(gm.universe.teams[0].score, 2) self.assertEqual(gm.universe.teams[1].score, 1) self.assertTrue(tv.cache[-1]["team_wins"] is not None) self.assertEqual(tv.cache[-1]["team_wins"], 0) self.assertEqual(gm.game_state["round_index"], 1)
def test_draw_on_timeout(self): test_start = (""" ###### #0 . # # . 1# ###### """) # the game lasts one round, and then draws NUM_ROUNDS = 1 # players do nothing teams = [SimpleTeam(StoppingPlayer()), SimpleTeam(StoppingPlayer())] gm = GameMaster(test_start, teams, 2, game_time=NUM_ROUNDS) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertTrue(tv.cache[-1]["game_draw"]) self.assertEqual(gm.game_state["round_index"], NUM_ROUNDS)
def test_lose_on_eating_all(self): test_start = ( """ ###### #0 . # # . 1# ###### """ ) teams = [ SimpleTeam(StoppingPlayer()), SimpleTeam(SteppingPlayer('<<<')) ] # bot 1 eats all the food and the game stops gm = GameMaster(test_start, teams, 2, 100) gm.universe.teams[0].score = 2 # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check assert tv.cache[-1]["round_index"] == 1 assert gm.universe.teams[0].score == 2 assert gm.universe.teams[1].score == 1 assert tv.cache[-1]["team_wins"] is not None assert tv.cache[-1]["team_wins"] == 0 assert gm.game_state["round_index"] == 1
def test_draw_on_timeout(self): test_start = ( """ ###### #0 . # # . 1# ###### """) # the game lasts one round, and then draws NUM_ROUNDS = 1 # players do nothing teams = [SimpleTeam(StoppingPlayer()), SimpleTeam(StoppingPlayer())] gm = GameMaster(test_start, teams, 2, game_time=NUM_ROUNDS) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check assert tv.cache[-1]["game_draw"] assert gm.game_state["round_index"] == NUM_ROUNDS
def test_draw_on_timeout(self): test_start = ( """ ###### #0 . # # . 1# ###### """) # the game lasts one round, and then draws gm = GameMaster(test_start, 2, 1) # players do nothing gm.register_team(SimpleTeam(StoppingPlayer())) gm.register_team(SimpleTeam(StoppingPlayer())) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, round_, turn, universe, events): self.cache.append(events) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertTrue(GameDraw in tv.cache[-1]) self.assertEqual(tv.cache[-1][0], GameDraw())
def test_win_on_timeout_team_1(self): test_start = (""" ###### #0 ..# #.. 1# ###### """) # the game lasts two rounds, enough time for bot 1 to eat food NUM_ROUNDS = 2 teams = [ SimpleTeam(StoppingPlayer()), SimpleTeam(TestPlayer( '<<')) # bot 1 moves west twice to eat the single food ] gm = GameMaster(test_start, teams, 2, game_time=NUM_ROUNDS) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertTrue(tv.cache[-1]["team_wins"] is not None) self.assertEqual(tv.cache[-1]["team_wins"], 1) self.assertEqual(gm.game_state["round_index"], NUM_ROUNDS)
def test_lose_on_eating_all(self): test_start = ( """ ###### #0 . # # . 1# ###### """ ) # the game lasts one round, and then draws gm = GameMaster(test_start, 2, 100) # players do nothing gm.register_team(SimpleTeam(StoppingPlayer())) gm.register_team(SimpleTeam(TestPlayer([west, west, west]))) gm.universe.teams[0].score = 2 # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() self.round_ = list() def observe(self, round_, turn, universe, events): self.cache.append(events) self.round_.append(round_) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertEqual(tv.round_[-1], 1) self.assertEqual(gm.universe.teams[0].score, 2) self.assertEqual(gm.universe.teams[1].score, 1) self.assertTrue(TeamWins in tv.cache[-1]) self.assertEqual(tv.cache[-1].filter_type(TeamWins)[0], TeamWins(0))
def test_win_on_timeout_team_0(self): test_start = """ ###### #0 ..# #.. 1# ###### """ # the game lasts two rounds, enough time for bot 1 to eat food NUM_ROUNDS = 2 gm = GameMaster(test_start, 2, game_time=NUM_ROUNDS) # bot 1 moves east twice to eat the single food gm.register_team(SimpleTeam(TestPlayer(">>"))) gm.register_team(SimpleTeam(StoppingPlayer())) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertTrue(tv.cache[-1]["team_wins"] is not None) self.assertEqual(tv.cache[-1]["team_wins"], 0) self.assertEqual(gm.game_state["round_index"], NUM_ROUNDS)
def test_win_on_timeout_team_1(self): test_start = ( """ ###### #0 ..# #.. 1# ###### """) # the game lasts two rounds, enough time for bot 1 to eat food gm = GameMaster(test_start, 2, 2) gm.register_team(SimpleTeam(StoppingPlayer())) # bot 1 moves west twice to eat the single food gm.register_team(SimpleTeam(TestPlayer([west, west]))) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, round_, turn, universe, events): self.cache.append(events) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertTrue(TeamWins in tv.cache[-1]) self.assertEqual(tv.cache[-1][0], TeamWins(1))
def test_win_on_timeout_team_1(self): test_start = ( """ ###### #0 ..# #.. 1# ###### """) # the game lasts two rounds, enough time for bot 1 to eat food NUM_ROUNDS = 2 teams = [ SimpleTeam(StoppingPlayer()), SimpleTeam(SteppingPlayer('<<')) # bot 1 moves west twice to eat the single food ] gm = GameMaster(test_start, teams, 2, game_time=NUM_ROUNDS) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check assert tv.cache[-1]["team_wins"] is not None assert tv.cache[-1]["team_wins"] == 1 assert gm.game_state["round_index"] == NUM_ROUNDS
def test_lose_on_eating_all(self): test_start = (""" ###### #0 . # # . 1# ###### """) teams = [SimpleTeam(StoppingPlayer()), SimpleTeam(TestPlayer('<<<'))] # bot 1 eats all the food and the game stops gm = GameMaster(test_start, teams, 2, 100) gm.universe.teams[0].score = 2 # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() # check self.assertEqual(tv.cache[-1]["round_index"], 1) self.assertEqual(gm.universe.teams[0].score, 2) self.assertEqual(gm.universe.teams[1].score, 1) self.assertTrue(tv.cache[-1]["team_wins"] is not None) self.assertEqual(tv.cache[-1]["team_wins"], 0) self.assertEqual(gm.game_state["round_index"], 1)
def test_must_not_move_after_last_timeout(self): # 0 must move back and forth because of random steps # but due to its last timeout, it should be disqualified # immediately test_start = ( """ ###### ##0.## # ## # ##. 1# ###### """ ) # players do nothing class TimeOutPlayer(AbstractPlayer): def get_move(self): raise PlayerTimeout class CheckTestPlayer(AbstractPlayer): def get_move(self): raise RuntimeError("This should never be called") teams = [ SimpleTeam(TimeOutPlayer()), SimpleTeam(CheckTestPlayer()) ] # the game lasts one round, and then draws gm = GameMaster(test_start, teams, 2, 100, max_timeouts=1) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() gm.play() print(gm.universe.pretty) print(gm.game_state) # check assert gm.game_state["max_timeouts"] == 1 assert tv.cache[-1]["round_index"] == gm.game_state["max_timeouts"] - 1 assert gm.universe.teams[0].score == 0 assert gm.universe.teams[1].score == 0 assert gm.universe.bots[0].current_pos == (2,1) assert tv.cache[-1]["team_wins"] is not None assert tv.cache[-1]["team_wins"] == 1 # the game ends in round 0 with bot_id 0 assert gm.game_state["round_index"] == 0 assert gm.game_state["bot_id"] == 0
def test_lose_5_timeouts(self): # 0 must move back and forth because of random steps test_start = ( """ ###### #0 #.# ### # ##. 1# ###### """ ) # players do nothing class TimeOutPlayer(AbstractPlayer): def get_move(self): raise PlayerTimeout teams = [ SimpleTeam(TimeOutPlayer()), SimpleTeam(StoppingPlayer()) ] # the game lasts one round, and then draws gm = GameMaster(test_start, teams, 2, 100, max_timeouts=5) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() assert gm.universe.bots[0].current_pos == (1,1) gm.play() # check assert gm.game_state["max_timeouts"] == 5 assert tv.cache[-1]["round_index"] == gm.game_state["max_timeouts"] - 1 assert gm.universe.teams[0].score == 0 assert gm.universe.teams[1].score == 0 # the bot moves four times, so after the fourth time, # it is back on its original position assert gm.universe.bots[0].current_pos == (1,1) assert tv.cache[-1]["team_wins"] is not None assert tv.cache[-1]["team_wins"] == 1
def test_viewer_must_not_change_gm(self): free_obj = Free() class MeanViewer(AbstractViewer): def set_initial(self, universe): universe.teams[1].score = 50 def observe(self, round_, turn, universe, events): universe.teams[0].score = 100 universe.bots[0].current_pos = (4,4) universe.maze[0,0][0] = free_obj events.append(TeamWins(0)) test_self.assertEqual(len(events), 2) test_start = ( """ ###### #0 . # #.. 1# ###### """) number_bots = 2 gm = GameMaster(test_start, number_bots, 200) gm.register_team(SimpleTeam(TestPlayer([(0,0)]))) gm.register_team(SimpleTeam(TestPlayer([(0,0)]))) original_universe = gm.universe.copy() test_self = self class TestViewer(AbstractViewer): def observe(self, round_, turn, universe, events): # universe should not have been altered test_self.assertEqual(original_universe, gm.universe) # there should only be a botmoves event test_self.assertEqual(len(events), 1) test_self.assertEqual(len(events), 1) test_self.assertTrue(BotMoves in events) gm.register_viewer(MeanViewer()) gm.register_viewer(TestViewer()) gm.set_initial() gm.play_round(0) self.assertEqual(original_universe, gm.universe)
def test_lose_5_timeouts(self): # 0 must move back and forth because of random steps test_start = ( """ ###### #0 #.# ### # ##. 1# ###### """ ) # the game lasts one round, and then draws gm = GameMaster(test_start, 2, 100) # players do nothing class TimeOutPlayer(AbstractPlayer): def get_move(self): raise PlayerTimeout gm.register_team(SimpleTeam(TimeOutPlayer())) gm.register_team(SimpleTeam(StoppingPlayer())) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() self.round_ = list() def observe(self, round_, turn, universe, events): self.cache.append(events) self.round_.append(round_) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() self.assertEqual(gm.universe.bots[0].current_pos, (1,1)) gm.play() # check self.assertEqual(tv.round_[-1], pelita.game_master.MAX_TIMEOUTS - 1) self.assertEqual(gm.universe.teams[0].score, 0) self.assertEqual(gm.universe.teams[1].score, 0) self.assertEqual(gm.universe.bots[0].current_pos, (2,1)) self.assertTrue(TeamWins in tv.cache[-1]) self.assertEqual(tv.cache[-1].filter_type(TeamWins)[0], TeamWins(1))
def test_lose_5_timeouts(self): # 0 must move back and forth because of random steps test_start = ( """ ###### #0 #.# ### # ##. 1# ###### """ ) # the game lasts one round, and then draws gm = GameMaster(test_start, 2, 100, max_timeouts=5) # players do nothing class TimeOutPlayer(AbstractPlayer): def get_move(self): raise PlayerTimeout gm.register_team(SimpleTeam(TimeOutPlayer())) gm.register_team(SimpleTeam(StoppingPlayer())) # this test viewer caches all events lists seen through observe class TestViewer(AbstractViewer): def __init__(self): self.cache = list() def observe(self, universe, game_state): self.cache.append(game_state) # run the game tv = TestViewer() gm.register_viewer(tv) gm.set_initial() self.assertEqual(gm.universe.bots[0].current_pos, (1,1)) gm.play() # check self.assertEqual(gm.game_state["max_timeouts"], 5) self.assertEqual(tv.cache[-1]["round_index"], gm.game_state["max_timeouts"] - 1) self.assertEqual(gm.universe.teams[0].score, 0) self.assertEqual(gm.universe.teams[1].score, 0) self.assertEqual(gm.universe.bots[0].current_pos, (2,1)) self.assertTrue(tv.cache[-1]["team_wins"] is not None) self.assertEqual(tv.cache[-1]["team_wins"], 1)
def test_viewer_may_change_gm(self): class MeanViewer(AbstractViewer): def set_initial(self, universe): universe.teams[1].score = 50 def observe(self, universe, game_state): universe.teams[0].score = 100 universe.bots[0].current_pos = (4,2) universe.maze[0,0] = False game_state["team_wins"] = 0 test_start = ( """ ###### #0 . # #.. 1# ###### """) number_bots = 2 teams = [ SimpleTeam(TestPlayer([(0,0)])), SimpleTeam(TestPlayer([(0,0)])) ] gm = GameMaster(test_start, teams, number_bots, 200) original_universe = gm.universe.copy() test_self = self class TestViewer(AbstractViewer): def observe(self, universe, game_state): # universe has been altered test_self.assertNotEqual(original_universe, gm.universe) gm.register_viewer(MeanViewer()) gm.register_viewer(TestViewer()) gm.set_initial() gm.play_round() self.assertNotEqual(original_universe, gm.universe)
def test_viewer_may_change_gm(self): class MeanViewer(AbstractViewer): def set_initial(self, universe): universe.teams[1].score = 50 def observe(self, universe, game_state): universe.teams[0].score = 100 universe.bots[0].current_pos = (4, 2) universe.maze[0, 0] = False game_state["team_wins"] = 0 test_start = (""" ###### #0 . # #.. 1# ###### """) number_bots = 2 teams = [ SimpleTeam(TestPlayer([(0, 0)])), SimpleTeam(TestPlayer([(0, 0)])) ] gm = GameMaster(test_start, teams, number_bots, 200) original_universe = gm.universe.copy() test_self = self class TestViewer(AbstractViewer): def observe(self, universe, game_state): # universe has been altered test_self.assertNotEqual(original_universe, gm.universe) gm.register_viewer(MeanViewer()) gm.register_viewer(TestViewer()) gm.set_initial() gm.play_round() self.assertNotEqual(original_universe, gm.universe)
#!/usr/bin/python from pelita.game_master import GameMaster from pelita.player import StoppingPlayer, SimpleTeam from pelita.viewer import AsciiViewer from players import RandomPlayer, NQRandomPlayer if __name__ == '__main__': layout = (""" ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) gm = GameMaster(layout, 4, 200) gm.register_team(SimpleTeam(StoppingPlayer(), NQRandomPlayer())) gm.register_team(SimpleTeam(NQRandomPlayer(), NQRandomPlayer())) gm.register_viewer(AsciiViewer()) gm.play()
def test_game(self): test_start = ( """ ###### #0 . # #.. 1# ###### """) number_bots = 2 # The problem here is that the layout does not allow us to specify a # different inital position and current position. When testing universe # equality by comparing its string representation, this does not matter. # But if we want to compare using the __eq__ method, but specify the # target as ascii encoded maze/layout we need to convert the layout to a # CTFUniverse and then modify the initial positions. For this we define # a closure here to quickly generate a target universe to compare to. # Also we adapt the score, in case food has been eaten def create_TestUniverse(layout, black_score=0, white_score=0): initial_pos = [(1, 1), (4, 2)] universe = create_CTFUniverse(layout, number_bots) universe.teams[0].score = black_score universe.teams[1].score = white_score for i, pos in enumerate(initial_pos): universe.bots[i].initial_pos = pos if not universe.maze.has_at(Food, (1, 2)): universe.teams[1]._score_point() if not universe.maze.has_at(Food, (2, 2)): universe.teams[1]._score_point() if not universe.maze.has_at(Food, (3, 1)): universe.teams[0]._score_point() return universe gm = GameMaster(test_start, number_bots, 200) gm.register_team(SimpleTeam(TestPlayer([east, east, east, south, stop, east]))) gm.register_team(SimpleTeam(TestPlayer([west, west, west, stop, west, west]))) gm.register_viewer(DevNullViewer()) gm.set_initial() gm.play_round(0) test_first_round = ( """ ###### # 0. # #..1 # ###### """) self.assertEqual(create_TestUniverse(test_first_round), gm.universe) gm.play_round(1) test_second_round = ( """ ###### # 0. # #.1 # ###### """) self.assertEqual(create_TestUniverse(test_second_round), gm.universe) gm.play_round(2) test_third_round = ( """ ###### # . # #.0 1# ###### """) self.assertEqual(create_TestUniverse(test_third_round, black_score=KILLPOINTS), gm.universe) gm.play_round(3) test_fourth_round = ( """ ###### #0 . # #. 1 # ###### """) self.assertEqual(create_TestUniverse(test_fourth_round, black_score=KILLPOINTS, white_score=KILLPOINTS), gm.universe) gm.play_round(4) test_fifth_round = ( """ ###### # 0. # #.1 # ###### """) self.assertEqual(create_TestUniverse(test_fifth_round, black_score=KILLPOINTS, white_score=KILLPOINTS), gm.universe) print gm.universe.pretty gm.play_round(5) test_sixth_round = ( """ ###### # 0 # #.1 # ###### """) print gm.universe.pretty self.assertEqual(create_TestUniverse(test_sixth_round, black_score=KILLPOINTS, white_score=KILLPOINTS), gm.universe) # now play the full game gm = GameMaster(test_start, number_bots, 200) gm.register_team(SimpleTeam(TestPlayer([east, east, east, south, stop, east]))) gm.register_team(SimpleTeam(TestPlayer([west, west, west, stop, west, west]))) gm.play() test_sixth_round = ( """ ###### # 0 # #.1 # ###### """) self.assertEqual(create_TestUniverse(test_sixth_round, black_score=KILLPOINTS, white_score=KILLPOINTS), gm.universe)
#!/usr/bin/python # -*- coding: utf-8 -*- import threading from pelita.game_master import GameMaster from pelita.player import StoppingPlayer, RandomPlayer, NQRandomPlayer, BFSPlayer, SimpleTeam from pelita.ui.tk_viewer import TkViewer if __name__ == '__main__': layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) gm = GameMaster(layout, 4, 200) gm.register_team(SimpleTeam(StoppingPlayer(), NQRandomPlayer())) gm.register_team(SimpleTeam(RandomPlayer(), BFSPlayer())) viewer = TkViewer() gm.register_viewer(viewer) threading.Thread(target=gm.play).start() viewer.app.mainloop()
#!/usr/bin/env python3 from pelita.game_master import GameMaster from pelita.player import StoppingPlayer, SimpleTeam from pelita.viewer import AsciiViewer from players import BFSPlayer if __name__ == "__main__": layout = """ ################## #0#. . # . # # ##### ##### # # . # . .#1# ################## """ gm = GameMaster(layout, 2, 200) gm.register_team(SimpleTeam(BFSPlayer())) gm.register_team(SimpleTeam(StoppingPlayer())) gm.register_viewer(AsciiViewer()) gm.play()
def test_remote_viewer_may_not_change_gm(self): free_obj = Free self.mean_viewer_did_run = False class MeanViewer(AbstractViewer): def set_initial(self, universe): universe.teams[1].score = 50 def observe(self_, universe, game_state): self.mean_viewer_did_run = True universe.teams[0].score = 100 universe.bots[0].current_pos = (4, 4) universe.maze[0, 0] = free_obj game_state["team_wins"] = 0 test_start = (""" ###### #0 . # #.. 1# ###### """) number_bots = 2 gm = GameMaster(test_start, number_bots, 1) gm.register_team(SimpleTeam(TestPlayer([(0, 0)]))) gm.register_team(SimpleTeam(TestPlayer([(0, 0)]))) original_universe = gm.universe.copy() self.test_viewer_did_run = False test_self = self class TestViewer(AbstractViewer): def observe(self_, universe, game_state): self.test_viewer_did_run = True # universe should not have been altered test_self.assertEqual(original_universe, gm.universe) # there should only be a botmoves event test_self.assertEqual(len(game_state["bot_moved"]), 1) test_self.assertEqual(len(game_state["bot_moved"]), 1) # We need to be able to tell when our subscriber is able to receive # new events from the publisher. # Due to its completely asynchronous approach, zmq does not even # provide built-in methods to check whether two or more sockets # are connected, so we have to figure a way to find out. # The approach is as follows: When the publisher starts, it # sends only ‘sync’ messages without a pause. # When a subscriber is finally connected, it will receive this message and # set an instance variable (`has_sync`). The main thread checks whether # all variables of all subscribers have been set, will stop # sending ‘sync’ and move on. # No special thread synchronisation or locking is being used. The current # code is hopefully simple enough not to include any race conditions. class SyncedSubscriber(SimpleSubscriber): def sync(self): self.has_sync = True address = "ipc:///tmp/pelita-publisher-%s" % uuid.uuid4() mean_viewer = SyncedSubscriber(MeanViewer(), address) test_viewer = SyncedSubscriber(TestViewer(), address) # must be threads because we try to access shared state # in the mean_viewer_did_run variable # (and in a bad way) mean_viewer_thread = mean_viewer.autoplay_thread() test_viewer_thread = test_viewer.autoplay_thread() publisher_viewer = SimplePublisher(address) viewers = [mean_viewer, test_viewer] while not all( getattr(viewer, "has_sync", False) for viewer in viewers): publisher_viewer.socket.send_json({"__action__": "sync"}) # now we can register it and game_master takes care of sending messages gm.register_viewer(publisher_viewer) gm.set_initial() gm.play() # exit our threads publisher_viewer.socket.send_json({ "__action__": "exit", "__data__": {} }) # wait until threads stop mean_viewer_thread.join() test_viewer_thread.join() # must close the socket and terminate the context # else we may get an assertion failure in zmq publisher_viewer.socket.close() publisher_viewer.context.term() self.assertEqual(original_universe, gm.universe) # check, that the code was actually executed self.assertTrue(self.mean_viewer_did_run) self.assertTrue(self.test_viewer_did_run)
def test_remote_viewer_may_not_change_gm(self): free_obj = Free self.mean_viewer_did_run = False class MeanViewer(AbstractViewer): def set_initial(self, universe): universe.teams[1].score = 50 def observe(self_, universe, game_state): self.mean_viewer_did_run = True universe.teams[0].score = 100 universe.bots[0].current_pos = (4,4) universe.maze[0,0] = free_obj game_state["team_wins"] = 0 test_start = ( """ ###### #0 . # #.. 1# ###### """) number_bots = 2 gm = GameMaster(test_start, number_bots, 1) gm.register_team(SimpleTeam(TestPlayer([(0,0)]))) gm.register_team(SimpleTeam(TestPlayer([(0,0)]))) original_universe = gm.universe.copy() self.test_viewer_did_run = False test_self = self class TestViewer(AbstractViewer): def observe(self_, universe, game_state): self.test_viewer_did_run = True # universe should not have been altered test_self.assertEqual(original_universe, gm.universe) # there should only be a botmoves event test_self.assertEqual(len(game_state["bot_moved"]), 1) test_self.assertEqual(len(game_state["bot_moved"]), 1) # We need to be able to tell when our subscriber is able to receive # new events from the publisher. # Due to its completely asynchronous approach, zmq does not even # provide built-in methods to check whether two or more sockets # are connected, so we have to figure a way to find out. # The approach is as follows: When the publisher starts, it # sends only ‘sync’ messages without a pause. # When a subscriber is finally connected, it will receive this message and # set an instance variable (`has_sync`). The main thread checks whether # all variables of all subscribers have been set, will stop # sending ‘sync’ and move on. # No special thread synchronisation or locking is being used. The current # code is hopefully simple enough not to include any race conditions. class SyncedSubscriber(SimpleSubscriber): def sync(self): self.has_sync = True mean_viewer = SyncedSubscriber(MeanViewer(), "ipc:///tmp/pelita-publisher") test_viewer = SyncedSubscriber(TestViewer(), "ipc:///tmp/pelita-publisher") # must be threads because we try to access shared state # in the mean_viewer_did_run variable # (and in a bad way) mean_viewer_thread = mean_viewer.autoplay_thread() test_viewer_thread = test_viewer.autoplay_thread() publisher_viewer = SimplePublisher("ipc:///tmp/pelita-publisher") viewers = [mean_viewer, test_viewer] while not all(getattr(viewer, "has_sync", False) for viewer in viewers): publisher_viewer.socket.send_json({"__action__": "sync"}) # now we can register it and game_master takes care of sending messages gm.register_viewer(publisher_viewer) gm.set_initial() gm.play() # exit our threads publisher_viewer.socket.send_json({"__action__": "exit", "__data__": {}}) # wait until threads stop mean_viewer_thread.join() test_viewer_thread.join() # must close the socket and terminate the context # else we may get an assertion failure in zmq publisher_viewer.socket.close() publisher_viewer.context.term() self.assertEqual(original_universe, gm.universe) # check, that the code was actually executed self.assertTrue(self.mean_viewer_did_run) self.assertTrue(self.test_viewer_did_run)
class ServerActor(DispatchingActor): """ Actor which is used to handle all incoming requests, assigns each team a RemoteTeamPlayer and registers this with GameMaster. It also automatically starts a new game whenever two players are accepted. """ def on_start(self): self.teams = [] self.team_names = [] self.game_master = None @expose def initialize_game(self, message, layout, number_bots, game_time): """ Initialises a new game. """ self.game_master = GameMaster(layout, number_bots, game_time) def _remove_dead_teams(self): # check, if previously added teams are still alive: zipped = [(team, name) for team, name in zip(self.teams, self.team_names) if not getattr(team, "_remote_mailbox", None) or team._remote_mailbox.outbox.thread.is_alive()] if zipped: teams, team_names = zip(*zipped) self.teams = list(teams) self.team_names = list(team_names) @expose def hello(self, message, team_name, actor_uuid): """ Register the actor with address `actor_uuid` as team `team_name`. """ _logger.info("Received 'hello' from '%s'." % team_name) self._remove_dead_teams() if self.ref.remote: other_ref = self.ref.remote.create_proxy(actor_uuid) else: other_ref = actor_registry.get_by_uuid(actor_uuid) self.teams.append(other_ref) self.team_names.append(team_name) self.ref.reply("ok") if len(self.teams) == 2: _logger.info("Two players are available. Starting a game.") self.ref.notify("start_game") @expose def register_viewer(self, message, viewer): self.game_master.register_viewer(viewer) @expose def start_game(self, message): """ Tells the game master to start a new game. This method only returns when the game master itself returns. """ for team_idx in range(len(self.teams)): team_ref = self.teams[team_idx] team_name = self.team_names[team_idx] remote_player = RemoteTeamPlayer(team_ref) self.game_master.register_team(remote_player, team_name=team_name) self.game_master.play()
#!/usr/bin/python from pelita.game_master import GameMaster from pelita.player import BFSPlayer, RandomPlayer, NQRandomPlayer, SimpleTeam from pelita.viewer import AbstractViewer import sys from pacman_viewer import TornadoViewer from pelita.layout import get_random_layout if __name__ == '__main__': layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) layout = get_random_layout() gm = GameMaster(layout, 4, 200) gm.register_team(SimpleTeam(BFSPlayer(), NQRandomPlayer())) gm.register_team(SimpleTeam(NQRandomPlayer(), BFSPlayer())) gm.register_viewer(TornadoViewer()) gm.play()