tie-break for narrative points

This commit is contained in:
Maxime Réaux 2026-03-03 11:52:07 +01:00
parent d72c9902d4
commit 53b1fc916c
8 changed files with 194 additions and 17 deletions

View file

@ -6,7 +6,7 @@ from warchron.constants import ContextType
from warchron.model.exception import ForbiddenOperation
from warchron.model.war import War
from warchron.model.war_event import InfluenceSpent, TieResolved
from warchron.model.score_service import ScoreService
from warchron.model.score_service import ScoreService, ParticipantScore
@dataclass
@ -85,6 +85,61 @@ class TieResolver:
)
return ties
@staticmethod
def find_campaign_objective_ties(
war: War,
campaign_id: str,
objective_id: str,
) -> List[TieContext]:
base_scores = ScoreService.compute_scores(
war,
ContextType.CAMPAIGN,
campaign_id,
)
scores = TieResolver._build_objective_scores(
base_scores,
objective_id,
)
buckets: DefaultDict[int, List[str]] = defaultdict(list)
for pid, score in scores.items():
buckets[score.victory_points].append(pid)
ties: List[TieContext] = []
context_id = f"{campaign_id}:{objective_id}"
for score_value, participants in buckets.items():
if len(participants) <= 1:
continue
if TieResolver.is_tie_resolved(
war,
ContextType.OBJECTIVE,
context_id,
score_value,
):
continue
if not TieResolver.can_tie_be_resolved(
war,
ContextType.OBJECTIVE,
context_id,
participants,
):
war.events.append(
TieResolved(
None,
ContextType.OBJECTIVE,
context_id,
score_value,
)
)
continue
ties.append(
TieContext(
context_type=ContextType.OBJECTIVE,
context_id=context_id,
participants=participants,
score_value=score_value,
)
)
return ties
@staticmethod
def find_war_ties(war: War) -> List[TieContext]:
from warchron.model.result_checker import ResultChecker
@ -115,6 +170,79 @@ class TieResolver:
)
return ties
@staticmethod
def find_war_objective_ties(
war: War,
objective_id: str,
) -> List[TieContext]:
from warchron.model.result_checker import ResultChecker
base_scores = ScoreService.compute_scores(
war,
ContextType.WAR,
war.id,
)
scores = TieResolver._build_objective_scores(
base_scores,
objective_id,
)
ranking = ResultChecker.get_effective_ranking(
war,
ContextType.OBJECTIVE,
f"{war.id}:{objective_id}",
scores,
)
ties: List[TieContext] = []
for _, group, _ in ranking:
if len(group) <= 1:
continue
score_value = scores[group[0]].victory_points
context_id = f"{war.id}:{objective_id}"
if TieResolver.is_tie_resolved(
war,
ContextType.OBJECTIVE,
context_id,
score_value,
):
continue
if not TieResolver.can_tie_be_resolved(
war,
ContextType.OBJECTIVE,
context_id,
group,
):
war.events.append(
TieResolved(
None,
ContextType.OBJECTIVE,
context_id,
score_value,
)
)
continue
ties.append(
TieContext(
context_type=ContextType.OBJECTIVE,
context_id=context_id,
participants=group,
score_value=score_value,
)
)
return ties
@staticmethod
def _build_objective_scores(
base_scores: Dict[str, ParticipantScore],
objective_id: str,
) -> Dict[str, ParticipantScore]:
return {
pid: ParticipantScore(
victory_points=score.narrative_points.get(objective_id, 0),
narrative_points={},
)
for pid, score in base_scores.items()
}
@staticmethod
def apply_bids(
war: War,