choice tie-break and random fallback + exception cleanup + war<->camp pid
This commit is contained in:
parent
241d7f10f5
commit
241e76c937
15 changed files with 241 additions and 157 deletions
|
|
@ -3,7 +3,7 @@ from dataclasses import dataclass, field
|
|||
from collections import defaultdict
|
||||
|
||||
from warchron.constants import ContextType, ScoreKind
|
||||
from warchron.model.exception import ForbiddenOperation
|
||||
from warchron.model.exception import ForbiddenOperation, DomainError
|
||||
from warchron.model.war import War
|
||||
from warchron.model.war_event import InfluenceSpent, TieResolved
|
||||
from warchron.model.score_service import ScoreService, ParticipantScore
|
||||
|
|
@ -17,6 +17,7 @@ class TieContext:
|
|||
score_value: int | None = None
|
||||
score_kind: ScoreKind | None = None
|
||||
objective_id: str | None = None
|
||||
sector_id: str | None = None
|
||||
|
||||
def key(self) -> tuple[str, str, int | None]:
|
||||
return (self.context_type, self.context_id, self.score_value)
|
||||
|
|
@ -24,71 +25,6 @@ class TieContext:
|
|||
|
||||
class TieResolver:
|
||||
|
||||
@staticmethod
|
||||
def find_choice_ties(
|
||||
war: War,
|
||||
round_id: str,
|
||||
) -> List[TieContext]:
|
||||
round = war.get_round(round_id)
|
||||
campaign = war.get_campaign_by_round(round_id)
|
||||
if campaign is None:
|
||||
raise RuntimeError("Round without campaign")
|
||||
ties: List[TieContext] = []
|
||||
scores = ScoreService.compute_scores(
|
||||
war,
|
||||
ContextType.CAMPAIGN,
|
||||
campaign.id,
|
||||
)
|
||||
score_groups = ScoreService.group_participants_by_score(
|
||||
scores, lambda score: score.victory_points
|
||||
)
|
||||
sector_to_battle = {b.sector_id: b for b in round.battles.values()}
|
||||
for group in score_groups:
|
||||
if len(group) <= 1:
|
||||
continue
|
||||
demand: Dict[str, List[str]] = {}
|
||||
for pid in group:
|
||||
choice = round.choices.get(pid)
|
||||
if not choice:
|
||||
continue
|
||||
for sec_id in (
|
||||
choice.priority_sector_id,
|
||||
choice.secondary_sector_id,
|
||||
):
|
||||
if sec_id:
|
||||
demand.setdefault(sec_id, []).append(pid)
|
||||
for sector_id, demanders in demand.items():
|
||||
battle = sector_to_battle.get(sector_id)
|
||||
if battle is None:
|
||||
continue
|
||||
places = len(battle.get_available_places())
|
||||
if len(demanders) <= places:
|
||||
continue
|
||||
context = TieContext(
|
||||
ContextType.CHOICE,
|
||||
round_id,
|
||||
demanders,
|
||||
score_value=None,
|
||||
score_kind=ScoreKind.VP,
|
||||
)
|
||||
if TieResolver.is_tie_resolved(war, context):
|
||||
continue
|
||||
if not TieResolver.can_tie_be_resolved(
|
||||
war,
|
||||
context,
|
||||
demanders,
|
||||
):
|
||||
war.events.append(
|
||||
TieResolved(
|
||||
None,
|
||||
ContextType.CHOICE,
|
||||
round_id,
|
||||
)
|
||||
)
|
||||
continue
|
||||
ties.append(context)
|
||||
return ties
|
||||
|
||||
@staticmethod
|
||||
def find_battle_ties(war: War, round_id: str) -> List[TieContext]:
|
||||
round = war.get_round(round_id)
|
||||
|
|
@ -104,12 +40,12 @@ class TieResolver:
|
|||
if TieResolver.is_tie_resolved(war, context):
|
||||
continue
|
||||
if campaign is None:
|
||||
raise RuntimeError("No campaign for this battle tie")
|
||||
raise DomainError("No campaign for this battle tie")
|
||||
if battle.player_1_id is None or battle.player_2_id is None:
|
||||
raise RuntimeError("Missing player(s) in this battle context.")
|
||||
p1 = campaign.participants[battle.player_1_id].war_participant_id
|
||||
p2 = campaign.participants[battle.player_2_id].war_participant_id
|
||||
if not TieResolver.can_tie_be_resolved(war, context, [p1, p2]):
|
||||
raise DomainError("Missing player(s) in this battle context.")
|
||||
p1_id = campaign.campaign_to_war_part_id(battle.player_1_id)
|
||||
p2_id = campaign.campaign_to_war_part_id(battle.player_2_id)
|
||||
if not TieResolver.can_tie_be_resolved(war, context, [p1_id, p2_id]):
|
||||
war.events.append(
|
||||
TieResolved(None, ContextType.BATTLE, battle.sector_id)
|
||||
)
|
||||
|
|
@ -118,7 +54,7 @@ class TieResolver:
|
|||
TieContext(
|
||||
context_type=ContextType.BATTLE,
|
||||
context_id=battle.sector_id,
|
||||
participants=[p1, p2],
|
||||
participants=[p1_id, p2_id],
|
||||
score_value=None,
|
||||
score_kind=None,
|
||||
)
|
||||
|
|
@ -240,8 +176,8 @@ class TieResolver:
|
|||
ContextType.WAR,
|
||||
war.id,
|
||||
[],
|
||||
score_value,
|
||||
ScoreKind.VP,
|
||||
score_value=score_value,
|
||||
score_kind=ScoreKind.VP,
|
||||
)
|
||||
if TieResolver.is_tie_resolved(war, context):
|
||||
continue
|
||||
|
|
@ -427,15 +363,15 @@ class TieResolver:
|
|||
context,
|
||||
context.participants,
|
||||
)
|
||||
# confirmed draw if non had bid
|
||||
# confirmed draw if none had bid
|
||||
if not active:
|
||||
war.events.append(
|
||||
TieResolved(
|
||||
None,
|
||||
context.context_type,
|
||||
context.context_id,
|
||||
context.score_value,
|
||||
context.objective_id,
|
||||
score_value=context.score_value,
|
||||
objective_id=context.objective_id,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
|
@ -446,8 +382,8 @@ class TieResolver:
|
|||
None,
|
||||
context.context_type,
|
||||
context.context_id,
|
||||
context.score_value,
|
||||
context.objective_id,
|
||||
score_value=context.score_value,
|
||||
objective_id=context.objective_id,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue