From f5ad45f671ffce4bdeff48ef1f96d41ca3a58e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20R=C3=A9aux?= Date: Thu, 19 Mar 2026 11:25:40 +0100 Subject: [PATCH] raise exception on choice/battle constrained update/delete --- src/warchron/model/pairing.py | 26 +++++---------- src/warchron/model/round.py | 63 ++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/warchron/model/pairing.py b/src/warchron/model/pairing.py index d2c8f88..fed5234 100644 --- a/src/warchron/model/pairing.py +++ b/src/warchron/model/pairing.py @@ -47,15 +47,6 @@ class Pairing: raise DomainError( "There are not enough sectors for all participants to battle" ) - for pid, choice in round.choices.items(): - if choice is not None and not choice.priority_sector_id: - raise ForbiddenOperation( - f"Missing priority choice for participant {pid}" - ) - if choice is not None and not choice.secondary_sector_id: - raise ForbiddenOperation( - f"Missing secondary choice for participant {pid}" - ) def cleanup() -> None: for bat in round.battles.values(): @@ -74,6 +65,15 @@ class Pairing: "Do you want to continue?", action=cleanup, ) + for pid, choice in round.choices.items(): + if choice is not None and not choice.priority_sector_id: + raise ForbiddenOperation( + f"Missing priority choice for participant {pid}" + ) + if choice is not None and not choice.secondary_sector_id: + raise ForbiddenOperation( + f"Missing secondary choice for participant {pid}" + ) @staticmethod def assign_battles_to_participants( @@ -226,10 +226,6 @@ class Pairing: ) or len(active) <= places ): - print( - f"Natural or acceptable draw for sector {sector_id} with participants:\n", - context.participants, - ) war.events.append( TieResolved( None, @@ -246,10 +242,6 @@ class Pairing: bids = bids_map[current_context.key()] # confirmed draw if current bids are 0 if bids is not None and not any(bids.values()): - print( - f"Confirmed draw for sector {sector_id} with participants:\n", - context.participants, - ) war.events.append( TieResolved( None, diff --git a/src/warchron/model/round.py b/src/warchron/model/round.py index a7b4363..f0db6e2 100644 --- a/src/warchron/model/round.py +++ b/src/warchron/model/round.py @@ -5,7 +5,11 @@ from typing import Any, Dict, List, TYPE_CHECKING if TYPE_CHECKING: from warchron.model.campaign import Campaign from warchron.model.war import War -from warchron.model.exception import ForbiddenOperation +from warchron.model.exception import ( + ForbiddenOperation, + DomainError, + RequiresConfirmation, +) from warchron.model.choice import Choice from warchron.model.battle import Battle @@ -95,7 +99,9 @@ class Round: if self.is_over: # TODO catch me if you can raise ForbiddenOperation("Can't update choice in a closed round.") - # TODO prevent if battles already assigned + if self.has_battle_with_participant(participant_id): + # TODO catch me if you can (inner) + raise ForbiddenOperation("Can't update choice already assigned to battle.") choice = self.get_choice(participant_id) if choice: choice.set_priority(priority_sector_id) @@ -120,7 +126,9 @@ class Round: if self.is_over: # TODO catch me if you can (inner) raise ForbiddenOperation("Can't remove choice in a closed round.") - # TODO prevent if battles already assigned + if self.has_battle_with_participant(participant_id): + # TODO catch me if you can (inner) + raise ForbiddenOperation("Can't remove choice already assigned to battle.") self.war.revert_choice_ties( self.id, participants=[self.campaign.campaign_to_war_part_id(participant_id)], @@ -185,12 +193,16 @@ class Round: victory_condition: str | None, comment: str | None, ) -> None: + from warchron.model.pairing import Pairing + if self.is_over: # TODO catch me if you can raise ForbiddenOperation("Can't update battle in a closed round.") bat = self.get_battle(sector_id) - # TODO require confirmation if there was choice tie to clear it - if bat: + if not bat: + raise DomainError(f"No battle found for sector {sector_id}") + + def apply_update() -> None: bat.set_player_1(player_1_id) bat.set_player_2(player_2_id) bat.set_winner(winner_id) @@ -198,6 +210,47 @@ class Round: bat.set_victory_condition(victory_condition) bat.set_comment(comment) + if bat.player_1_id == player_1_id and bat.player_2_id == player_2_id: + apply_update() + return + affected_choices: List[Choice] = [] + affected_players: List[str | None] = list( + { + player_1_id, + player_2_id, + bat.player_1_id, + bat.player_2_id, + } + - {None} + ) + for choice in self.choices.values(): + for player in affected_players: + if ( + player + and self.has_choice_with_participant(player) + and Pairing.participant_spent_token( + self.war, + self.id, + sector_id, + self.campaign.campaign_to_war_part_id(player), + ) + ): + affected_choices.append(choice) + if not affected_choices: + apply_update() + return + + def cleanup_and_update() -> None: + self.clear_sector_references(sector_id) + apply_update() + + raise RequiresConfirmation( + "Changing the player(s) of this sector will affect choices.\n" + "Choices will be cleared and their tokens and tie-breaks will be deleted.\n" + "Do you want to continue?", + action=cleanup_and_update, + ) + def clear_participant_references(self, participant_id: str) -> None: for battle in self.battles.values(): trigger_revert_ties = False