Spaces:
Running
Running
File size: 1,448 Bytes
414dc55 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | """Evidence discovery via non-interrogation channels (search / forensic / document).
Every clue in the solution's minimal set is reachable here, so solvability never
depends on a suspect choosing to talk - the discoverability guarantee in play.
"""
from __future__ import annotations
from ..schemas.case import CaseFile
from ..schemas.clue import Clue
from ..schemas.enums import DiscoveryMethod
from .game_state import GameState
from .state_update import discover_clues
_NON_INTERROGATION = frozenset(
{DiscoveryMethod.SEARCH, DiscoveryMethod.FORENSIC, DiscoveryMethod.DOCUMENT}
)
def clues_at(case: CaseFile, loc_id: str) -> tuple[Clue, ...]:
"""Clues physically discoverable by examining a location."""
return tuple(
c
for c in case.clues
if c.discoverable_at_loc_id == loc_id and c.discovery_method in _NON_INTERROGATION
)
def search_location(state: GameState, case: CaseFile, loc_id: str) -> tuple[GameState, tuple[Clue, ...]]:
found = clues_at(case, loc_id)
newly = tuple(c for c in found if c.clue_id not in state.discovered_clue_ids)
new_state = discover_clues(state, tuple(c.clue_id for c in newly), case)
return new_state, newly
def available_evidence(state: GameState, case: CaseFile) -> tuple[Clue, ...]:
"""Discovered clues the player currently holds and may present to suspects."""
return tuple(c for c in case.clues if c.clue_id in state.discovered_clue_ids)
|