Files
dotfiles/tests/gems/test_modules.py
Richie add7a6a848
treefmt / nix fmt (pull_request) Successful in 6s
test ebook search / test-ebook-search (pull_request) Successful in 39s
pytest / pytest (pull_request) Successful in 40s
build_systems / build-brain (pull_request) Successful in 1m0s
build_systems / build-bob (pull_request) Successful in 1m2s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m33s
build_systems / build-jeeves (pull_request) Successful in 2m25s
test ebook search / test-ebook-search (push) Successful in 35s
build_systems / build-brain (push) Successful in 37s
build_systems / build-bob (push) Successful in 37s
build_systems / build-jeeves (push) Successful in 2m17s
treefmt / nix fmt (push) Successful in 5s
pytest / pytest (push) Successful in 29s
build_systems / build-rhapsody-in-green (push) Successful in 49s
feat(gems): add multiplayer gem game with custom content packs
- implement FastAPI and HTMX lobby and game interfaces
- support up to four human and AI-controlled players
- add configurable rules, victory conditions, and expansion modules
- support validated JSON cards, patrons, objectives, and outposts
2026-07-22 20:47:03 -04:00

61 lines
2.5 KiB
Python

from __future__ import annotations
from python.gems.domain.engine import bonuses, new_game
from python.gems.domain.models import GameSettings, Modules, OwnedCard, Requirement, RequirementKind, ResourceDefinition
from python.gems.domain.requirements import requirements_met
def test_any_color_requirements_can_be_distinct() -> None:
requirements = [
Requirement(id="first", kind=RequirementKind.ANY_COLOR, count=2),
Requirement(id="second", kind=RequirementKind.ANY_COLOR, count=2, distinct_from=["first"]),
]
assert requirements_met(requirements, {"pearl": 2, "wave": 2})
assert not requirements_met(requirements, {"pearl": 3, "wave": 1})
def test_light_resource_colors_use_dark_token_lettering() -> None:
light = ResourceDefinition(id="light", label="Light", symbol="W", color="#f4f2ed")
gold = ResourceDefinition(id="gold", label="Gold", symbol="Au", color="#d9a928")
dark = ResourceDefinition(id="dark", label="Dark", symbol="B", color="#151719")
assert light.ink_color == "#111111"
assert gold.ink_color == "#ffffff"
assert dark.ink_color == "#ffffff"
def test_standard_resources_store_conventional_symbols() -> None:
"""Standard gem labels normalize legacy abbreviations in pack data."""
standard = {
"Onyx": "O",
"Sapphire": "S",
"Emerald": "E",
"Ruby": "R",
"Diamond": "D",
"Gold": "G",
}
for label, expected in standard.items():
resource = ResourceDefinition(id=label.casefold(), label=label, symbol="?", color="#334455")
assert resource.symbol == expected
custom = ResourceDefinition(id="pearl", label="Pearl", symbol="P", color="#334455")
assert custom.symbol == "P"
def test_all_modules_deal_their_content(content_pack) -> None:
settings = GameSettings(modules=Modules(objectives=True, outposts=True, eastern_decks=True, fortifications=True))
state = new_game("ABCDEFGH", ["A", "B"], content_pack, settings, seed=5)
assert "eastern:1" in state.markets
assert state.available_objectives == ["goal_one"]
assert not state.available_patrons
assert state.players[0].fortifications_available == 3
def test_multi_bonus_counts_twice_but_is_one_card(content_pack) -> None:
settings = GameSettings(modules=Modules(eastern_decks=True))
state = new_game("ABCDEFGH", ["A"], content_pack, settings, seed=5)
player = state.players[0]
player.cards.append(OwnedCard(card_id="eastern_2_1"))
assert bonuses(player, content_pack)[content_pack.card("eastern_2_1").bonus_resource] == 2
assert len(player.cards) == 1