3.8 KiB
3.8 KiB
qualifiers-seeding
Automatisiert das Team-Seeding für UEFA-Qualifikationsturniere.
Trigger
- Neue Saison erstellen
- Team-Import
- "seeding", "seed teams", "neue saison"
Kontext
Das Seeding erstellt die Node-Struktur und weist Teams basierend auf UEFA-Koeffizienten zu. Die Hauptfunktion ist seed_nodes25() in qualifiers/helpers.py.
Regeln
-
Node-Struktur folgt UEFA-Format:
Champions Path: └── UCL: Q1 → Q2 → Q3 → PO └── UEL: Q2 → Q3 → PO └── UECL: Q3 → PO League Path: └── UCL: Q2 → Q3 → PO └── UEL: Q3 → PO -
Koeffizienten-Ranking:
# Formel: Koeffizient * 100000 - Position # Höherer Wert = besseres Ranking coefficients[team.id] = float(100000 * team.coefficient - team.position) -
State-Transitions:
none(0) →seeded(1): Nachseeded_teams.set()- Vorgänger-Nodes müssen mindestens State
draw(3) haben
-
GroupsOfSize automatisch erstellen:
node.create_groupsofsize() # Erstellt: 4, 6, 8, 10, 12, 20 mit number=0
Beispiel: Nodes für neue Saison erstellen
from qualifiers.models import QPath, QTier, QStage, QNode
# Path erstellen
cp = QPath.objects.create(scenario=scenario, name='Champions Path')
# Tiers erstellen
ucl = QTier.objects.create(
scenario=scenario,
path=cp,
name='UCL',
ypos=3,
optimize_prio=50
)
# Stages erstellen
q1 = QStage.objects.create(scenario=scenario, path=cp, name='Q1', xpos=1)
q2 = QStage.objects.create(scenario=scenario, path=cp, name='Q2', xpos=2)
# Nodes erstellen mit Navigation
node_q1 = QNode.objects.create(
scenario=scenario,
name='Q1',
tier=ucl,
stage=q1,
type=0, # Grouping
state=1, # Seeded
)
node_q2 = QNode.objects.create(
scenario=scenario,
name='Q2',
tier=ucl,
stage=q2,
type=0,
state=0, # Wartet auf Q1
)
# Navigation setzen
node_q1.winners = node_q2
node_q1.save()
Beispiel: Teams seeden
from scheduler.models import Team
from qualifiers.models import QNode
node = QNode.objects.get(
scenario=scenario,
tier__name='UCL',
stage__name='Q1'
)
# Top 16 Teams nach Koeffizient
teams = Team.objects.filter(
season=scenario.season,
active=True
).order_by('-coefficient')[:16]
# Teams zuweisen
node.seeded_teams.set(teams)
node.state = 1 # Seeded
node.save()
# Gruppengrößen erstellen
node.create_groupsofsize()
Beispiel: Upcomers von Vorgänger-Node
# Nach Q1 Draw: Teams für Q2 sammeln
q1_node = QNode.objects.get(scenario=scenario, tier__name='UCL', stage__name='Q1')
q2_node = QNode.objects.get(scenario=scenario, tier__name='UCL', stage__name='Q2')
# Upcomers sind finalisierte Matches aus Q1
upcomers = q2_node.upcomers(scenario)
# Format:
# [
# {'id': 123, 'team': <Team>, 'coeff': 45.5, 'countries': ['GER'], ...},
# {'id': 456, 'match': <QMatch>, 'coeff': 30.2, 'countries': ['ESP', 'ITA'], ...},
# ]
Validierung
def validate_node_seeding(node):
"""Prüft Seeding-Voraussetzungen."""
errors = []
# Mindestens 2 Teams
total_teams = node.nTeams(node.upcomers(node.scenario))
if total_teams < 2:
errors.append("Mindestens 2 Teams erforderlich")
# Gerade Anzahl
if total_teams % 2 != 0:
errors.append("Ungerade Teamanzahl")
# Alle Vorgänger finalisiert
for pred in node.qnode_winners.all() | node.qnode_losers.all():
if pred.current_state(node.scenario) < 3:
errors.append(f"Vorgänger {pred.which()} nicht im Draw-State")
return errors