display tiebreak place
This commit is contained in:
parent
c144845376
commit
a3144dc3c9
5 changed files with 73 additions and 19 deletions
|
|
@ -135,11 +135,6 @@ class WarParticipantScoreDTO:
|
|||
objective_icons: Dict[str, QIcon] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TieDialogData:
|
||||
title: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class WarSettingsDTO:
|
||||
major_value: int
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from typing import Dict
|
||||
from dataclasses import dataclass
|
||||
|
||||
from PyQt6.QtGui import QIcon
|
||||
|
||||
|
|
@ -11,16 +12,20 @@ from warchron.constants import (
|
|||
ScoreKind,
|
||||
)
|
||||
|
||||
from warchron.controller.dtos import TieDialogData
|
||||
from warchron.model.tiebreaking import TieContext, TieBreaker
|
||||
from warchron.model.war import War
|
||||
from warchron.model.campaign import Campaign
|
||||
from warchron.model.round import Round
|
||||
from warchron.model.scoring import ParticipantScore
|
||||
from warchron.model.scoring import ParticipantScore, ScoreComputer
|
||||
from warchron.model.checking import ResultChecker
|
||||
from warchron.model.exception import DomainError
|
||||
|
||||
|
||||
@dataclass
|
||||
class TieDialogData:
|
||||
title: str
|
||||
|
||||
|
||||
class Presenter:
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -30,17 +35,16 @@ class Presenter:
|
|||
campaign: Campaign | None = None,
|
||||
round: Round | None = None,
|
||||
) -> TieDialogData:
|
||||
# TODO display Nth place
|
||||
if ctx.context_type == ContextType.WAR:
|
||||
if ctx.objective_id:
|
||||
if ctx.context_type in (ContextType.WAR, ContextType.CAMPAIGN):
|
||||
rank = Presenter._get_tie_rank(war, ctx)
|
||||
rank_label = Presenter._build_rank_label(rank)
|
||||
level = str(ctx.context_type).capitalize()
|
||||
if ctx.objective_id is not None:
|
||||
obj = war.objectives[ctx.objective_id]
|
||||
return TieDialogData(f"War objective tie — {obj.name}")
|
||||
return TieDialogData("War tie")
|
||||
if ctx.context_type == ContextType.CAMPAIGN:
|
||||
if ctx.objective_id:
|
||||
obj = war.objectives[ctx.objective_id]
|
||||
return TieDialogData(f"Campaign objective tie — {obj.name}")
|
||||
return TieDialogData("Campaign tie")
|
||||
return TieDialogData(
|
||||
f"{level} objective tie for {rank_label} — {obj.name}"
|
||||
)
|
||||
return TieDialogData(f"{level} tie for {rank_label}")
|
||||
if ctx.context_type == ContextType.BATTLE:
|
||||
if campaign:
|
||||
sector = campaign.sectors[ctx.context_id]
|
||||
|
|
@ -177,3 +181,57 @@ class Presenter:
|
|||
compute_icon(battle.player_1_id),
|
||||
compute_icon(battle.player_2_id),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _ordinal(n: int) -> str:
|
||||
if 10 <= n % 100 <= 20:
|
||||
suffix = "th"
|
||||
else:
|
||||
suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
|
||||
return f"{n}{suffix}"
|
||||
|
||||
@staticmethod
|
||||
def _build_rank_label(rank: int | None) -> str:
|
||||
if rank is None:
|
||||
return ""
|
||||
return f"{Presenter._ordinal(rank)} place"
|
||||
|
||||
@staticmethod
|
||||
def _get_tie_rank(
|
||||
war: War,
|
||||
ctx: TieContext,
|
||||
) -> int | None:
|
||||
from warchron.model.checking import ResultChecker
|
||||
|
||||
scores = ScoreComputer.compute_scores(
|
||||
war,
|
||||
ctx.context_type,
|
||||
ctx.context_id,
|
||||
)
|
||||
if ctx.objective_id is None:
|
||||
|
||||
def value_getter(score: ParticipantScore) -> int:
|
||||
return score.victory_points
|
||||
|
||||
score_kind = ScoreKind.VP
|
||||
else:
|
||||
obj_id = ctx.objective_id
|
||||
|
||||
def value_getter(score: ParticipantScore) -> int:
|
||||
return score.narrative_points.get(obj_id, 0)
|
||||
|
||||
score_kind = ScoreKind.NP
|
||||
ranking = ResultChecker.get_effective_ranking(
|
||||
war,
|
||||
ctx.context_type,
|
||||
ctx.context_id,
|
||||
score_kind,
|
||||
scores,
|
||||
value_getter,
|
||||
ctx.objective_id,
|
||||
)
|
||||
tied = set(ctx.participants)
|
||||
for rank, group, _ in ranking:
|
||||
if tied.intersection(group):
|
||||
return rank
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ class Pairing:
|
|||
raise DomainError("Campaign not found")
|
||||
match_counts = Pairing.build_match_count(campaign)
|
||||
available_battles = round.get_battles_with_places()
|
||||
# FIXME no error when all participants allocated
|
||||
if not available_battles:
|
||||
raise DomainError("No available battle remaining")
|
||||
occupancy = {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class Ui_tieDialog(object):
|
|||
|
||||
def retranslateUi(self, tieDialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
tieDialog.setWindowTitle(_translate("tieDialog", "Tie"))
|
||||
tieDialog.setWindowTitle(_translate("tieDialog", "Tie-break"))
|
||||
self.tieContext.setText(_translate("tieDialog", "Battle tie"))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tie</string>
|
||||
<string>Tie-break</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue