fix choice tiebreak loop and cancel tiebreak lost tokens

This commit is contained in:
Maxime Réaux 2026-03-17 11:16:47 +01:00
parent a3b9f5a943
commit 42ad708e77
13 changed files with 333 additions and 129 deletions

View file

@ -167,7 +167,7 @@ class CampaignController:
def resolve_ties(
self, war: War, contexts: List[TieContext]
) -> Dict[tuple[str, str, int | None], Dict[str, bool]]:
) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]:
bids_map = {}
for ctx in contexts:
active = TieResolver.get_active_participants(war, ctx, ctx.participants)
@ -180,7 +180,7 @@ class CampaignController:
parent=self.app.view,
players=players,
counters=counters,
context_type=ContextType.CAMPAIGN,
context_type=ctx.context_type,
context_id=ctx.context_id,
context_name=None,
)
@ -192,7 +192,7 @@ class CampaignController:
counters=counters,
context_type=ctx.context_type,
context_id=ctx.context_id,
context_name=objective.name,
context_name=f"Objective tie: {objective.name}",
)
if not dialog.exec():
TieResolver.cancel_tie_break(war, ctx)

View file

@ -1,4 +1,5 @@
from typing import TYPE_CHECKING
from uuid import uuid4
if TYPE_CHECKING:
from warchron.controller.app_controller import AppController
@ -25,8 +26,9 @@ class RoundClosureWorkflow(ClosureWorkflow):
bids_map = self.app.rounds.resolve_ties(war, ties)
for tie in ties:
bids = bids_map[tie.key()]
TieResolver.apply_bids(war, tie, bids)
TieResolver.resolve_tie_state(war, tie, bids)
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_battle_ties(war, round.id)
for battle in round.battles.values():
ClosureService.apply_battle_outcomes(war, campaign, battle)
@ -42,8 +44,9 @@ class CampaignClosureWorkflow(ClosureWorkflow):
bids_map = self.app.campaigns.resolve_ties(war, ties)
for tie in ties:
bids = bids_map[tie.key()]
TieResolver.apply_bids(war, tie, bids)
TieResolver.resolve_tie_state(war, tie, bids)
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_campaign_ties(war, campaign.id)
for obj in war.get_objectives_used_as_maj_or_min():
objective_id = obj.id
@ -56,8 +59,9 @@ class CampaignClosureWorkflow(ClosureWorkflow):
bids_map = self.app.campaigns.resolve_ties(war, ties)
for tie in ties:
bids = bids_map[tie.key()]
TieResolver.apply_bids(war, tie, bids)
TieResolver.resolve_tie_state(war, tie, bids)
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_campaign_objective_ties(
war,
campaign.id,
@ -75,8 +79,9 @@ class WarClosureWorkflow(ClosureWorkflow):
bids_map = self.app.wars.resolve_ties(war, ties)
for tie in ties:
bids = bids_map[tie.key()]
TieResolver.apply_bids(war, tie, bids)
TieResolver.resolve_tie_state(war, tie, bids)
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_war_ties(war)
for obj in war.get_objectives_used_as_maj_or_min():
objective_id = obj.id
@ -88,8 +93,9 @@ class WarClosureWorkflow(ClosureWorkflow):
bids_map = self.app.wars.resolve_ties(war, ties)
for tie in ties:
bids = bids_map[tie.key()]
TieResolver.apply_bids(war, tie, bids)
TieResolver.resolve_tie_state(war, tie, bids)
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_war_objective_ties(
war,
objective_id,
@ -103,7 +109,7 @@ class RoundPairingWorkflow:
self.app = controller
def start(self, war: War, round: Round) -> None:
Pairing.check_round_pairable(round)
Pairing.check_round_pairable(war, round)
Pairing.assign_battles_to_participants(
war,
round,

View file

@ -72,6 +72,7 @@ class RoundController:
comment=choice.comment,
)
)
# TODO display allocated sectors and used token
self.app.view.display_round_choices(choices_for_display)
battles_for_display: List[BattleDTO] = []
for sect in sectors:
@ -89,6 +90,7 @@ class RoundController:
player_1_name = self.app.model.get_participant_name(
camp_part.war_participant_id
)
p1_id = battle.player_1_id
else:
player_1_name = ""
if battle.player_2_id:
@ -96,6 +98,7 @@ class RoundController:
player_2_name = self.app.model.get_participant_name(
camp_part.war_participant_id
)
p2_id = battle.player_2_id
else:
player_2_name = ""
if battle.winner_id:
@ -112,7 +115,11 @@ class RoundController:
if battle.is_draw():
p1_icon = Icons.get(IconName.DRAW)
p2_icon = Icons.get(IconName.DRAW)
context = TieContext(ContextType.BATTLE, battle.sector_id)
context = TieContext(
ContextType.BATTLE,
battle.sector_id,
[p1_id, p2_id],
)
if TieResolver.was_tie_broken_by_tokens(war, context):
effective_winner = ResultChecker.get_effective_winner_id(
war, ContextType.BATTLE, battle.sector_id, None
@ -197,7 +204,7 @@ class RoundController:
str(e),
)
for bat in rnd.battles.values():
bat.cleanup_battle_players()
bat.clear_battle_players()
return
except DomainError as e:
QMessageBox.warning(
@ -225,7 +232,7 @@ class RoundController:
def resolve_ties(
self, war: War, contexts: List[TieContext]
) -> Dict[tuple[str, str, int | None], Dict[str, bool]]:
) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]:
bids_map = {}
for ctx in contexts:
players = [
@ -236,11 +243,12 @@ class RoundController:
for pid in ctx.participants
]
counters = [war.get_influence_tokens(pid) for pid in ctx.participants]
# TODO display sector name for BATTLE or CHOICE
dialog = TieDialog(
parent=self.app.view,
players=players,
counters=counters,
context_type=ContextType.BATTLE,
context_type=ctx.context_type,
context_id=ctx.context_id,
)
if not dialog.exec():

View file

@ -58,7 +58,7 @@ class WarController:
]
scores = ScoreService.compute_scores(war, ContextType.WAR, war.id)
rows: List[WarParticipantScoreDTO] = []
vp_icon_map: dict[str, QIcon] = {}
vp_icon_map: Dict[str, QIcon] = {}
objective_icon_maps: Dict[str, Dict[str, QIcon]] = {}
if war.is_over:
vp_icon_map = RankingIcon.compute_icons(
@ -157,7 +157,7 @@ class WarController:
def resolve_ties(
self, war: War, contexts: List[TieContext]
) -> Dict[tuple[str, str, int | None], Dict[str, bool]]:
) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]:
bids_map = {}
for ctx in contexts:
active = TieResolver.get_active_participants(
@ -174,7 +174,7 @@ class WarController:
parent=self.app.view,
players=players,
counters=counters,
context_type=ContextType.WAR,
context_type=ctx.context_type,
context_id=ctx.context_id,
context_name=None,
)