import random
from collections import defaultdict
def schedule_round(teams, sheets, history, seed=None, max_tries=500):
"""
teams: lista med lag (t.ex. ["A","B","C","D"])
sheets: lista med banor (t.ex. ["Sheet1","Sheet2"])
history: set med frozenset({lag1, lag2}) som redan mötts
seed: valfri seed för reproducerbarhet
max_tries: hur många försök att hitta parningar utan upprepning
"""
if seed is not None:
rnd = random.Random(seed)
else:
rnd = random
teams_local = teams[:]
rnd.shuffle(teams_local)
# Om udda antal lag -> en "bye"
bye = None
if len(teams_local) % 2 == 1:
bye = teams_local.pop() # sist lottade får vila
# Försök hitta parningar utan att lag mötts tidigare
for _ in range(max_tries):
rnd.shuffle(teams_local)
pairs = [(teams_local[i], teams_local[i+1]) for i in range(0, len(teams_local), 2)]
if all(frozenset(p) not in history for p in pairs):
break
else:
# lyckades inte undvika alla upprepningar – kör bara den senaste uppsättningen par
pairs = [(teams_local[i], teams_local[i+1]) for i in range(0, len(teams_local), 2)]
# Slumpa banfördelning
need = min(len(pairs), len(sheets))
chosen_sheets = sheets[:]
rnd.shuffle(chosen_sheets)
chosen_sheets = chosen_sheets[:need]
# Bygg schema och uppdatera historik
round_games = []
for (t1, t2), sh in zip(pairs, chosen_sheets):
round_games.append({"home": t1, "away": t2, "sheet": sh})
history.add(frozenset((t1, t2)))
# Om fler matcher än banor: resterande matcher får inte plats denna omgång
overflow = pairs[need:]
return round_games, overflow, bye
def schedule_tournament(teams, sheets, num_rounds, seed=None):
history = set()
rnd = random.Random(seed)
teams = teams[:]
all_rounds = []
waiting_matches = [] # ifall det blev fler matcher än banor en omgång
for r in range(1, num_rounds+1):
# Om tidigare overflow, spela dem först i denna omgång
carry = waiting_matches[:]
waiting_matches = []
# Skapa nya par för de lag som inte är upptagna i carry
busy = set(x for pair in carry for x in pair)
free_teams = [t for t in teams if t not in busy]
# Lottning för fria lag
games, overflow, bye = schedule_round(free_teams, sheets, history, seed=rnd.randint(0, 10**9))
# Blanda in carry-matcher på lediga banor om möjligt
rnd.shuffle(carry)
# Lediga banor kvar efter games
used_sheets = len(games)
free_sheet_count = max(0, len(sheets) - used_sheets)
round_games = games[:]
for pair in carry[:free_sheet_count]:
sh = f"Sheet(extra-{len(round_games)+1})" # eller återanvänd lediga verkliga sheets om du följer resurser strikt
round_games.append({"home": pair[0], "away": pair[1], "sheet": sh})
history.add(frozenset(pair))
# Ev. kvarvarande carry-matcher + nya overflow flyttas fram
waiting_matches = carry[free_sheet_count:] + overflow
all_rounds.append({"round": r, "games": round_games, "bye": bye})
return all_rounds, waiting_matches
# Exempel
teams = ["Lag A", "Lag B", "Lag C", "Lag D", "Lag E", "Lag F"]
sheets = ["Bana 1", "Bana 2", "Bana 3"]
schema, kvar = schedule_tournament(teams, sheets, num_rounds=3, seed=42)
for r in schema:
print(f"Omgång {r['round']}:")
for g in r["games"]:
print(f" {g['home']} vs {g['away']} – {g['sheet']}")
if r["bye"]:
print(f" Vila: {r['bye']}")
print()
if kvar:
print("Matcher som inte hann spelas och måste schemaläggas senare:", kvar)