Order imports, format with ruff, make the account key constants Final so mypy --strict accepts them, and type the test helpers. Configure ruff and mypy in pyproject.toml and pin the dev tool versions. All modules, classes and functions already carry Doxygen comments; doxygen Doxyfile builds without warnings. Task: MIL-004#2 Closes #18
79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
"""@file game_logic.py
|
|
@brief Pure game functions: draw accounts, describe them, check guesses.
|
|
"""
|
|
|
|
import random
|
|
from collections.abc import Sequence
|
|
|
|
from higher_lower.constants import (
|
|
ACCOUNT_TEMPLATE,
|
|
CHOICE_A,
|
|
CHOICE_B,
|
|
KEY_COUNTRY,
|
|
KEY_DESCRIPTION,
|
|
KEY_NAME,
|
|
)
|
|
from higher_lower.game_data import Account, data
|
|
|
|
_DEFAULT_RNG = random.Random()
|
|
|
|
|
|
def get_random_account(
|
|
accounts: Sequence[Account] = data,
|
|
rng: random.Random | None = None,
|
|
) -> Account:
|
|
"""@brief Return one random account.
|
|
|
|
@param accounts The accounts to draw from.
|
|
@param rng Random generator; pass a seeded one to make the draw repeatable.
|
|
@return A random entry of accounts.
|
|
"""
|
|
return (rng or _DEFAULT_RNG).choice(accounts)
|
|
|
|
|
|
def pick_pair(
|
|
accounts: Sequence[Account] = data,
|
|
rng: random.Random | None = None,
|
|
) -> tuple[Account, Account]:
|
|
"""@brief Return two different random accounts.
|
|
|
|
@param accounts The accounts to draw from; needs at least two entries.
|
|
@param rng Random generator; pass a seeded one to make the draw repeatable.
|
|
@return The accounts A and B, never the same entry.
|
|
@throws ValueError If accounts has fewer than two entries.
|
|
"""
|
|
first, second = (rng or _DEFAULT_RNG).sample(accounts, 2)
|
|
return first, second
|
|
|
|
|
|
def format_data(account: Account) -> str:
|
|
"""@brief Describe an account for the player.
|
|
|
|
@param account The account to describe.
|
|
@return Text such as "Nike, a Sportswear multinational, from United States".
|
|
"""
|
|
return ACCOUNT_TEMPLATE.format(
|
|
name=account[KEY_NAME],
|
|
description=account[KEY_DESCRIPTION],
|
|
country=account[KEY_COUNTRY],
|
|
)
|
|
|
|
|
|
def check_answer(guess: str, a_followers: int, b_followers: int) -> bool:
|
|
"""@brief Tell whether the guess names the account with more followers.
|
|
|
|
Equal follower counts make either choice correct.
|
|
|
|
@param guess "a" or "b", in any case.
|
|
@param a_followers Follower count of account A.
|
|
@param b_followers Follower count of account B.
|
|
@return True if the guess is right.
|
|
@throws ValueError If guess is neither "a" nor "b".
|
|
"""
|
|
choice = guess.lower()
|
|
if choice == CHOICE_A:
|
|
return a_followers >= b_followers
|
|
if choice == CHOICE_B:
|
|
return b_followers >= a_followers
|
|
raise ValueError(f"guess must be {CHOICE_A!r} or {CHOICE_B!r}, got {guess!r}")
|