"""Tracks how the player behaves across loops. The point of this module is not scoring. It is to give the game a small model of the player's habits so the narration can quietly react to them: the corridor that "remembers you." """ from __future__ import annotations from dataclasses import dataclass, field, asdict from typing import Dict, Optional @dataclass class PlayerMemory: # progress level: int = 0 # which hallway you are standing in (0 = the start) best_level: int = 0 # furthest you have ever reached loops: int = 0 # total corridors walked this run # behaviour turn_backs: int = 0 continues: int = 0 false_reports: int = 0 # turned back when nothing was wrong missed: int = 0 # walked on past a real change inspects: Dict[str, int] = field(default_factory=dict) # confidence confidence_sum: float = 0.0 confidence_n: int = 0 def record_inspect(self, thing: str) -> None: self.inspects[thing] = self.inspects.get(thing, 0) + 1 def record_confidence(self, value: Optional[int]) -> None: if value: self.confidence_sum += value self.confidence_n += 1 @property def confidence(self) -> float: if not self.confidence_n: return 0.0 return round(self.confidence_sum / self.confidence_n, 2) @property def favorite(self) -> Optional[str]: """The property the player fixates on, once a habit has formed.""" if not self.inspects: return None thing, count = max(self.inspects.items(), key=lambda kv: kv[1]) return thing if count >= 3 else None def to_dict(self) -> dict: return asdict(self) @classmethod def from_dict(cls, data: dict) -> "PlayerMemory": if not data: return cls() known = {f: data[f] for f in cls.__dataclass_fields__ if f in data} return cls(**known)