Coverage for src/duelboard/models.py: 100%
44 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 19:18 +0900
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 19:18 +0900
1"""Data models for Elo rating calculations."""
3from dataclasses import dataclass
4from enum import Enum
6from .types import Metadata
9class BattleOutcome(Enum):
10 """Battle outcome enum."""
12 WIN_A = "player_a"
13 WIN_B = "player_b"
14 TIE = "tie"
15 TIE_BOTHBAD = "tie (bothbad)"
18@dataclass
19class Battle:
20 """Represents a battle between two players."""
22 player_a: str
23 player_b: str
24 outcome: BattleOutcome
25 metadata: Metadata | None = None
27 def __post_init__(self) -> None:
28 if isinstance(self.outcome, str):
29 self.outcome = BattleOutcome(self.outcome)
32@dataclass
33class Player:
34 """Represents a player in the rating system."""
36 name: str
37 rating: float = 1000.0
38 battles: int = 0
39 wins: int = 0
40 losses: int = 0
41 ties: int = 0
43 @property
44 def win_rate(self) -> float:
45 """Calculate win rate."""
46 if self.battles == 0:
47 return 0.0
48 return self.wins / self.battles
51@dataclass
52class EloRating:
53 """Represents an Elo rating result."""
55 player: str
56 rating: float
57 confidence_interval: tuple[float, float] | None = None
58 battles: int = 0
60 def __lt__(self, other: "EloRating") -> bool:
61 return self.rating < other.rating
63 def __le__(self, other: "EloRating") -> bool:
64 return self.rating <= other.rating
66 def __gt__(self, other: "EloRating") -> bool:
67 return self.rating > other.rating
69 def __ge__(self, other: "EloRating") -> bool:
70 return self.rating >= other.rating