refacto file and class names

This commit is contained in:
Maxime Réaux 2026-03-19 15:23:50 +01:00
parent 3d0d7874e3
commit 956fa63c0b
12 changed files with 126 additions and 126 deletions

View file

@ -19,9 +19,9 @@ from warchron.model.war import War
from warchron.model.campaign import Campaign from warchron.model.campaign import Campaign
from warchron.model.campaign_participant import CampaignParticipant 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.tiebreaking import TieContext, TieBreaker
from warchron.model.score_service import ScoreService from warchron.model.scoring import ScoreComputer
from warchron.controller.closure_workflow import CampaignClosureWorkflow from warchron.controller.workflows import CampaignClosureWorkflow
from warchron.controller.presenter import Presenter from warchron.controller.presenter import Presenter
from warchron.view.campaign_dialog import CampaignDialog from warchron.view.campaign_dialog import CampaignDialog
@ -53,7 +53,7 @@ class CampaignController:
for sect in sectors for sect in sectors
] ]
self.app.view.display_campaign_sectors(sectors_for_display) self.app.view.display_campaign_sectors(sectors_for_display)
scores = ScoreService.compute_scores(war, ContextType.CAMPAIGN, campaign_id) scores = ScoreComputer.compute_scores(war, ContextType.CAMPAIGN, campaign_id)
rows: List[CampaignParticipantScoreDTO] = [] rows: List[CampaignParticipantScoreDTO] = []
vp_icon_map: Dict[str, QIcon] = {} vp_icon_map: Dict[str, QIcon] = {}
objective_icon_maps: Dict[str, Dict[str, QIcon]] = {} objective_icon_maps: Dict[str, Dict[str, QIcon]] = {}
@ -171,7 +171,7 @@ class CampaignController:
) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]: ) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]:
bids_map = {} bids_map = {}
for ctx in contexts: for ctx in contexts:
active = TieResolver.get_active_participants(war, ctx, ctx.participants) active = TieBreaker.get_active_participants(war, ctx, ctx.participants)
players = [ players = [
ParticipantOption(id=pid, name=self.app.model.get_participant_name(pid)) ParticipantOption(id=pid, name=self.app.model.get_participant_name(pid))
for pid in active for pid in active
@ -189,7 +189,7 @@ class CampaignController:
context_name=data.title, context_name=data.title,
) )
if not dialog.exec(): if not dialog.exec():
TieResolver.cancel_tie_break(war, ctx) TieBreaker.cancel_tie_break(war, ctx)
raise AbortedOperation("Tie resolution cancelled") raise AbortedOperation("Tie resolution cancelled")
bids_map[ctx.key()] = dialog.get_bids() bids_map[ctx.key()] = dialog.get_bids()
return bids_map return bids_map

View file

@ -12,12 +12,12 @@ from warchron.constants import (
) )
from warchron.controller.dtos import TieDialogData from warchron.controller.dtos import TieDialogData
from warchron.model.tie_manager import TieContext, TieResolver 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.score_service import ParticipantScore from warchron.model.scoring import ParticipantScore
from warchron.model.result_checker import ResultChecker from warchron.model.checking import ResultChecker
from warchron.model.exception import DomainError from warchron.model.exception import DomainError
@ -160,7 +160,7 @@ class Presenter:
base_icon = IconName.TIEBREAK base_icon = IconName.TIEBREAK
if base_icon is None: if base_icon is None:
return None return None
spent = TieResolver.participant_spent_token( spent = TieBreaker.participant_spent_token(
war, war,
ContextType.BATTLE, ContextType.BATTLE,
battle.sector_id, battle.sector_id,

View file

@ -17,7 +17,7 @@ from warchron.model.exception import (
DomainError, DomainError,
RequiresConfirmation, RequiresConfirmation,
) )
from warchron.model.tie_manager import TieResolver, TieContext from warchron.model.tiebreaking import TieBreaker, TieContext
from warchron.model.pairing import Pairing from warchron.model.pairing import Pairing
from warchron.model.round import Round from warchron.model.round import Round
from warchron.model.war import War from warchron.model.war import War
@ -31,7 +31,7 @@ from warchron.controller.dtos import (
ChoiceDTO, ChoiceDTO,
BattleDTO, BattleDTO,
) )
from warchron.controller.closure_workflow import ( from warchron.controller.workflows import (
RoundClosureWorkflow, RoundClosureWorkflow,
RoundPairingWorkflow, RoundPairingWorkflow,
) )
@ -274,7 +274,7 @@ class RoundController:
context_name=data.title, context_name=data.title,
) )
if not dialog.exec(): if not dialog.exec():
TieResolver.cancel_tie_break(war, ctx) TieBreaker.cancel_tie_break(war, ctx)
raise AbortedOperation("Tie resolution cancelled") raise AbortedOperation("Tie resolution cancelled")
bids_map[ctx.key()] = dialog.get_bids() bids_map[ctx.key()] = dialog.get_bids()
return bids_map return bids_map

View file

@ -24,9 +24,9 @@ from warchron.controller.dtos import (
from warchron.model.war import War from warchron.model.war import War
from warchron.model.war_participant import WarParticipant 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.tiebreaking import TieContext, TieBreaker
from warchron.model.score_service import ScoreService from warchron.model.scoring import ScoreComputer
from warchron.controller.closure_workflow import WarClosureWorkflow from warchron.controller.workflows import WarClosureWorkflow
from warchron.controller.presenter import Presenter from warchron.controller.presenter import Presenter
from warchron.view.war_dialog import WarDialog from warchron.view.war_dialog import WarDialog
@ -57,7 +57,7 @@ class WarController:
ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description) ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description)
for obj in war.get_objectives_used_as_maj_or_min() for obj in war.get_objectives_used_as_maj_or_min()
] ]
scores = ScoreService.compute_scores(war, ContextType.WAR, war.id) scores = ScoreComputer.compute_scores(war, ContextType.WAR, war.id)
rows: List[WarParticipantScoreDTO] = [] rows: List[WarParticipantScoreDTO] = []
vp_icon_map: Dict[str, QIcon] = {} vp_icon_map: Dict[str, QIcon] = {}
objective_icon_maps: Dict[str, Dict[str, QIcon]] = {} objective_icon_maps: Dict[str, Dict[str, QIcon]] = {}
@ -161,7 +161,7 @@ class WarController:
) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]: ) -> Dict[tuple[str, str, int | None, str | None, str | None], Dict[str, bool]]:
bids_map = {} bids_map = {}
for ctx in contexts: for ctx in contexts:
active = TieResolver.get_active_participants( active = TieBreaker.get_active_participants(
war, war,
ctx, ctx,
ctx.participants, ctx.participants,
@ -184,7 +184,7 @@ class WarController:
context_name=data.title, context_name=data.title,
) )
if not dialog.exec(): if not dialog.exec():
TieResolver.cancel_tie_break(war, ctx) TieBreaker.cancel_tie_break(war, ctx)
raise AbortedOperation("Tie resolution cancelled") raise AbortedOperation("Tie resolution cancelled")
bids_map[ctx.key()] = dialog.get_bids() bids_map[ctx.key()] = dialog.get_bids()
return bids_map return bids_map

View file

@ -6,51 +6,51 @@ if TYPE_CHECKING:
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.closure_service import ClosureService from warchron.model.closing import Closer
from warchron.model.tie_manager import TieResolver from warchron.model.tiebreaking import TieBreaker
from warchron.model.pairing import Pairing from warchron.model.pairing import Pairing
class ClosureWorkflow: class Workflow:
def __init__(self, controller: "AppController"): def __init__(self, controller: "AppController"):
self.app = controller self.app = controller
class RoundClosureWorkflow(ClosureWorkflow): class RoundClosureWorkflow(Workflow):
def start(self, war: War, campaign: Campaign, round: Round) -> None: def start(self, war: War, campaign: Campaign, round: Round) -> None:
ClosureService.check_round_closable(round) Closer.check_round_closable(round)
ties = TieResolver.find_battle_ties(war, round.id) ties = TieBreaker.find_battle_ties(war, round.id)
while ties: while ties:
bids_map = self.app.rounds.resolve_ties(war, ties) bids_map = self.app.rounds.resolve_ties(war, ties)
for tie in ties: for tie in ties:
bids = bids_map[tie.key()] bids = bids_map[tie.key()]
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids) TieBreaker.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids) TieBreaker.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_battle_ties(war, round.id) ties = TieBreaker.find_battle_ties(war, round.id)
for battle in round.battles.values(): for battle in round.battles.values():
ClosureService.apply_battle_outcomes(war, campaign, battle) Closer.apply_battle_outcomes(war, campaign, battle)
ClosureService.finalize_round(round) Closer.finalize_round(round)
class CampaignClosureWorkflow(ClosureWorkflow): class CampaignClosureWorkflow(Workflow):
def start(self, war: War, campaign: Campaign) -> None: def start(self, war: War, campaign: Campaign) -> None:
ClosureService.check_campaign_closable(campaign) Closer.check_campaign_closable(campaign)
ties = TieResolver.find_campaign_ties(war, campaign.id) ties = TieBreaker.find_campaign_ties(war, campaign.id)
while ties: while ties:
bids_map = self.app.campaigns.resolve_ties(war, ties) bids_map = self.app.campaigns.resolve_ties(war, ties)
for tie in ties: for tie in ties:
bids = bids_map[tie.key()] bids = bids_map[tie.key()]
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids) TieBreaker.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids) TieBreaker.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_campaign_ties(war, campaign.id) ties = TieBreaker.find_campaign_ties(war, campaign.id)
for obj in war.get_objectives_used_as_maj_or_min(): for obj in war.get_objectives_used_as_maj_or_min():
objective_id = obj.id objective_id = obj.id
ties = TieResolver.find_campaign_objective_ties( ties = TieBreaker.find_campaign_objective_ties(
war, war,
campaign.id, campaign.id,
objective_id, objective_id,
@ -59,33 +59,33 @@ class CampaignClosureWorkflow(ClosureWorkflow):
bids_map = self.app.campaigns.resolve_ties(war, ties) bids_map = self.app.campaigns.resolve_ties(war, ties)
for tie in ties: for tie in ties:
bids = bids_map[tie.key()] bids = bids_map[tie.key()]
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids) TieBreaker.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids) TieBreaker.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_campaign_objective_ties( ties = TieBreaker.find_campaign_objective_ties(
war, war,
campaign.id, campaign.id,
objective_id, objective_id,
) )
ClosureService.finalize_campaign(campaign) Closer.finalize_campaign(campaign)
class WarClosureWorkflow(ClosureWorkflow): class WarClosureWorkflow(Workflow):
def start(self, war: War) -> None: def start(self, war: War) -> None:
ClosureService.check_war_closable(war) Closer.check_war_closable(war)
ties = TieResolver.find_war_ties(war) ties = TieBreaker.find_war_ties(war)
while ties: while ties:
bids_map = self.app.wars.resolve_ties(war, ties) bids_map = self.app.wars.resolve_ties(war, ties)
for tie in ties: for tie in ties:
bids = bids_map[tie.key()] bids = bids_map[tie.key()]
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids) TieBreaker.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids) TieBreaker.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_war_ties(war) ties = TieBreaker.find_war_ties(war)
for obj in war.get_objectives_used_as_maj_or_min(): for obj in war.get_objectives_used_as_maj_or_min():
objective_id = obj.id objective_id = obj.id
ties = TieResolver.find_war_objective_ties( ties = TieBreaker.find_war_objective_ties(
war, war,
objective_id, objective_id,
) )
@ -93,14 +93,14 @@ class WarClosureWorkflow(ClosureWorkflow):
bids_map = self.app.wars.resolve_ties(war, ties) bids_map = self.app.wars.resolve_ties(war, ties)
for tie in ties: for tie in ties:
bids = bids_map[tie.key()] bids = bids_map[tie.key()]
tie_id = TieResolver.find_active_tie_id(war, tie) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, tie) or str(uuid4())
TieResolver.apply_bids(war, tie, tie_id, bids) TieBreaker.apply_bids(war, tie, tie_id, bids)
TieResolver.resolve_tie_state(war, tie, tie_id, bids) TieBreaker.resolve_tie_state(war, tie, tie_id, bids)
ties = TieResolver.find_war_objective_ties( ties = TieBreaker.find_war_objective_ties(
war, war,
objective_id, objective_id,
) )
ClosureService.finalize_war(war) Closer.finalize_war(war)
class RoundPairingWorkflow: class RoundPairingWorkflow:

View file

@ -5,10 +5,10 @@ from collections import defaultdict
from warchron.constants import ContextType, ScoreKind from warchron.constants import ContextType, ScoreKind
from warchron.model.war import War from warchron.model.war import War
from warchron.model.war_event import TieResolved from warchron.model.war_event import TieResolved
from warchron.model.tie_manager import TieResolver, TieContext from warchron.model.tiebreaking import TieBreaker, TieContext
if TYPE_CHECKING: if TYPE_CHECKING:
from warchron.model.score_service import ParticipantScore from warchron.model.scoring import ParticipantScore
class ResultChecker: class ResultChecker:
@ -75,29 +75,29 @@ class ResultChecker:
current_rank += 1 current_rank += 1
continue continue
# normal tie-break if tie persists # normal tie-break if tie persists
if not TieResolver.is_tie_resolved(war, context): if not TieBreaker.is_tie_resolved(war, context):
ranking.append( ranking.append(
(current_rank, subgroup, {pid: 0 for pid in subgroup}) (current_rank, subgroup, {pid: 0 for pid in subgroup})
) )
current_rank += 1 current_rank += 1
continue continue
groups = TieResolver.rank_by_tokens(war, context, subgroup) groups = TieBreaker.rank_by_tokens(war, context, subgroup)
tokens_spent = TieResolver.tokens_spent_map(war, context, subgroup) tokens_spent = TieBreaker.tokens_spent_map(war, context, subgroup)
for group in groups: for group in groups:
group_tokens = {pid: tokens_spent[pid] for pid in group} group_tokens = {pid: tokens_spent[pid] for pid in group}
ranking.append((current_rank, group, group_tokens)) ranking.append((current_rank, group, group_tokens))
current_rank += 1 current_rank += 1
continue continue
# no tie # no tie
if len(participants) == 1 or not TieResolver.is_tie_resolved(war, context): if len(participants) == 1 or not TieBreaker.is_tie_resolved(war, context):
ranking.append( ranking.append(
(current_rank, participants, {pid: 0 for pid in participants}) (current_rank, participants, {pid: 0 for pid in participants})
) )
current_rank += 1 current_rank += 1
continue continue
# apply token ranking # apply token ranking
groups = TieResolver.rank_by_tokens(war, context, participants) groups = TieBreaker.rank_by_tokens(war, context, participants)
tokens_spent = TieResolver.tokens_spent_map(war, context, participants) tokens_spent = TieBreaker.tokens_spent_map(war, context, participants)
for group in groups: for group in groups:
group_tokens = {pid: tokens_spent[pid] for pid in group} group_tokens = {pid: tokens_spent[pid] for pid in group}
ranking.append((current_rank, group, group_tokens)) ranking.append((current_rank, group, group_tokens))
@ -111,13 +111,13 @@ class ResultChecker:
value_getter: Callable[[ParticipantScore], int], value_getter: Callable[[ParticipantScore], int],
subcontexts: List[TieContext], subcontexts: List[TieContext],
) -> List[List[str]]: ) -> List[List[str]]:
from warchron.model.score_service import ScoreService from warchron.model.scoring import ScoreComputer
rank_map: Dict[str, Tuple[int, ...]] = {} rank_map: Dict[str, Tuple[int, ...]] = {}
for pid in participants: for pid in participants:
ranks: List[int] = [] ranks: List[int] = []
for sub in subcontexts: for sub in subcontexts:
scores = ScoreService.compute_scores( scores = ScoreComputer.compute_scores(
war, sub.context_type, sub.context_id war, sub.context_type, sub.context_id
) )
ranking = ResultChecker.get_effective_ranking( ranking = ResultChecker.get_effective_ranking(

View file

@ -9,7 +9,7 @@ from warchron.model.round import Round
from warchron.model.battle import Battle from warchron.model.battle import Battle
class ClosureService: class Closer:
# Round methods # Round methods
@ -24,7 +24,7 @@ class ClosureService:
@staticmethod @staticmethod
def apply_battle_outcomes(war: War, campaign: Campaign, battle: Battle) -> None: def apply_battle_outcomes(war: War, campaign: Campaign, battle: Battle) -> None:
from warchron.model.result_checker import ResultChecker from warchron.model.checking import ResultChecker
already_granted = any( already_granted = any(
isinstance(e, InfluenceGained) and e.context_id == battle.sector_id isinstance(e, InfluenceGained) and e.context_id == battle.sector_id

View file

@ -14,10 +14,10 @@ from warchron.model.exception import (
from warchron.model.war import War from warchron.model.war import War
from warchron.model.round import Round from warchron.model.round import Round
from warchron.model.battle import Battle from warchron.model.battle import Battle
from warchron.model.score_service import ScoreService from warchron.model.scoring import ScoreComputer
from warchron.model.tie_manager import TieResolver, TieContext from warchron.model.tiebreaking import TieBreaker, TieContext
from warchron.model.war_event import TieResolved from warchron.model.war_event import TieResolved
from warchron.model.score_service import ParticipantScore from warchron.model.scoring import ParticipantScore
ResolveTiesCallback = Callable[ ResolveTiesCallback = Callable[
["War", List["TieContext"]], ["War", List["TieContext"]],
@ -84,7 +84,7 @@ class Pairing:
campaign = war.get_campaign_by_round(round.id) campaign = war.get_campaign_by_round(round.id)
if campaign is None: if campaign is None:
raise DomainError(f"Campaign for round {round.id} doesn't exist") raise DomainError(f"Campaign for round {round.id} doesn't exist")
scores = ScoreService.compute_scores( scores = ScoreComputer.compute_scores(
war, war,
ContextType.CAMPAIGN, ContextType.CAMPAIGN,
campaign.id, campaign.id,
@ -93,7 +93,7 @@ class Pairing:
def value_getter(score: ParticipantScore) -> int: def value_getter(score: ParticipantScore) -> int:
return score.victory_points return score.victory_points
score_groups = ScoreService.group_participants_by_score(scores, value_getter) score_groups = ScoreComputer.group_participants_by_score(scores, value_getter)
sector_to_battle: Dict[str, Battle] = { sector_to_battle: Dict[str, Battle] = {
b.sector_id: b for b in round.battles.values() b.sector_id: b for b in round.battles.values()
} }
@ -206,9 +206,9 @@ class Pairing:
sector_id=sector_id, sector_id=sector_id,
) )
# ---- resolve tie loop ---- # ---- resolve tie loop ----
tie_id = TieResolver.find_active_tie_id(war, context) or str(uuid4()) tie_id = TieBreaker.find_active_tie_id(war, context) or str(uuid4())
while not TieResolver.is_tie_resolved(war, context): while not TieBreaker.is_tie_resolved(war, context):
active = TieResolver.get_active_participants( active = TieBreaker.get_active_participants(
war, context, context.participants war, context, context.participants
) )
current_context = TieContext( current_context = TieContext(
@ -221,7 +221,7 @@ class Pairing:
) )
# natural, unbreakable or acceptable (enough places) draw # natural, unbreakable or acceptable (enough places) draw
if ( if (
not TieResolver.can_tie_be_resolved( not TieBreaker.can_tie_be_resolved(
war, context, current_context.participants war, context, current_context.participants
) )
or len(active) <= places or len(active) <= places
@ -254,9 +254,9 @@ class Pairing:
) )
) )
break break
TieResolver.apply_bids(war, context, tie_id, bids) TieBreaker.apply_bids(war, context, tie_id, bids)
TieResolver.resolve_tie_state(war, context, tie_id, bids) TieBreaker.resolve_tie_state(war, context, tie_id, bids)
ranked_groups = TieResolver.rank_by_tokens( ranked_groups = TieBreaker.rank_by_tokens(
war, war,
context, context,
context.participants, context.participants,
@ -316,14 +316,14 @@ class Pairing:
raise DomainError(f"No campaign found for round {round.id}") raise DomainError(f"No campaign found for round {round.id}")
war_pid = campaign.campaign_to_war_part_id(campaign_participant_id) war_pid = campaign.campaign_to_war_part_id(campaign_participant_id)
token_priority = TieResolver.participant_spent_token( token_priority = TieBreaker.participant_spent_token(
war, war,
ContextType.CHOICE, ContextType.CHOICE,
round.id, round.id,
choice.priority_sector_id, choice.priority_sector_id,
war_pid, war_pid,
) )
token_secondary = TieResolver.participant_spent_token( token_secondary = TieBreaker.participant_spent_token(
war, war,
ContextType.CHOICE, ContextType.CHOICE,
round.id, round.id,

View file

@ -193,7 +193,7 @@ class Round:
victory_condition: str | None, victory_condition: str | None,
comment: str | None, comment: str | None,
) -> None: ) -> None:
from warchron.model.tie_manager import TieResolver from warchron.model.tiebreaking import TieBreaker
if self.is_over: if self.is_over:
raise ForbiddenOperation("Can't update battle in a closed round.") raise ForbiddenOperation("Can't update battle in a closed round.")
@ -227,7 +227,7 @@ class Round:
if ( if (
player player
and self.has_choice_with_participant(player) and self.has_choice_with_participant(player)
and TieResolver.participant_spent_token( and TieBreaker.participant_spent_token(
self.war, self.war,
ContextType.CHOICE, ContextType.CHOICE,
self.id, self.id,

View file

@ -15,7 +15,7 @@ class ParticipantScore:
narrative_points: Dict[str, int] = field(default_factory=dict) narrative_points: Dict[str, int] = field(default_factory=dict)
class ScoreService: class ScoreComputer:
@staticmethod @staticmethod
def _get_battles_for_context( def _get_battles_for_context(
@ -47,7 +47,7 @@ class ScoreService:
def compute_scores( def compute_scores(
war: War, context_type: ContextType, context_id: str war: War, context_type: ContextType, context_id: str
) -> Dict[str, ParticipantScore]: ) -> Dict[str, ParticipantScore]:
from warchron.model.result_checker import ResultChecker from warchron.model.checking import ResultChecker
if context_type == ContextType.CAMPAIGN: if context_type == ContextType.CAMPAIGN:
camp = war.get_campaign(context_id) camp = war.get_campaign(context_id)
@ -61,7 +61,7 @@ class ScoreService:
) )
for pid in participant_ids for pid in participant_ids
} }
battles = ScoreService._get_battles_for_context(war, context_type, context_id) battles = ScoreComputer._get_battles_for_context(war, context_type, context_id)
for battle in battles: for battle in battles:
base_winner = None base_winner = None
if battle.winner_id is not None: if battle.winner_id is not None:

View file

@ -6,7 +6,7 @@ from warchron.constants import ContextType, ScoreKind
from warchron.model.exception import ForbiddenOperation, DomainError from warchron.model.exception import ForbiddenOperation, DomainError
from warchron.model.war import War from warchron.model.war import War
from warchron.model.war_event import InfluenceSpent, TieResolved from warchron.model.war_event import InfluenceSpent, TieResolved
from warchron.model.score_service import ScoreService, ParticipantScore from warchron.model.scoring import ScoreComputer, ParticipantScore
@dataclass @dataclass
@ -29,7 +29,7 @@ class TieContext:
) )
class TieResolver: class TieBreaker:
@staticmethod @staticmethod
def find_active_tie_id( def find_active_tie_id(
@ -65,10 +65,10 @@ class TieResolver:
context: TieContext = TieContext( context: TieContext = TieContext(
ContextType.BATTLE, battle.sector_id, [p1_id, p2_id] ContextType.BATTLE, battle.sector_id, [p1_id, p2_id]
) )
if TieResolver.is_tie_resolved(war, context): if TieBreaker.is_tie_resolved(war, context):
continue continue
tie_id = TieResolver.find_active_tie_id(war, context) tie_id = TieBreaker.find_active_tie_id(war, context)
if not TieResolver.can_tie_be_resolved(war, context, [p1_id, p2_id]): if not TieBreaker.can_tie_be_resolved(war, context, [p1_id, p2_id]):
war.events.append( war.events.append(
TieResolved( TieResolved(
participant_id=None, participant_id=None,
@ -92,7 +92,7 @@ class TieResolver:
@staticmethod @staticmethod
def find_campaign_ties(war: War, campaign_id: str) -> List[TieContext]: def find_campaign_ties(war: War, campaign_id: str) -> List[TieContext]:
scores = ScoreService.compute_scores(war, ContextType.CAMPAIGN, campaign_id) scores = ScoreComputer.compute_scores(war, ContextType.CAMPAIGN, campaign_id)
buckets: DefaultDict[int, List[str]] = defaultdict(list) buckets: DefaultDict[int, List[str]] = defaultdict(list)
for pid, score in scores.items(): for pid, score in scores.items():
buckets[score.victory_points].append(pid) buckets[score.victory_points].append(pid)
@ -107,10 +107,10 @@ class TieResolver:
score_value, score_value,
ScoreKind.VP, ScoreKind.VP,
) )
if TieResolver.is_tie_resolved(war, context): if TieBreaker.is_tie_resolved(war, context):
continue continue
tie_id = TieResolver.find_active_tie_id(war, context) tie_id = TieBreaker.find_active_tie_id(war, context)
if not TieResolver.can_tie_be_resolved(war, context, participants): if not TieBreaker.can_tie_be_resolved(war, context, participants):
war.events.append( war.events.append(
TieResolved( TieResolved(
participant_id=None, participant_id=None,
@ -137,7 +137,7 @@ class TieResolver:
def find_campaign_objective_ties( def find_campaign_objective_ties(
war: War, campaign_id: str, objective_id: str war: War, campaign_id: str, objective_id: str
) -> List[TieContext]: ) -> List[TieContext]:
scores = ScoreService.compute_scores( scores = ScoreComputer.compute_scores(
war, war,
ContextType.CAMPAIGN, ContextType.CAMPAIGN,
campaign_id, campaign_id,
@ -159,10 +159,10 @@ class TieResolver:
ScoreKind.NP, ScoreKind.NP,
objective_id, objective_id,
) )
if TieResolver.is_tie_resolved(war, context): if TieBreaker.is_tie_resolved(war, context):
continue continue
tie_id = TieResolver.find_active_tie_id(war, context) tie_id = TieBreaker.find_active_tie_id(war, context)
if not TieResolver.can_tie_be_resolved( if not TieBreaker.can_tie_be_resolved(
war, war,
context, context,
participants, participants,
@ -193,9 +193,9 @@ class TieResolver:
@staticmethod @staticmethod
def find_war_ties(war: War) -> List[TieContext]: def find_war_ties(war: War) -> List[TieContext]:
from warchron.model.result_checker import ResultChecker from warchron.model.checking import ResultChecker
scores = ScoreService.compute_scores(war, ContextType.WAR, war.id) scores = ScoreComputer.compute_scores(war, ContextType.WAR, war.id)
ranking = ResultChecker.get_effective_ranking( ranking = ResultChecker.get_effective_ranking(
war, war,
ContextType.WAR, ContextType.WAR,
@ -216,10 +216,10 @@ class TieResolver:
score_value=score_value, score_value=score_value,
score_kind=ScoreKind.VP, score_kind=ScoreKind.VP,
) )
if TieResolver.is_tie_resolved(war, context): if TieBreaker.is_tie_resolved(war, context):
continue continue
tie_id = TieResolver.find_active_tie_id(war, context) tie_id = TieBreaker.find_active_tie_id(war, context)
if not TieResolver.can_tie_be_resolved(war, context, group): if not TieBreaker.can_tie_be_resolved(war, context, group):
war.events.append( war.events.append(
TieResolved( TieResolved(
participant_id=None, participant_id=None,
@ -244,9 +244,9 @@ class TieResolver:
@staticmethod @staticmethod
def find_war_objective_ties(war: War, objective_id: str) -> List[TieContext]: def find_war_objective_ties(war: War, objective_id: str) -> List[TieContext]:
from warchron.model.result_checker import ResultChecker from warchron.model.checking import ResultChecker
scores = ScoreService.compute_scores( scores = ScoreComputer.compute_scores(
war, war,
ContextType.WAR, ContextType.WAR,
war.id, war.id,
@ -272,13 +272,13 @@ class TieResolver:
context: TieContext = TieContext( context: TieContext = TieContext(
ContextType.WAR, war.id, [], np_value, ScoreKind.NP, objective_id ContextType.WAR, war.id, [], np_value, ScoreKind.NP, objective_id
) )
if TieResolver.is_tie_resolved( if TieBreaker.is_tie_resolved(
war, war,
context, context,
): ):
continue continue
tie_id = TieResolver.find_active_tie_id(war, context) tie_id = TieBreaker.find_active_tie_id(war, context)
if not TieResolver.can_tie_be_resolved( if not TieBreaker.can_tie_be_resolved(
war, war,
context, context,
group, group,
@ -398,7 +398,7 @@ class TieResolver:
context: TieContext, context: TieContext,
participants: List[str], participants: List[str],
) -> List[str]: ) -> List[str]:
groups = TieResolver.rank_by_tokens(war, context, participants) groups = TieBreaker.rank_by_tokens(war, context, participants)
return groups[0] return groups[0]
@staticmethod @staticmethod
@ -423,7 +423,7 @@ class TieResolver:
) )
) )
return return
groups = TieResolver.rank_by_tokens(war, context, context.participants) groups = TieBreaker.rank_by_tokens(war, context, context.participants)
if len(groups[0]) == 1: if len(groups[0]) == 1:
war.events.append( war.events.append(
TieResolved( TieResolved(
@ -444,7 +444,7 @@ class TieResolver:
def can_tie_be_resolved( def can_tie_be_resolved(
war: War, context: TieContext, participants: List[str] war: War, context: TieContext, participants: List[str]
) -> bool: ) -> bool:
active = TieResolver.get_active_participants(war, context, participants) active = TieBreaker.get_active_participants(war, context, participants)
return any(war.get_influence_tokens(pid) > 0 for pid in active) return any(war.get_influence_tokens(pid) > 0 for pid in active)
@staticmethod @staticmethod

View file

@ -273,44 +273,44 @@
"choices": [ "choices": [
{ {
"participant_id": "602e2eaf-297e-490b-b0e9-efec818e466a", "participant_id": "602e2eaf-297e-490b-b0e9-efec818e466a",
"priority_sector_id": null, "priority_sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f",
"secondary_sector_id": null, "secondary_sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499",
"comment": null "comment": null
}, },
{ {
"participant_id": "1f6b4e7c-b1e4-4a2e-9aea-7bb75b20b4de", "participant_id": "1f6b4e7c-b1e4-4a2e-9aea-7bb75b20b4de",
"priority_sector_id": null, "priority_sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499",
"secondary_sector_id": null, "secondary_sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f",
"comment": null "comment": null
}, },
{ {
"participant_id": "237c1291-4331-4242-bd70-bf648185a627", "participant_id": "237c1291-4331-4242-bd70-bf648185a627",
"priority_sector_id": null, "priority_sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f",
"secondary_sector_id": null, "secondary_sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499",
"comment": null "comment": null
}, },
{ {
"participant_id": "876a1684-7fe2-4d8d-a50a-a4d7e354c5b0", "participant_id": "876a1684-7fe2-4d8d-a50a-a4d7e354c5b0",
"priority_sector_id": null, "priority_sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499",
"secondary_sector_id": null, "secondary_sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f",
"comment": null "comment": null
} }
], ],
"battles": [ "battles": [
{ {
"sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f", "sector_id": "d1f7c6cf-40ff-42b8-b1b6-05576017de1f",
"player_1_id": "602e2eaf-297e-490b-b0e9-efec818e466a", "player_1_id": "237c1291-4331-4242-bd70-bf648185a627",
"player_2_id": "237c1291-4331-4242-bd70-bf648185a627", "player_2_id": "602e2eaf-297e-490b-b0e9-efec818e466a",
"winner_id": null, "winner_id": null,
"score": null, "score": null,
"victory_condition": "tie", "victory_condition": "Tie",
"comment": "Never finished..." "comment": "Never finished..."
}, },
{ {
"sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499", "sector_id": "096da98e-d8b4-4c71-946a-3cee2cc38499",
"player_1_id": "1f6b4e7c-b1e4-4a2e-9aea-7bb75b20b4de", "player_1_id": "1f6b4e7c-b1e4-4a2e-9aea-7bb75b20b4de",
"player_2_id": "876a1684-7fe2-4d8d-a50a-a4d7e354c5b0", "player_2_id": "876a1684-7fe2-4d8d-a50a-a4d7e354c5b0",
"winner_id": "876a1684-7fe2-4d8d-a50a-a4d7e354c5b0", "winner_id": "1f6b4e7c-b1e4-4a2e-9aea-7bb75b20b4de",
"score": "4/2", "score": "4/2",
"victory_condition": "Mission", "victory_condition": "Mission",
"comment": "Decisive fast attack impossible to resist." "comment": "Decisive fast attack impossible to resist."