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)
|
objective_icons: Dict[str, QIcon] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TieDialogData:
|
|
||||||
title: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WarSettingsDTO:
|
class WarSettingsDTO:
|
||||||
major_value: int
|
major_value: int
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from PyQt6.QtGui import QIcon
|
from PyQt6.QtGui import QIcon
|
||||||
|
|
||||||
|
|
@ -11,16 +12,20 @@ from warchron.constants import (
|
||||||
ScoreKind,
|
ScoreKind,
|
||||||
)
|
)
|
||||||
|
|
||||||
from warchron.controller.dtos import TieDialogData
|
|
||||||
from warchron.model.tiebreaking import TieContext, TieBreaker
|
from warchron.model.tiebreaking import TieContext, TieBreaker
|
||||||
from warchron.model.war import War
|
from warchron.model.war import War
|
||||||
from warchron.model.campaign import Campaign
|
from warchron.model.campaign import Campaign
|
||||||
from warchron.model.round import Round
|
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.checking import ResultChecker
|
||||||
from warchron.model.exception import DomainError
|
from warchron.model.exception import DomainError
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TieDialogData:
|
||||||
|
title: str
|
||||||
|
|
||||||
|
|
||||||
class Presenter:
|
class Presenter:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -30,17 +35,16 @@ class Presenter:
|
||||||
campaign: Campaign | None = None,
|
campaign: Campaign | None = None,
|
||||||
round: Round | None = None,
|
round: Round | None = None,
|
||||||
) -> TieDialogData:
|
) -> TieDialogData:
|
||||||
# TODO display Nth place
|
if ctx.context_type in (ContextType.WAR, ContextType.CAMPAIGN):
|
||||||
if ctx.context_type == ContextType.WAR:
|
rank = Presenter._get_tie_rank(war, ctx)
|
||||||
if ctx.objective_id:
|
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]
|
obj = war.objectives[ctx.objective_id]
|
||||||
return TieDialogData(f"War objective tie — {obj.name}")
|
return TieDialogData(
|
||||||
return TieDialogData("War tie")
|
f"{level} objective tie for {rank_label} — {obj.name}"
|
||||||
if ctx.context_type == ContextType.CAMPAIGN:
|
)
|
||||||
if ctx.objective_id:
|
return TieDialogData(f"{level} tie for {rank_label}")
|
||||||
obj = war.objectives[ctx.objective_id]
|
|
||||||
return TieDialogData(f"Campaign objective tie — {obj.name}")
|
|
||||||
return TieDialogData("Campaign tie")
|
|
||||||
if ctx.context_type == ContextType.BATTLE:
|
if ctx.context_type == ContextType.BATTLE:
|
||||||
if campaign:
|
if campaign:
|
||||||
sector = campaign.sectors[ctx.context_id]
|
sector = campaign.sectors[ctx.context_id]
|
||||||
|
|
@ -177,3 +181,57 @@ class Presenter:
|
||||||
compute_icon(battle.player_1_id),
|
compute_icon(battle.player_1_id),
|
||||||
compute_icon(battle.player_2_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")
|
raise DomainError("Campaign not found")
|
||||||
match_counts = Pairing.build_match_count(campaign)
|
match_counts = Pairing.build_match_count(campaign)
|
||||||
available_battles = round.get_battles_with_places()
|
available_battles = round.get_battles_with_places()
|
||||||
|
# FIXME no error when all participants allocated
|
||||||
if not available_battles:
|
if not available_battles:
|
||||||
raise DomainError("No available battle remaining")
|
raise DomainError("No available battle remaining")
|
||||||
occupancy = {
|
occupancy = {
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class Ui_tieDialog(object):
|
||||||
|
|
||||||
def retranslateUi(self, tieDialog):
|
def retranslateUi(self, tieDialog):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
tieDialog.setWindowTitle(_translate("tieDialog", "Tie"))
|
tieDialog.setWindowTitle(_translate("tieDialog", "Tie-break"))
|
||||||
self.tieContext.setText(_translate("tieDialog", "Battle tie"))
|
self.tieContext.setText(_translate("tieDialog", "Battle tie"))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Tie</string>
|
<string>Tie-break</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon">
|
||||||
<iconset>
|
<iconset>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue