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)