def test_get_move_chooses_random_available_move_if_random_lt_epsilon(
         self, random_mock, choice_mock):
     random_mock.return_value = 0.099
     choice_mock.side_effect = MockRandom(4).choice
     assert_get_move_is(self, self.player, self.board, 6, Board.X,
                        "X--|-O-|---")
     choice_mock.assert_called_once_with([1, 2, 3, 5, 6, 7, 8])
    def test_get_move_chooses_random_best_available_move_if_random_gte_epsilon_and_multiple_bests(
            self, random_mock, choice_mock):
        random_mock.return_value = 0.1
        choice_mock.side_effect = MockRandom(1).choice

        self.player.values[get_board_state_tuple(
            "X--|-XO|---")] = 0.501  # position 0
        self.player.values[get_board_state_tuple(
            "--X|-XO|---")] = 0.501  # position 2

        # Symmetries for X--|-XO|---:
        #                -O-|-X-|X-- (Rotated by 90 degrees)
        #                ---|OX-|--X (Rotated by 180 degrees)
        #                --X|-X-|-O- (Rotated by 270 degrees)
        #                ---|-XO|X-- (Reflected horizontally) - position 6
        #                --X|OX-|--- (Reflected vertically)
        #                X--|-X-|-O- (Reflected on left diagonal)
        #                -O-|-X-|--X (Reflected on right diagonal)
        #
        # Symmetries for --X|-XO|---:
        #                XO-|-X-|--- (Rotated by 90 degrees)
        #                ---|OX-|X-- (Rotated by 180 degrees)
        #                ---|-X-|-OX (Rotated by 270 degrees)
        #                ---|-XO|--X (Reflected horizontally) - position 8
        #                X--|OX-|--- (Reflected vertically)
        #                ---|-X-|XO- (Reflected on left diagonal)
        #                -OX|-X-|--- (Reflected on right diagonal)

        assert_get_move_is(self, self.player, self.board, 2, Board.X,
                           "---|-XO|---")
        choice_mock.assert_called_once_with([0, 2, 6, 8])
 def test_get_move_chooses_best_available_move_if_random_gte_epsilon(
         self, random_mock, choice_mock):
     random_mock.return_value = 0.1
     choice_mock.side_effect = MockRandom(0).choice
     self.player.values[get_board_state_tuple("---|-XO|---")] = 0.501
     assert_get_move_is(self, self.player, self.board, 5, Board.O,
                        "---|-X-|---")
     choice_mock.assert_called_once_with([5])
 def test_get_move_chooses_best_available_move_if_learning_disabled(
         self, random_mock, choice_mock):
     self.player.disable_learning()
     random_mock.return_value = 0.099
     choice_mock.side_effect = MockRandom(0).choice
     self.player.values[get_board_state_tuple("---|-O-|--X")] = 0.501
     assert_get_move_is(self, self.player, self.board, 4, Board.O,
                        "---|---|--X")
     random_mock.assert_not_called()
     choice_mock.assert_called_once_with([4])
 def test_get_move_chooses_random_best_available_move_if_random_gte_epsilon_and_multiple_bests(
         self, random_mock, choice_mock):
     random_mock.return_value = 0.1
     choice_mock.side_effect = MockRandom(1).choice
     self.player.values[get_board_state_tuple("X--|-XO|---")] = 0.501
     self.player.values[get_board_state_tuple("--X|-XO|---")] = 0.501
     self.player.values[get_board_state_tuple("---|-XO|X--")] = 0.501
     assert_get_move_is(self, self.player, self.board, 2, Board.X,
                        "---|-XO|---")
     choice_mock.assert_called_once_with([0, 2, 6])
    def test_get_move_chooses_best_available_move_if_random_gte_epsilon(
            self, random_mock, choice_mock):
        random_mock.return_value = 0.1
        choice_mock.side_effect = MockRandom(0).choice
        self.player.values[get_board_state_tuple(
            "---|-XO|---")] = 0.501  # Original
        # Reflected horizontally

        # Force other symmetric choices to be of lower value
        self.player.values[get_board_state_tuple(
            "-O-|-X-|---")] = 0.499  # Rotated by 90 degrees
        # Reflected on right diagonal
        self.player.values[get_board_state_tuple(
            "---|OX-|---")] = 0.499  # Rotated by 180 degrees
        # Reflected vertically
        self.player.values[get_board_state_tuple(
            "---|-X-|-O-")] = 0.499  # Rotated by 270 degrees
        # Reflected on left diagonal

        assert_get_move_is(self, self.player, self.board, 5, Board.O,
                           "---|-X-|---")
        choice_mock.assert_called_once_with([5])
 def test_get_move_returns_random_available_move(self, choice_mock):
     choice_mock.side_effect = MockRandom(5).choice
     assert_get_move_is(self, self.player, self.board, 7, Board.X,
                        "---|-XO|---")