factorise ranking icon mapper

This commit is contained in:
Maxime Réaux 2026-02-26 11:28:29 +01:00
parent 5a64a294c5
commit 3fe3bb331c
3 changed files with 60 additions and 80 deletions

View file

@ -1,15 +1,11 @@
from typing import List, Dict, Tuple, TYPE_CHECKING from typing import List, Dict, Tuple, TYPE_CHECKING
from PyQt6.QtWidgets import QMessageBox, QDialog from PyQt6.QtWidgets import QMessageBox, QDialog
from PyQt6.QtGui import QIcon
from warchron.constants import ( from warchron.constants import (
RefreshScope, RefreshScope,
ContextType, ContextType,
ItemType, ItemType,
Icons,
IconName,
RANK_TO_ICON,
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@ -28,8 +24,8 @@ from warchron.model.campaign_participant import CampaignParticipant
from warchron.model.sector import Sector from warchron.model.sector import Sector
from warchron.model.tie_manager import TieContext, TieResolver from warchron.model.tie_manager import TieContext, TieResolver
from warchron.model.score_service import ScoreService from warchron.model.score_service import ScoreService
from warchron.model.result_checker import ResultChecker
from warchron.controller.closure_workflow import CampaignClosureWorkflow from warchron.controller.closure_workflow import CampaignClosureWorkflow
from warchron.controller.ranking_icon import RankingIcon
from warchron.view.campaign_dialog import CampaignDialog from warchron.view.campaign_dialog import CampaignDialog
from warchron.view.campaign_participant_dialog import CampaignParticipantDialog from warchron.view.campaign_participant_dialog import CampaignParticipantDialog
from warchron.view.sector_dialog import SectorDialog from warchron.view.sector_dialog import SectorDialog
@ -40,41 +36,6 @@ class CampaignController:
def __init__(self, app: "AppController"): def __init__(self, app: "AppController"):
self.app = app self.app = app
def _compute_campaign_ranking_icons(
self, war: War, campaign: Campaign
) -> Dict[str, QIcon]:
scores = ScoreService.compute_scores(
war,
ContextType.CAMPAIGN,
campaign.id,
)
ranking = ResultChecker.get_effective_ranking(
war, ContextType.CAMPAIGN, campaign.id, scores
)
icon_map = {}
for rank, group, token_map in ranking:
base_icon = RANK_TO_ICON.get(rank, IconName.VPNTH)
vp = scores[group[0]].victory_points
original_group_size = sum(
1 for s in scores.values() if s.victory_points == vp
)
for pid in group:
spent = token_map.get(pid, 0)
if original_group_size == 1:
icon_name = base_icon
elif len(group) == 1:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}BREAK")
else:
icon_name = base_icon
else:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}TIEDRAW")
else:
icon_name = getattr(IconName, f"{base_icon.name}DRAW")
icon_map[pid] = QIcon(Icons.get_pixmap(icon_name))
return icon_map
def _fill_campaign_details(self, campaign_id: str) -> None: def _fill_campaign_details(self, campaign_id: str) -> None:
camp = self.app.model.get_campaign(campaign_id) camp = self.app.model.get_campaign(campaign_id)
self.app.view.show_campaign_details(name=camp.name, month=camp.month) self.app.view.show_campaign_details(name=camp.name, month=camp.month)
@ -98,7 +59,9 @@ class CampaignController:
rows: List[CampaignParticipantScoreDTO] = [] rows: List[CampaignParticipantScoreDTO] = []
icon_map = {} icon_map = {}
if camp.is_over: if camp.is_over:
icon_map = self._compute_campaign_ranking_icons(war, camp) icon_map = RankingIcon.compute_icons(
war, ContextType.CAMPAIGN, campaign_id, scores
)
for camp_part in camp.get_all_campaign_participants(): for camp_part in camp.get_all_campaign_participants():
war_part_id = camp_part.war_participant_id war_part_id = camp_part.war_participant_id
war_part = war.get_war_participant(war_part_id) war_part = war.get_war_participant(war_part_id)

View file

@ -0,0 +1,54 @@
from typing import Dict
from PyQt6.QtGui import QIcon
from warchron.constants import (
ContextType,
Icons,
IconName,
RANK_TO_ICON,
)
from warchron.model.war import War
from warchron.model.score_service import ParticipantScore
from warchron.model.result_checker import ResultChecker
class RankingIcon:
@staticmethod
def compute_icons(
war: War,
context_type: ContextType,
context_id: str,
scores: Dict[str, ParticipantScore],
) -> Dict[str, QIcon]:
# scores = ScoreService.compute_scores(
# war,
# context_type,
# context_id,
# )
ranking = ResultChecker.get_effective_ranking(
war, context_type, context_id, scores
)
icon_map = {}
for rank, group, token_map in ranking:
base_icon = RANK_TO_ICON.get(rank, IconName.VPNTH)
vp = scores[group[0]].victory_points
original_group_size = sum(
1 for s in scores.values() if s.victory_points == vp
)
for pid in group:
spent = token_map.get(pid, 0)
if original_group_size == 1:
icon_name = base_icon
elif len(group) == 1:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}BREAK")
else:
icon_name = base_icon
else:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}TIEDRAW")
else:
icon_name = getattr(IconName, f"{base_icon.name}DRAW")
icon_map[pid] = QIcon(Icons.get_pixmap(icon_name))
return icon_map

View file

@ -1,15 +1,11 @@
from typing import List, Tuple, TYPE_CHECKING, Dict from typing import List, Tuple, TYPE_CHECKING, Dict
from PyQt6.QtWidgets import QMessageBox, QDialog from PyQt6.QtWidgets import QMessageBox, QDialog
from PyQt6.QtGui import QIcon
from warchron.constants import ( from warchron.constants import (
RefreshScope, RefreshScope,
ItemType, ItemType,
ContextType, ContextType,
Icons,
IconName,
RANK_TO_ICON,
) )
from warchron.model.exception import ( from warchron.model.exception import (
DomainError, DomainError,
@ -29,8 +25,8 @@ from warchron.model.war_participant import WarParticipant
from warchron.model.objective import Objective from warchron.model.objective import Objective
from warchron.model.tie_manager import TieContext, TieResolver from warchron.model.tie_manager import TieContext, TieResolver
from warchron.model.score_service import ScoreService from warchron.model.score_service import ScoreService
from warchron.model.result_checker import ResultChecker
from warchron.controller.closure_workflow import WarClosureWorkflow from warchron.controller.closure_workflow import WarClosureWorkflow
from warchron.controller.ranking_icon import RankingIcon
from warchron.view.war_dialog import WarDialog from warchron.view.war_dialog import WarDialog
from warchron.view.objective_dialog import ObjectiveDialog from warchron.view.objective_dialog import ObjectiveDialog
from warchron.view.war_participant_dialog import WarParticipantDialog from warchron.view.war_participant_dialog import WarParticipantDialog
@ -41,39 +37,6 @@ class WarController:
def __init__(self, app: "AppController"): def __init__(self, app: "AppController"):
self.app = app self.app = app
def _compute_war_ranking_icons(self, war: War) -> Dict[str, QIcon]:
scores = ScoreService.compute_scores(
war,
ContextType.WAR,
war.id,
)
ranking = ResultChecker.get_effective_ranking(
war, ContextType.WAR, war.id, scores
)
icon_map = {}
for rank, group, token_map in ranking:
base_icon = RANK_TO_ICON.get(rank, IconName.VPNTH)
vp = scores[group[0]].victory_points
original_group_size = sum(
1 for s in scores.values() if s.victory_points == vp
)
for pid in group:
spent = token_map.get(pid, 0)
if original_group_size == 1:
icon_name = base_icon
elif len(group) == 1:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}BREAK")
else:
icon_name = base_icon
else:
if spent > 0:
icon_name = getattr(IconName, f"{base_icon.name}TIEDRAW")
else:
icon_name = getattr(IconName, f"{base_icon.name}DRAW")
icon_map[pid] = QIcon(Icons.get_pixmap(icon_name))
return icon_map
def _fill_war_details(self, war_id: str) -> None: def _fill_war_details(self, war_id: str) -> None:
war = self.app.model.get_war(war_id) war = self.app.model.get_war(war_id)
self.app.view.show_war_details(name=war.name, year=war.year) self.app.view.show_war_details(name=war.name, year=war.year)
@ -92,7 +55,7 @@ class WarController:
rows: List[WarParticipantScoreDTO] = [] rows: List[WarParticipantScoreDTO] = []
icon_map = {} icon_map = {}
if war.is_over: if war.is_over:
icon_map = self._compute_war_ranking_icons(war) icon_map = RankingIcon.compute_icons(war, ContextType.WAR, war_id, scores)
for war_part in war.get_all_war_participants(): for war_part in war.get_all_war_participants():
player_name = self.app.model.get_player_name(war_part.player_id) player_name = self.app.model.get_player_name(war_part.player_id)
score = scores[war_part.id] score = scores[war_part.id]