order pairing draws with war ranking
This commit is contained in:
parent
188f5256fb
commit
2505573250
3 changed files with 65 additions and 25 deletions
|
|
@ -86,6 +86,7 @@ class RoundController:
|
||||||
rnd,
|
rnd,
|
||||||
part.id,
|
part.id,
|
||||||
)
|
)
|
||||||
|
# TODO clarify status icons
|
||||||
if alloc.priority != ChoiceStatus.NONE:
|
if alloc.priority != ChoiceStatus.NONE:
|
||||||
priority_icon = QIcon(
|
priority_icon = QIcon(
|
||||||
Icons.get_pixmap(IconName[alloc.priority.name])
|
Icons.get_pixmap(IconName[alloc.priority.name])
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
from __future__ import annotations
|
|
||||||
from typing import Dict, Tuple
|
|
||||||
|
|
||||||
from warchron.model.campaign import Campaign
|
|
||||||
|
|
||||||
|
|
||||||
class CampaignHistory:
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def build_match_count(campaign: Campaign) -> Dict[Tuple[str, str], int]:
|
|
||||||
counts: Dict[Tuple[str, str], int] = {}
|
|
||||||
for rnd in campaign.rounds:
|
|
||||||
for battle in rnd.battles.values():
|
|
||||||
p1 = battle.player_1_id
|
|
||||||
p2 = battle.player_2_id
|
|
||||||
if not p1 or not p2:
|
|
||||||
continue
|
|
||||||
key = (p1, p2) if p1 < p2 else (p2, p1)
|
|
||||||
counts[key] = counts.get(key, 0) + 1
|
|
||||||
return counts
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple, TYPE_CHECKING
|
||||||
|
from collections import defaultdict
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
|
@ -18,7 +19,9 @@ from warchron.model.scoring import ScoreComputer
|
||||||
from warchron.model.tiebreaking import TieBreaker, TieContext, ResolveTiesCallback
|
from warchron.model.tiebreaking import TieBreaker, TieContext, ResolveTiesCallback
|
||||||
from warchron.model.war_event import TieResolved
|
from warchron.model.war_event import TieResolved
|
||||||
from warchron.model.scoring import ParticipantScore
|
from warchron.model.scoring import ParticipantScore
|
||||||
from warchron.model.history import CampaignHistory
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
|
|
||||||
ScoredBattle = Tuple[int, Battle]
|
ScoredBattle = Tuple[int, Battle]
|
||||||
|
|
||||||
|
|
@ -260,15 +263,58 @@ class Pairing:
|
||||||
context.participants,
|
context.participants,
|
||||||
)
|
)
|
||||||
ordered: List[str] = []
|
ordered: List[str] = []
|
||||||
for group in ranked_groups:
|
refined_groups = Pairing._refine_with_war_ranking(
|
||||||
|
war,
|
||||||
|
ranked_groups,
|
||||||
|
)
|
||||||
|
for group in refined_groups:
|
||||||
shuffled_group = list(group)
|
shuffled_group = list(group)
|
||||||
# TODO improve tie break with history parsing
|
|
||||||
random.shuffle(shuffled_group)
|
random.shuffle(shuffled_group)
|
||||||
ordered.extend(
|
ordered.extend(
|
||||||
campaign.war_to_campaign_part_id(pid) for pid in shuffled_group
|
campaign.war_to_campaign_part_id(pid) for pid in shuffled_group
|
||||||
)
|
)
|
||||||
return ordered[:places]
|
return ordered[:places]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _refine_with_war_ranking(
|
||||||
|
war: War,
|
||||||
|
ranked_groups: List[List[str]],
|
||||||
|
) -> List[List[str]]:
|
||||||
|
from warchron.model.checking import ResultChecker
|
||||||
|
|
||||||
|
scores = ScoreComputer.compute_scores(
|
||||||
|
war,
|
||||||
|
ContextType.WAR,
|
||||||
|
war.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
def value_getter(score: ParticipantScore) -> int:
|
||||||
|
return score.victory_points
|
||||||
|
|
||||||
|
war_ranking = ResultChecker.get_effective_ranking(
|
||||||
|
war,
|
||||||
|
ContextType.WAR,
|
||||||
|
war.id,
|
||||||
|
ScoreKind.VP,
|
||||||
|
scores,
|
||||||
|
value_getter,
|
||||||
|
)
|
||||||
|
rank_map: Dict[str, int] = {}
|
||||||
|
for rank, group, _ in war_ranking:
|
||||||
|
for pid in group:
|
||||||
|
rank_map[pid] = rank
|
||||||
|
refined: List[List[str]] = []
|
||||||
|
for group in ranked_groups:
|
||||||
|
if len(group) <= 1:
|
||||||
|
refined.append(group)
|
||||||
|
continue
|
||||||
|
buckets: Dict[int, List[str]] = defaultdict(list)
|
||||||
|
for pid in group:
|
||||||
|
buckets[rank_map.get(pid, 10**9)].append(pid)
|
||||||
|
for rank in sorted(buckets.keys()):
|
||||||
|
refined.append(buckets[rank])
|
||||||
|
return refined
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _assign_fallback(
|
def _assign_fallback(
|
||||||
war: War,
|
war: War,
|
||||||
|
|
@ -278,7 +324,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("Campaign not found")
|
raise DomainError("Campaign not found")
|
||||||
match_counts = CampaignHistory.build_match_count(campaign)
|
match_counts = Pairing.build_match_count(campaign)
|
||||||
random.shuffle(remaining)
|
random.shuffle(remaining)
|
||||||
for pid in list(remaining):
|
for pid in list(remaining):
|
||||||
available = round.get_battles_with_places()
|
available = round.get_battles_with_places()
|
||||||
|
|
@ -316,6 +362,19 @@ class Pairing:
|
||||||
rematch_penalty += match_counts.get(key, 0)
|
rematch_penalty += match_counts.get(key, 0)
|
||||||
return rematch_penalty * rematch_weight + occupancy_penalty * occupancy_weight
|
return rematch_penalty * rematch_weight + occupancy_penalty * occupancy_weight
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_match_count(campaign: Campaign) -> Dict[Tuple[str, str], int]:
|
||||||
|
counts: Dict[Tuple[str, str], int] = {}
|
||||||
|
for rnd in campaign.rounds:
|
||||||
|
for battle in rnd.battles.values():
|
||||||
|
p1 = battle.player_1_id
|
||||||
|
p2 = battle.player_2_id
|
||||||
|
if not p1 or not p2:
|
||||||
|
continue
|
||||||
|
key = (p1, p2) if p1 < p2 else (p2, p1)
|
||||||
|
counts[key] = counts.get(key, 0) + 1
|
||||||
|
return counts
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_allocation_kind(
|
def get_allocation_kind(
|
||||||
war: War,
|
war: War,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue