Exemple #1
0
    def test_invalid_state(example_statement: Statement) -> None:
        """Should return None for inconsistent states."""
        start_state = SolverState((frozenset({Role.VILLAGER}),) * 3, path=(True,))

        invalid_state = start_state.is_consistent(example_statement)

        assert invalid_state is None
Exemple #2
0
    def test_is_consistent_on_empty_state(
        example_small_solverstate: SolverState, example_statement: Statement
    ) -> None:
        """
        Should check a new statement against an empty SolverState for consistency.
        """
        start_state = SolverState()

        result = start_state.is_consistent(example_statement)

        assert result == example_small_solverstate
Exemple #3
0
def example_medium_solved_list(
    medium_game_roles: tuple[Role, ...]
) -> tuple[SolverState, ...]:
    possible_roles_1 = (
        frozenset({Role.SEER}),
        frozenset({Role.ROBBER, Role.TROUBLEMAKER, Role.WOLF, Role.DRUNK, Role.MINION}),
        frozenset({Role.DRUNK}),
        frozenset({Role.ROBBER}),
        frozenset({Role.ROBBER, Role.TROUBLEMAKER, Role.WOLF, Role.DRUNK, Role.MINION}),
        frozenset(
            {
                Role.ROBBER,
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.SEER,
                Role.MINION,
            }
        ),
    )
    possible_roles_2 = (
        frozenset({Role.ROBBER, Role.TROUBLEMAKER, Role.WOLF, Role.DRUNK, Role.MINION}),
        frozenset({Role.WOLF}),
        frozenset({Role.DRUNK}),
        frozenset({Role.ROBBER}),
        frozenset({Role.SEER}),
        frozenset(
            {
                Role.ROBBER,
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.SEER,
                Role.MINION,
            }
        ),
    )
    return (
        SolverState(
            possible_roles_1,
            ((SwitchPriority.DRUNK, 2, 5), (SwitchPriority.ROBBER, 3, 2)),
            (True, False, True, True, False),
        ),
        SolverState(
            possible_roles_2,
            ((SwitchPriority.DRUNK, 2, 5), (SwitchPriority.ROBBER, 3, 2)),
            (False, False, True, True, True),
        ),
    )
Exemple #4
0
    def test_repr() -> None:
        """Should pretty-print SolverStates using the custom formatter."""
        result = SolverState((frozenset({Role.VILLAGER}),), path=(True,))

        assert (
            str(result)
            == repr(result)
            == (
                "SolverState(\n"
                "    possible_roles=(frozenset([Role.VILLAGER]),),\n"
                "    path=(True,),\n"
                "    role_counts={\n"
                "        Role.INSOMNIAC: 1,\n"
                "        Role.VILLAGER: 2,\n"
                "        Role.ROBBER: 1,\n"
                "        Role.DRUNK: 1,\n"
                "        Role.WOLF: 2,\n"
                "        Role.SEER: 1,\n"
                "        Role.TANNER: 1,\n"
                "        Role.MASON: 2,\n"
                "        Role.MINION: 1,\n"
                "        Role.TROUBLEMAKER: 1,\n"
                "        Role.HUNTER: 1\n"
                "    },\n"
                "    count_true=1\n"
                ")"
            )
        )
Exemple #5
0
    def test_solver_medium_known_true(
        medium_statement_list: tuple[Statement, ...],
        medium_game_roles: tuple[Role, ...],
    ) -> None:
        """Should return a SolverState with the most likely solution."""
        possible_roles = (
            frozenset({
                Role.DRUNK, Role.MINION, Role.TROUBLEMAKER, Role.WOLF,
                Role.ROBBER
            }),
            frozenset({Role.SEER}),
            frozenset({Role.DRUNK}),
            frozenset({Role.MINION}),
            frozenset({
                Role.DRUNK, Role.MINION, Role.TROUBLEMAKER, Role.WOLF,
                Role.ROBBER
            }),
            frozenset({
                Role.ROBBER,
                Role.MINION,
                Role.TROUBLEMAKER,
                Role.SEER,
                Role.WOLF,
                Role.DRUNK,
            }),
        )

        result = solvers.relaxed_solver(medium_statement_list, (1, ))

        assert (SolverState(
            possible_roles,
            ((SwitchPriority.DRUNK, 2, 5), ),
            (False, True, True, False, False),
        ) in result)
Exemple #6
0
    def test_get_empty_switch_dict(small_game_roles: tuple[Role, ...]) -> None:
        """Should return the identity switch dict."""
        possible_roles = (frozenset({Role.ROBBER, Role.VILLAGER, Role.SEER}),) * 3
        state = SolverState(possible_roles)

        result = predictions.get_switch_dict(state)

        assert result == {i: i for i in range(const.NUM_ROLES)}
Exemple #7
0
def example_small_solverstate_solved(small_game_roles: tuple[Role, ...]) -> SolverState:
    possible_roles = (
        frozenset({Role.VILLAGER}),
        frozenset({Role.ROBBER}),
        frozenset({Role.SEER}),
    )
    return SolverState(
        possible_roles, ((SwitchPriority.ROBBER, 1, 2),), (True, True, True)
    )
Exemple #8
0
    def test_is_consistent_on_existing_state(
        example_medium_solverstate: SolverState,
    ) -> None:
        """
        Should check a new statement against accumulated statements for consistency.
        Should not change result.path - that is done in the switching_solver function.
        """
        possible_roles = (frozenset({Role.SEER}),) + (const.ROLE_SET,) * (
            const.NUM_ROLES - 1
        )
        example_solverstate = SolverState(possible_roles, path=(True,))
        new_statement = Statement(
            "next", ((2, frozenset({Role.DRUNK})),), ((SwitchPriority.DRUNK, 2, 5),)
        )

        result = example_solverstate.is_consistent(new_statement)

        assert result == example_medium_solverstate
Exemple #9
0
def example_small_solverstate(small_game_roles: tuple[Role, ...]) -> SolverState:
    possible_roles = (
        frozenset({Role.SEER}),
        frozenset({Role.ROBBER, Role.VILLAGER, Role.SEER}),
        frozenset({Role.ROBBER}),
    )
    return SolverState(
        possible_roles,
        ((SwitchPriority.ROBBER, 2, 0),),
        (True,),
        role_counts={Role.VILLAGER: 1, Role.SEER: 0, Role.ROBBER: 0},
    )
Exemple #10
0
    def test_is_consistent_deepcopy_mechanics(
        example_medium_solverstate: SolverState,
    ) -> None:
        """
        Modifying one SolverState should not affect
        other SolverStates created by is_consistent.
        """
        possible_roles = (frozenset({Role.SEER}),) + (const.ROLE_SET,) * (
            const.NUM_ROLES - 1
        )
        example = SolverState(possible_roles, path=(True,))
        new_statement = Statement(
            "next", ((2, frozenset({Role.DRUNK})),), ((SwitchPriority.DRUNK, 2, 5),)
        )

        result = example.is_consistent(new_statement)
        example.possible_roles += (frozenset({Role.NONE}),)
        example.switches += ((SwitchPriority.DRUNK, 5, 5),)
        example.possible_roles = (example.possible_roles[0] & {Role.NONE},)

        assert result == example_medium_solverstate
Exemple #11
0
    def test_eq(example_small_solverstate: SolverState) -> None:
        """Should be able to compare two identical SolverStates."""
        possible_roles = (
            frozenset({Role.SEER}),
            frozenset({Role.ROBBER, Role.VILLAGER, Role.SEER}),
            frozenset({Role.ROBBER}),
        )
        switches = ((SwitchPriority.ROBBER, 2, 0),)
        path = (True,)

        result = SolverState(possible_roles, switches, path)

        assert result == example_small_solverstate
Exemple #12
0
    def test_empty_unrestricted_prediction(medium_game_roles: tuple[Role, ...]) -> None:
        """Should return an empty list to denote that no prediction could be made."""
        solution = SolverState()

        result = predictions.make_unrestricted_prediction(solution)

        assert result == (
            Role.TROUBLEMAKER,
            Role.DRUNK,
            Role.WOLF,
            Role.SEER,
            Role.ROBBER,
            Role.MINION,
        )
Exemple #13
0
def expectimax(
    player_obj: Any,
    expected_statements: dict[int, tuple[Statement, ...]],
    statement_list: tuple[Statement, ...],
    state: SolverState,
    ind: int,
) -> tuple[float, Statement | None]:
    """
    Runs expectimax on the list of statements and current state up to a max depth.
    """
    if (
        ind == const.NUM_PLAYERS
        or ind - player_obj.player_index == const.EXPECTIMAX_DEPTH
    ):
        return player_obj.eval_fn(statement_list), None

    next_statements = player_obj.statements

    # Randomly choose a subset of the expected player statements and get expected value
    # of remaining statements. Adjust sample size based on const.BRANCH_FACTOR.
    if ind != player_obj.player_index:
        sample_size = const.BRANCH_FACTOR * player_obj.player_index
        indices = random.sample(range(len(expected_statements[ind])), sample_size)
        next_statements = [expected_statements[ind][i] for i in sorted(indices)]

    # Evaluate current state (value of consistent statements) and return values.
    vals = []
    for statement in next_statements:
        # If you are a Wolf, let yourself be inconsistent (each state needs a value).
        new_state = state if player_obj.is_evil() else state.is_consistent(statement)
        if new_state is not None:
            val, _ = expectimax(
                player_obj,
                expected_statements,
                statement_list + (statement,),
                new_state,
                ind + 1,
            )
            vals.append(val)

    if not vals:
        return 10, None

    # Choose your own move to maximize val
    if ind == player_obj.player_index:
        max_value = max(vals)
        best_indices = [index for index, value in enumerate(vals) if value == max_value]
        return max_value, player_obj.statements[random.choice(best_indices)]

    return sum(vals) / len(vals), None
Exemple #14
0
    def test_get_role_counts() -> None:
        """
        Should return True if there is a a dict with counts of all certain roles.
        """
        set_roles(Role.WOLF, Role.SEER, Role.VILLAGER, Role.ROBBER, Role.VILLAGER)
        possible_roles_list = (
            frozenset({Role.VILLAGER}),
            frozenset({Role.SEER}),
            frozenset({Role.VILLAGER}),
        ) + (const.ROLE_SET,) * 2

        result = SolverState(possible_roles_list).get_role_counts()

        assert result == {Role.SEER: 0, Role.VILLAGER: 0, Role.WOLF: 1, Role.ROBBER: 1}
Exemple #15
0
def example_medium_solverstate(medium_game_roles: tuple[Role, ...]) -> SolverState:
    possible_roles = (
        frozenset({Role.SEER}),
        frozenset(
            {
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.ROBBER,
                Role.SEER,
                Role.MINION,
            }
        ),
        frozenset({Role.DRUNK}),
        frozenset(
            {
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.ROBBER,
                Role.SEER,
                Role.MINION,
            }
        ),
        frozenset(
            {
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.ROBBER,
                Role.SEER,
                Role.MINION,
            }
        ),
        frozenset(
            {
                Role.TROUBLEMAKER,
                Role.WOLF,
                Role.DRUNK,
                Role.ROBBER,
                Role.SEER,
                Role.MINION,
            }
        ),
    )
    return SolverState(possible_roles, ((SwitchPriority.DRUNK, 2, 5),), (True, True))
Exemple #16
0
def example_large_solverstate(large_game_roles: tuple[Role, ...]) -> SolverState:
    possible_roles = (
        frozenset({Role.ROBBER}),
        frozenset(
            {
                Role.SEER,
                Role.HUNTER,
                Role.DRUNK,
                Role.TANNER,
                Role.WOLF,
                Role.INSOMNIAC,
                Role.MASON,
                Role.MINION,
                Role.VILLAGER,
                Role.TROUBLEMAKER,
            }
        ),
        frozenset({Role.SEER}),
        frozenset({Role.VILLAGER}),
        frozenset({Role.MASON}),
        frozenset({Role.MASON}),
        frozenset({Role.DRUNK}),
        frozenset(
            {
                Role.SEER,
                Role.HUNTER,
                Role.DRUNK,
                Role.TANNER,
                Role.WOLF,
                Role.INSOMNIAC,
                Role.MASON,
                Role.MINION,
                Role.VILLAGER,
                Role.TROUBLEMAKER,
            }
        ),
    ) + (const.ROLE_SET,) * 7
    switches = ((SwitchPriority.ROBBER, 6, 0), (SwitchPriority.ROBBER, 9, 6))
    path = (True, False, True, True, True, True, True, False)
    return SolverState(possible_roles, switches, path)
Exemple #17
0
def example_medium_solverstate_solved(
    medium_game_roles: tuple[Role, ...]
) -> SolverState:
    possible_roles = (
        frozenset({Role.SEER}),
        frozenset({Role.ROBBER, Role.DRUNK, Role.WOLF, Role.TROUBLEMAKER, Role.MINION}),
        frozenset({Role.DRUNK}),
        frozenset({Role.ROBBER}),
        frozenset({Role.ROBBER, Role.DRUNK, Role.WOLF, Role.TROUBLEMAKER, Role.MINION}),
        frozenset(
            {
                Role.DRUNK,
                Role.ROBBER,
                Role.SEER,
                Role.WOLF,
                Role.TROUBLEMAKER,
                Role.MINION,
            }
        ),
    )
    switches = ((SwitchPriority.DRUNK, 2, 5), (SwitchPriority.ROBBER, 3, 2))
    path = (True, False, True, True, False)
    return SolverState(possible_roles, switches, path)
Exemple #18
0
    def test_constructor() -> None:
        """Should initialize a SolverState."""
        result = SolverState((frozenset({Role.VILLAGER}),), path=(True,))

        assert isinstance(result, SolverState)