def test_last_piece_in_empty_bin_only_steals_if_opponent_has_pieces(
        player, opponent):
    board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 0, 2], goal=12),
        opponent: PlayerRow(bins=[1, 6, 7, 0, 3, 7], goal=3),
    })
    new_board = take_turn(board, Turn(player, 5))
    assert new_board[player] == PlayerRow(bins=[0, 10, 0, 1, 1, 0], goal=12)
    assert new_board[opponent] == PlayerRow(bins=[1, 6, 7, 0, 3, 7], goal=3)
示例#2
0
def test_example_random_player_strategy_chooses_valid_bins():
    random_strategy = ExampleRandomPlayerStrategy()

    for i in range(6):
        one_nonempty_bin_row = PlayerRow(
            bins=[1 if i == j else 0 for j in range(6)], goal=20)
        assert random_strategy.choose_bin(one_nonempty_bin_row) == i

    semi_empty_bin_row = PlayerRow(bins=[1, 0, 1, 0, 1, 0], goal=15)
    assert random_strategy.choose_bin(semi_empty_bin_row) in [0, 2, 4]
def test_serialization_returns_correct_serialization_for_boards():
    p1 = Player.ONE
    p1_row = PlayerRow.get_new_player_row()
    p2 = Player.TWO
    p2_row = PlayerRow.get_new_player_row()
    board = Board({p1: p1_row, p2: p2_row})
    assert to_serializable(board) == {
        to_serializable(p1): to_serializable(p1_row),
        to_serializable(p2): to_serializable(p2_row),
    }
def test_double_wrap_turn_that_ends_in_goal(player, opponent):
    turn = Turn(player, 0)
    board = Board({
        player: PlayerRow(bins=[14, 0, 0, 0, 2, 0], goal=10),
        opponent: PlayerRow(bins=[1, 6, 4, 0, 1, 7], goal=3),
    })

    new_board = take_turn(board, turn)

    assert new_board[player] == PlayerRow(bins=[1, 1, 1, 1, 3, 1], goal=12)
    assert new_board[opponent] == PlayerRow(bins=[2, 7, 5, 1, 2, 8], goal=3)
def test_double_wrap_turn(player, opponent):
    turn = Turn(player, 1)
    board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 2, 0], goal=12),
        opponent: PlayerRow(bins=[1, 6, 8, 0, 2, 7], goal=3),
    })

    new_board = take_turn(board, turn)

    assert new_board[player] == PlayerRow(bins=[1, 0, 0, 0, 3, 1], goal=13)
    assert new_board[opponent] == PlayerRow(bins=[2, 7, 9, 1, 3, 8], goal=3)
示例#6
0
def test_even_goal_strategy_chooses_bin_with_goal_making_moves():
    even_goal_strategy = EvenGoalOrPiecesOnOtherSideStrategy()

    for i in range(6):
        chosen_bin = even_goal_strategy.choose_bin(
            PlayerRow(bins=[(i + 1) if i == j else 0 for j in range(6)],
                      goal=0))
        assert chosen_bin == i

    documentation_example_row = PlayerRow(bins=[4, 0, 3, 8, 1, 0], goal=5)
    assert even_goal_strategy.choose_bin(documentation_example_row) == 2
def test_triple_wrap_turn(player, opponent):
    turn = Turn(player, 0)
    board = Board({
        player: PlayerRow(bins=[16, 1, 5, 0, 5, 2], goal=6),
        opponent: PlayerRow(bins=[0, 2, 1, 2, 1, 0], goal=7),
    })

    new_board = take_turn(board, turn)

    assert new_board[player] == PlayerRow(bins=[1, 2, 6, 1, 6, 3], goal=8)
    assert new_board[opponent] == PlayerRow(bins=[1, 3, 2, 3, 3, 2], goal=7)
def test_player_row_requires_non_negative_entries():
    with pytest.raises(ValueError):
        PlayerRow(bins=[-1 for _ in range(NUMBER_OF_BINS)], goal=0)

    with pytest.raises(ValueError):
        PlayerRow(
            bins=[NUMBER_OF_STARTING_PIECES for _ in range(NUMBER_OF_BINS)],
            goal=-1,
        )

    assert PlayerRow(bins=[0 for _ in range(NUMBER_OF_BINS)],
                     goal=0) is not None
示例#9
0
def test_always_maximum_player_strategy_chooses_bin_with_least_pieces():
    always_max_strategy = AlwaysMaximumPlayerStrategy()

    for i in range(6):
        one_nonempty_bin_row = PlayerRow(
            bins=[1 if i == j else 0 for j in range(6)], goal=20)
        assert always_max_strategy.choose_bin(one_nonempty_bin_row) == i

    all_ones_row = PlayerRow(bins=[1, 1, 1, 1, 1, 1], goal=15)
    assert always_max_strategy.choose_bin(all_ones_row) == 0

    two_sixes_at_end_of_row = PlayerRow(bins=[1, 0, 4, 3, 6, 6], goal=7)
    assert always_max_strategy.choose_bin(two_sixes_at_end_of_row) == 4
def test_player_row_needs_number_of_bins_equal_to_game_config():
    with pytest.raises(ValueError):
        PlayerRow(bins=[], goal=0)

    with pytest.raises(ValueError):
        PlayerRow(
            bins=[
                NUMBER_OF_STARTING_PIECES for _ in range(NUMBER_OF_BINS + 1)
            ],
            goal=0,
        )

    assert (PlayerRow(
        bins=[NUMBER_OF_STARTING_PIECES for _ in range(NUMBER_OF_BINS)],
        goal=0,
    ) is not None)
def test_player_row_provides_convenience_function_for_new_row():
    assert hasattr(PlayerRow, "get_new_player_row")
    new_player_row = PlayerRow.get_new_player_row()
    assert new_player_row.bins == [
        NUMBER_OF_STARTING_PIECES for _ in range(NUMBER_OF_BINS)
    ]
    assert new_player_row.goal == 0
def test_get_new_game_board_provides_new_player_rows():
    new_board = get_new_board()
    assert Player.ONE in new_board.keys() and Player.TWO in new_board.keys()
    assert all([
        player_row == PlayerRow.get_new_player_row()
        for player_row in new_board.values()
    ])
def test_last_piece_in_empty_bin_steals_opponents_pieces(player, opponent):
    """
    The idea here is that if a player takes a turn that results
    in their last piece landing in a previously empty bin on their side,
    then the player gets to steal the pieces in the same bin on their
    opponents side. Both the last piece that landed in the previously empty
    bin and their opponents pieces go into the player's goal.
    """
    board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 0, 2], goal=12),
        opponent: PlayerRow(bins=[1, 6, 7, 1, 2, 7], goal=3),
    })

    # In-player row scenario
    in_player_row_board = take_turn(board, Turn(player, 5))
    assert in_player_row_board[player] == PlayerRow(bins=[0, 10, 0, 0, 1, 0],
                                                    goal=14)
    assert in_player_row_board[opponent] == PlayerRow(bins=[1, 6, 7, 0, 2, 7],
                                                      goal=3)

    # Double-wrap scenario
    double_wrap_board = take_turn(board, Turn(player, 1))
    assert double_wrap_board[player] == PlayerRow(bins=[1, 0, 0, 0, 0, 3],
                                                  goal=17)
    assert double_wrap_board[opponent] == PlayerRow(bins=[2, 7, 8, 2, 0, 8],
                                                    goal=3)
def test_player_row_provides_method_to_add_pieces_to_goal():
    player_row = PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0)
    player_row.add_pieces_to_goal(5)
    assert player_row.goal == 5

    player_row.add_pieces_to_goal(3)
    assert player_row.goal == 8
def test_player_row_provides_method_to_pieces_to_bins():
    player_row = PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0)
    for b in range(len(player_row.bins)):
        player_row.add_piece_in_bin(b)
        assert player_row.bins[b] == 5

        player_row.add_piece_in_bin(b)
        assert player_row.bins[b] == 6
def test_player_row_cannot_add_non_positive_pieces_to_goal():
    player_row = PlayerRow.get_new_player_row()
    with pytest.raises(ValueError):
        player_row.add_pieces_to_goal(-1)
    with pytest.raises(ValueError):
        player_row.add_pieces_to_goal(0)
def test_player_row_add_pieces_to_goal_defaults_to_one():
    player_row = PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0)
    player_row.add_pieces_to_goal()
    assert player_row.goal == 1
def test_get_new_game_board_provides_new_player_rows():
    new_board = get_new_board()
    assert Player.ONE in new_board.keys() and Player.TWO in new_board.keys()
    assert all([
        player_row == PlayerRow.get_new_player_row()
        for player_row in new_board.values()
    ])


@pytest.mark.parametrize(
    "selected_bin,players_result_row,opponents_result_row",
    [
        (
            0,
            PlayerRow([0, 4, 4, 4, 4, 4], 1),
            PlayerRow([4, 4, 4, 5, 5, 5], 0),
        ),
        (
            1,
            PlayerRow([5, 0, 4, 4, 4, 4], 1),
            PlayerRow([4, 4, 4, 4, 5, 5], 0),
        ),
        (
            2,
            PlayerRow([5, 5, 0, 4, 4, 4], 1),
            PlayerRow([4, 4, 4, 4, 4, 5], 0),
        ),
        (
            3,
            PlayerRow([5, 5, 5, 0, 4, 4], 1),
    def run(self, reset_simulation=False) -> None:  # pragma: nocover
        if self.has_run and not reset_simulation:
            return
        if reset_simulation:
            self._reset_simulation()

        current_player = self._starting_player
        current_turn = 0
        while True:
            # Set up objects for current player on this turn
            current_board = self._boards[current_turn]
            current_player_row = current_board[current_player]
            current_player_strategy = self._strategies[current_player]
            current_opponent_row = current_board[
                Player.ONE if current_player == Player.TWO else Player.TWO]

            # Allow current player to select a bin from their row, and ensure it is valid
            try:
                selected_bin = current_player_strategy.choose_bin(
                    current_player_row, current_opponent_row)
            except ValueError:
                # Assuming ValueError is thrown if player can't move, i.e. all bins are empty
                if all([b == 0 for b in current_player_row.bins]):
                    player_one_row = current_board[Player.ONE]
                    player_two_row = current_board[Player.TWO]

                    resulting_player_one_goal = (sum(player_one_row.bins) +
                                                 player_one_row.goal)
                    resulting_player_two_goal = (sum(player_two_row.bins) +
                                                 player_two_row.goal)
                    new_board = Board({
                        Player.ONE:
                        PlayerRow(bins=[0, 0, 0, 0, 0, 0],
                                  goal=resulting_player_one_goal),
                        Player.TWO:
                        PlayerRow(bins=[0, 0, 0, 0, 0, 0],
                                  goal=resulting_player_two_goal),
                    })
                    # self._turns.append(Turn.GameEndingTurn)  TODO
                    self._boards.append(new_board)
                    if resulting_player_one_goal > resulting_player_two_goal:
                        self._winning_player = Player.ONE
                    elif resulting_player_one_goal < resulting_player_two_goal:
                        self._winning_player = Player.TWO
                    else:
                        self._winning_player = None  # tie
                    self._has_run = True
                    break

            if current_player_row.bins[selected_bin] == 0:
                raise ValueError(
                    "Player strategies need to ensure they pick non-empty bins in 'choose_bin'"
                )

            # Perform turn with selected bin and save simulation data
            turn = Turn(current_player, selected_bin)
            new_board = take_turn(current_board, turn)
            self._turns.append(turn)
            self._boards.append(new_board)

            # Check if game has ended; otherwise, update who is up next
            if self._is_end_of_game():
                self._set_winner()
                self._has_run = True
                break
            current_player = who_gets_next_turn(current_board, turn, new_board)
            current_turn += 1
示例#20
0
def test_even_goal_stealing_shedding_requires_opponent_row():
    strategy = EvenGoalStealAndPiecesOnOtherSideStrategy()
    with pytest.raises(ValueError):
        strategy.choose_bin(player_row=PlayerRow.get_new_player_row())
def test_who_gets_next_turn_returns_correct_player(player, opponent):
    # player makes optimal first game move to get another turn
    prior_board = Board({
        player: PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0),
        opponent: PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0),
    })
    turn = Turn(player, 3)
    new_board = Board({
        player: PlayerRow(bins=[5, 5, 5, 0, 4, 4], goal=1),
        opponent: PlayerRow.get_new_player_row(),
    })
    assert who_gets_next_turn(prior_board, turn, new_board) == player

    # player makes a move to steal pieces from opponent
    prior_board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 0, 2], goal=12),
        opponent: PlayerRow(bins=[1, 6, 7, 1, 2, 7], goal=3),
    })
    turn = Turn(player, 5)
    new_board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 1, 0], goal=14),
        opponent: PlayerRow(bins=[1, 6, 7, 0, 2, 7], goal=3),
    })
    assert who_gets_next_turn(prior_board, turn, new_board) == opponent

    # player makes double-wrap move to steal pieces from opponent
    prior_board = Board({
        player: PlayerRow(bins=[0, 10, 0, 0, 0, 2], goal=12),
        opponent: PlayerRow(bins=[1, 6, 7, 1, 2, 7], goal=3),
    })
    turn = Turn(player, 1)
    new_board = Board({
        player: PlayerRow(bins=[1, 0, 0, 0, 0, 3], goal=17),
        opponent: PlayerRow(bins=[2, 7, 8, 2, 0, 8], goal=3),
    })
    assert who_gets_next_turn(prior_board, turn, new_board) == opponent

    # player makes double-wrap move and ends in goal
    prior_board = Board({
        player: PlayerRow(bins=[14, 0, 0, 0, 2, 0], goal=10),
        opponent: PlayerRow(bins=[1, 6, 4, 0, 1, 7], goal=3),
    })
    turn = Turn(player, 0)
    new_board = Board({
        player: PlayerRow(bins=[1, 1, 1, 1, 3, 1], goal=12),
        opponent: PlayerRow(bins=[2, 7, 5, 1, 2, 8], goal=3),
    })
    assert who_gets_next_turn(prior_board, turn, new_board) == player
def test_player_row_add_pieces_to_bin_must_be_correct_bin_selection():
    new_player_row = PlayerRow.get_new_player_row()
    with pytest.raises(ValueError):
        new_player_row.add_piece_in_bin(-1)
    with pytest.raises(ValueError):
        new_player_row.add_piece_in_bin(NUMBER_OF_BINS)
def test_player_row_provides_nice_representation():
    new_player_row = PlayerRow.get_new_player_row()
    assert repr(new_player_row) == "[  0 |  4,  4,  4,  4,  4,  4 ]"

    player_row = PlayerRow([12, 0, 1, 9, 10, 4], goal=10)
    assert repr(player_row) == "[ 10 | 12,  0,  1,  9, 10,  4 ]"
def test_serialize_returns_type_error_for_unregistered_type():
    class NewType:
        pass

    with pytest.raises(TypeError):
        to_serializable(NewType())


@pytest.mark.parametrize(
    "serializable,serialized",
    [
        (None, None),
        (Player.ONE, "one"),
        (Player.TWO, "two"),
        (
            PlayerRow.get_new_player_row(),
            {
                "bins": PlayerRow.get_new_player_row().bins,
                "goal": PlayerRow.get_new_player_row().goal,
            },
        ),
        (Turn(Player.ONE, 4), {
            "player": "one",
            "selected_bin": 4
        }),
        (Turn(Player.TWO, 2), {
            "player": "two",
            "selected_bin": 2
        }),
    ],
)
示例#25
0
def test_even_goal_strategy_chooses_bin_with_max_opponent_pieces(
        bins, expected_selection):
    even_goal_strategy = EvenGoalOrPiecesOnOtherSideStrategy()
    assert (even_goal_strategy.choose_bin(PlayerRow(
        bins=bins, goal=0)) == expected_selection)
def test_player_row_provides_equality_operations():
    player_row = PlayerRow(bins=[1, 2, 3, 4, 5, 6], goal=7)
    identical_player_row = PlayerRow(bins=[1, 2, 3, 4, 5, 6], goal=7)
    assert player_row == identical_player_row
    assert player_row != PlayerRow(bins=[6, 5, 4, 3, 2, 1], goal=7)
    assert player_row != 42
示例#27
0
        ([0, 0, 0, 0, 0, 1], 5),
    ],
)
def test_even_goal_strategy_chooses_bin_with_max_opponent_pieces(
        bins, expected_selection):
    even_goal_strategy = EvenGoalOrPiecesOnOtherSideStrategy()
    assert (even_goal_strategy.choose_bin(PlayerRow(
        bins=bins, goal=0)) == expected_selection)


@pytest.mark.parametrize(
    "boards,expected_selection",
    [
        (
            Board({
                Player.ONE: PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0),
                Player.TWO: PlayerRow(bins=[4, 4, 4, 4, 4, 4], goal=0),
            }),
            3,
        ),
        (
            Board({
                Player.ONE: PlayerRow(bins=[0, 6, 7, 2, 0, 5], goal=4),
                Player.TWO: PlayerRow(bins=[0, 5, 6, 7, 1, 6], goal=2),
            }),
            1,
        ),
        (
            Board({
                Player.ONE: PlayerRow(bins=[1, 8, 2, 4, 2, 0], goal=7),
                Player.TWO: PlayerRow(bins=[1, 6, 8, 0, 2, 7], goal=3),
示例#28
0
def test_player_strategy_raises_error_for_no_choices(strategy):
    with pytest.raises(ValueError):
        strategy.choose_bin(PlayerRow(bins=[0, 0, 0, 0, 0, 0], goal=10))