def test_stop_is_called_with_pending_callback(self): self.render(None) game_widget = Mock() players = PlayerPair(Mock(), Mock()) players.one.is_cheater.return_value = False players.two.is_cheater.return_value = False score_view = Mock() # noinspection PyTypeChecker game_controller = GameController(game_widget, players, score_view) bummerl = Bummerl(next_dealer=PlayerId.ONE) bummerl.start_game(seed=2) actions = get_actions_for_one_complete_game(PlayerId.TWO) expected_game_state = GameState.new(dealer=PlayerId.ONE, random_seed=2) game_controller.start(bummerl) # Initializes the game widget. game_widget.reset.assert_called_once() game_widget.init_from_game_state.assert_called_once() actual_game_state, done_callback, game_points = \ game_widget.init_from_game_state.call_args.args self.assertEqual(expected_game_state, actual_game_state) self.assertEqual(PlayerPair(0, 0), game_points) game_widget.reset_mock() done_callback() # Player action is requested. action = actions[0] players[action.player_id].request_next_action.assert_called_once() actual_game_state, action_callback, actual_game_points = \ players[action.player_id].request_next_action.call_args.args self.assertEqual(bummerl.game_points, actual_game_points) expected_game_state = action.execute(expected_game_state) players[action.player_id].reset_mock() # GameController.stop() is called before the GameWidget calls # action_callback(). game_controller.stop() # Player responds with an action. action_callback(action) # GameWidget.on_action() is called to update the UI. game_widget.on_action.assert_called_once() actual_action, done_callback = game_widget.on_action.call_args.args self.assertEqual(action, actual_action) game_widget.reset_mock() done_callback() # The GameController requests no action from the next player. next_player = expected_game_state.next_player players[next_player].request_next_action.assert_not_called()
def test_create_with_dealer_and_seed(self): bummerl = Bummerl(next_dealer=PlayerId.ONE) self.assertIsNone(bummerl.game) self.assertEqual([], bummerl.completed_games) self.assertEqual(PlayerPair(0, 0), bummerl.game_points) self.assertFalse(bummerl.is_over) game = bummerl.start_game(seed=456) self.assertEqual(game, bummerl.game) self.assertEqual([], bummerl.completed_games) self.assertIsNotNone(game) self.assertEqual(game.game_state, GameState.new(dealer=PlayerId.ONE, random_seed=456))
def test_cannot_finalize_the_current_game_if_it_is_not_over(self): bummerl = Bummerl() bummerl.start_game() self.assertFalse(bummerl.game.game_state.is_game_over) with self.assertRaisesRegex(AssertionError, "Current game is not over"): bummerl.finalize_game()
def test_seed_is_initialized_randomly_when_not_specified(self): """ Tests that the Bummerl object picks a seed if it is not specified as an argument to start(). This seed needs to be saved in case the Game object is pickled and unpickled. Otherwise, during unpickling we will start with a different game state. """ bummerl = Bummerl(next_dealer=PlayerId.ONE) bummerl.start_game() game = bummerl.game actions = get_available_actions(game.game_state) selected_action = \ [action for action in actions if isinstance(action, PlayCardAction)][0] game.play_action(selected_action) expected_game_state = copy.deepcopy(game.game_state) unpickled_bummerl = loads(dumps(bummerl)) self.assertIsNot(expected_game_state, unpickled_bummerl.game.game_state) self.assertEqual(expected_game_state, unpickled_bummerl.game.game_state)
def test_pickling(self): bummerl = Bummerl(next_dealer=PlayerId.ONE) _simulate_a_complete_game(bummerl.start_game(seed=2)) bummerl.finalize_game() _simulate_a_complete_game(bummerl.start_game(seed=2)) unpickled_bummerl = loads(dumps(bummerl)) self.assertIsNot(bummerl, unpickled_bummerl) self.assertIsNotNone(unpickled_bummerl.game) self.assertEqual(PlayerPair(0, 3), unpickled_bummerl.game_points) self.assertEqual(1, len(unpickled_bummerl.completed_games)) self.assertFalse(unpickled_bummerl.is_over) unpickled_bummerl.finalize_game() self.assertIsNone(unpickled_bummerl.game) self.assertEqual(PlayerPair(3, 3), unpickled_bummerl.game_points) self.assertEqual(2, len(unpickled_bummerl.completed_games)) self.assertFalse(unpickled_bummerl.is_over)
def test_new_bummerl_new_game(self): self.render(None) game_widget = Mock() players = PlayerPair(Mock(), Mock()) players.one.is_cheater.return_value = False players.two.is_cheater.return_value = True score_view = Mock() # noinspection PyTypeChecker game_controller = GameController(game_widget, players, score_view) bummerl = Bummerl(next_dealer=PlayerId.ONE) bummerl.start_game(seed=2) actions = get_actions_for_one_complete_game(PlayerId.TWO) expected_game_state = GameState.new(dealer=PlayerId.ONE, random_seed=2) game_controller.start(bummerl) # Initializes the game widget. game_widget.reset.assert_called_once() game_widget.init_from_game_state.assert_called_once() actual_game_state, done_callback, game_points = \ game_widget.init_from_game_state.call_args.args self.assertEqual(expected_game_state, actual_game_state) self.assertEqual(PlayerPair(0, 0), game_points) game_widget.reset_mock() done_callback() indices_of_actions_that_complete_a_trick = [1, 4, 6, 8, 10, 12] for i, action in enumerate(actions): print(f"Testing action #{i}: {action}") # Player action is requested. players[action.player_id].request_next_action.assert_called_once() actual_game_state, action_callback, actual_game_points = \ players[action.player_id].request_next_action.call_args.args if actual_game_state.next_player == PlayerId.ONE: self.assertEqual(expected_game_state.next_player_view(), actual_game_state) else: self.assertEqual(expected_game_state, actual_game_state) self.assertEqual(bummerl.game_points, actual_game_points) expected_game_state = action.execute(expected_game_state) players[action.player_id].reset_mock() # Player responds with an action. action_callback(action) # GameWidget.on_action() is called to update the UI. game_widget.on_action.assert_called_once() actual_action, done_callback = game_widget.on_action.call_args.args self.assertEqual(action, actual_action) game_widget.reset_mock() done_callback() # If a trick is completed, GameWidget.on_score_modified() is called and # GameWidget.on_trick_completed() is called. if i in indices_of_actions_that_complete_a_trick: game_widget.on_score_modified.assert_called_once() actual_score = game_widget.on_score_modified.call_args.args[0] self.assertEqual(expected_game_state.trick_points, actual_score) self.wait_for_mock_callback(game_widget.on_trick_completed) last_trick, winner, cards_in_hard, draw_new_cards, done_callback = \ game_widget.on_trick_completed.call_args.args self.assertEqual(expected_game_state.next_player, winner) self.assertEqual(expected_game_state.won_tricks[winner][-1], last_trick) self.assertEqual(expected_game_state.cards_in_hand, cards_in_hard) self.assertEqual(i == 1, draw_new_cards) game_widget.reset_mock() done_callback() # The game is over. The score_view_callback is called. score_view.assert_called_once() score_history, dismiss_callback = score_view.call_args.args self.assertEqual([(PlayerPair(13, 67), PlayerPair(0, 3))], score_history) score_view.reset_mock() dismiss_callback() # A new game is started. game_widget.reset.assert_called_once() game_widget.init_from_game_state.assert_called_once() actual_game_state, done_callback, game_points = \ game_widget.init_from_game_state.call_args.args self.assertEqual(PlayerId.ONE, actual_game_state.next_player) self.assertEqual(PlayerPair(0, 0), actual_game_state.trick_points) self.assertEqual(PlayerPair(0, 3), game_points) game_controller.stop()
def test_new_bummerl_is_started_after_the_current_one_is_over(self): self.render(None) game_widget = Mock() players = PlayerPair(Mock(), Mock()) players.one.is_cheater.return_value = False players.two.is_cheater.return_value = False score_view = Mock() # noinspection PyTypeChecker game_controller = GameController(game_widget, players, score_view) # Play an entire Bummerl except the last action. last_action = None bummerl = Bummerl(next_dealer=PlayerId.ONE) for i in range(5): bummerl.start_game(seed=2) actions = get_actions_for_one_complete_game( bummerl.game.game_state.next_player) actions_to_play = actions if i != 4 else actions[:-1] for action in actions_to_play: bummerl.game.play_action(action) if i == 4: last_action = actions[-1] break bummerl.finalize_game() game_controller.start(bummerl) # Initializes the game widget. game_widget.reset.assert_called_once() game_widget.init_from_game_state.assert_called_once() actual_game_state, done_callback, game_points = \ game_widget.init_from_game_state.call_args.args self.assertEqual(bummerl.game.game_state, actual_game_state) self.assertEqual(PlayerPair(6, 6), game_points) game_widget.reset_mock() done_callback() # Player action is requested. players[last_action.player_id].request_next_action.assert_called_once() actual_game_state, action_callback, actual_game_points = \ players[last_action.player_id].request_next_action.call_args.args self.assertEqual(bummerl.game.game_state.next_player_view(), actual_game_state) self.assertEqual(bummerl.game_points, actual_game_points) players[last_action.player_id].reset_mock() # Player responds with an action. action_callback(last_action) # GameWidget.on_action() is called to update the UI. game_widget.on_action.assert_called_once() actual_action, done_callback = game_widget.on_action.call_args.args self.assertEqual(last_action, actual_action) game_widget.reset_mock() done_callback() # GameWidget.on_score_modified() is called to update the score. game_widget.on_score_modified.assert_called_once() actual_score = game_widget.on_score_modified.call_args.args[0] self.assertEqual(PlayerPair(13, 67), actual_score) # GameWidget.on_trick_completed() is called. self.wait_for_mock_callback(game_widget.on_trick_completed) last_trick, winner, cards_in_hard, draw_new_cards, done_callback = \ game_widget.on_trick_completed.call_args.args self.assertEqual(bummerl.game.game_state.won_tricks.two[-1], last_trick) self.assertEqual(PlayerId.TWO, winner) self.assertEqual(bummerl.game.game_state.cards_in_hand, cards_in_hard) self.assertEqual(False, draw_new_cards) game_widget.reset_mock() done_callback() # The game is over. The score_view_callback is called. score_view.assert_called_once() score_history, dismiss_callback = score_view.call_args.args self.assertEqual([(PlayerPair(13, 67), PlayerPair(0, 3)), (PlayerPair(67, 13), PlayerPair(3, 0)), (PlayerPair(13, 67), PlayerPair(0, 3)), (PlayerPair(67, 13), PlayerPair(3, 0)), (PlayerPair(13, 67), PlayerPair(0, 3))], score_history) score_view.reset_mock() dismiss_callback() # A new bummerl and a new game is started. game_widget.reset.assert_called_once() game_widget.init_from_game_state.assert_called_once() actual_game_state, done_callback, game_points = \ game_widget.init_from_game_state.call_args.args self.assertEqual(PlayerPair(0, 0), actual_game_state.trick_points) self.assertEqual(PlayerPair(0, 0), game_points) game_controller.stop()
def test_cannot_start_a_game_if_current_game_is_not_finalized(self): bummerl = Bummerl() bummerl.start_game() with self.assertRaisesRegex(AssertionError, "Game in progress"): bummerl.start_game()
def test_play_a_complete_bummerl(self): bummerl = Bummerl(next_dealer=PlayerId.ONE) self.assertEqual(PlayerPair(0, 0), bummerl.game_points) self.assertEqual([], bummerl.completed_games) game_1 = bummerl.start_game(seed=2) _simulate_a_complete_game(game_1) bummerl.finalize_game() self.assertIsNone(bummerl.game) self.assertEqual(PlayerPair(0, 3), bummerl.game_points) self.assertEqual([game_1], bummerl.completed_games) self.assertFalse(bummerl.is_over) game_2 = bummerl.start_game(seed=2) _simulate_a_complete_game(game_2) bummerl.finalize_game() self.assertIsNone(bummerl.game) self.assertEqual(PlayerPair(3, 3), bummerl.game_points) self.assertEqual([game_1, game_2], bummerl.completed_games) self.assertFalse(bummerl.is_over) game_3 = bummerl.start_game(seed=2) _simulate_a_complete_game(game_3) bummerl.finalize_game() self.assertIsNone(bummerl.game) self.assertEqual(PlayerPair(3, 6), bummerl.game_points) self.assertEqual([game_1, game_2, game_3], bummerl.completed_games) self.assertFalse(bummerl.is_over) game_4 = bummerl.start_game(seed=2) _simulate_a_complete_game(game_4) bummerl.finalize_game() self.assertIsNone(bummerl.game) self.assertEqual(PlayerPair(6, 6), bummerl.game_points) self.assertEqual([game_1, game_2, game_3, game_4], bummerl.completed_games) self.assertFalse(bummerl.is_over) game_5 = bummerl.start_game(seed=2) _simulate_a_complete_game(game_5) bummerl.finalize_game() self.assertIsNone(bummerl.game) self.assertEqual(PlayerPair(6, 9), bummerl.game_points) self.assertEqual([game_1, game_2, game_3, game_4, game_5], bummerl.completed_games) self.assertTrue(bummerl.is_over) with self.assertRaisesRegex( AssertionError, r"Bummerl is over: PlayerPair\(one=6, two=9\)"): bummerl.start_game()
def test_create_with_no_arguments(self): bummerl = Bummerl() self.assertIsNone(bummerl.game) self.assertEqual([], bummerl.completed_games) self.assertEqual(PlayerPair(0, 0), bummerl.game_points) self.assertFalse(bummerl.is_over)
def evaluate_player_pair_in_process(num_bummerls: int, players: PlayerPair[str]) -> MetricsDict: # pylint: disable=too-many-locals,too-many-branches,too-many-statements players = PlayerPair(PLAYER_NAMES[players.one](PlayerId.ONE), PLAYER_NAMES[players.two](PlayerId.TWO)) # Initialize the metrics. bummerls = PlayerPair(0, 0) game_points = PlayerPair(0, 0) games = PlayerPair(0, 0) trick_points = PlayerPair(0, 0) bummerls_of_interest = PlayerPair(0, 0) games_of_interest = PlayerPair(0, 0) perf_counter_sum = PlayerPair(0, 0) process_time_sum = PlayerPair(0, 0) num_actions_requested = PlayerPair(0, 0) random_seed_generator = random.Random() # Simulate the games and update the metrics accordingly. for i in range(num_bummerls): print( f"\rSimulating bummerl {i} out of {num_bummerls} ({bummerls})...", end="") bummerl = Bummerl() is_bummerl_of_interest = False while not bummerl.is_over: bummerl.start_game(seed=random_seed_generator.random()) players.one.game_of_interest = False players.two.game_of_interest = False game = bummerl.game while not game.game_state.is_game_over: player_id = game.game_state.next_player if players[player_id].cheater: game_view = game.game_state else: game_view = game.game_state.next_player_view() action, perf_counter, process_time = _request_next_action_and_time_it( game_view, bummerl.game_points, players[player_id]) game.play_action(action) perf_counter_sum[player_id] += perf_counter process_time_sum[player_id] += process_time num_actions_requested[player_id] += 1 is_game_of_interest = \ players.one.game_of_interest or players.two.game_of_interest if is_game_of_interest: is_bummerl_of_interest = True _accumulate_player_pair(trick_points, game.game_state.trick_points) last_game_points = game.game_state.game_points if last_game_points.one > 0: games.one += 1 if is_game_of_interest: games_of_interest.one += 1 else: games.two += 1 if is_game_of_interest: games_of_interest.two += 1 _accumulate_player_pair(game_points, last_game_points) bummerl.finalize_game() if bummerl.game_points.one > 6: bummerls.one += 1 if is_bummerl_of_interest: bummerls_of_interest.one += 1 else: bummerls.two += 1 if is_bummerl_of_interest: bummerls_of_interest.two += 1 print(end="\r") return { "bummerls": bummerls, "games": games, "game_points": game_points, "trick_points": trick_points, "bummerls_of_interest": bummerls_of_interest, "games_of_interest": games_of_interest, "perf_counter_sum": perf_counter_sum, "process_time_sum": process_time_sum, "num_actions_requested": num_actions_requested }