In [1]:
import itertools
import random
import collections
In [2]:
teams = ['A', 'B', 'C', 'D', 'E', 'F']
forbidden_combinations = [('A', 'B')]
In [3]:
def is_forbidden(pair, forbidden_combinations):
return pair in forbidden_combinations or tuple(reversed(pair)) in forbidden_combinations
def is_legal(draw, remaining_teams, forbidden_combinations):
for team in remaining_teams:
if is_forbidden((draw, team), forbidden_combinations):
return False
return True
def draw_teams_with_backtracking(teams, forbidden_combinations, matchups=[]):
random.shuffle(teams)
if not teams:
return matchups
for i, current_team in enumerate(teams):
if len(matchups) % 2 == 0:
next_matchups = matchups + [current_team]
remaining_teams = teams[:i] + teams[i+1:]
result = draw_teams_with_backtracking(remaining_teams, forbidden_combinations, next_matchups)
if result:
return result
else:
last_team = matchups[-1]
if not is_forbidden((last_team, current_team), forbidden_combinations):
next_matchups = matchups + [current_team]
remaining_teams = teams[:i] + teams[i+1:]
result = draw_teams_with_backtracking(remaining_teams, forbidden_combinations, next_matchups)
if result:
return result
return None
def calculate_draw_odds(teams, forbidden_combinations, specified_team=None, simulations=10000):
matchup_counts = {team: {opponent: 0 for opponent in teams if team != opponent} for team in teams}
for _ in range(simulations):
random.shuffle(teams)
matchups = draw_teams_with_backtracking(teams, forbidden_combinations)
if matchups:
for i in range(0, len(matchups) - 1, 2):
team1, team2 = matchups[i], matchups[i + 1]
matchup_counts[team1][team2] += 1
matchup_counts[team2][team1] += 1
odds = {team: {} for team in teams}
for team1 in teams:
total_matches = sum(matchup_counts[team1].values())
for team2 in matchup_counts[team1]:
if total_matches > 0:
odds[team1][team2] = (matchup_counts[team1][team2] / total_matches) * 100
else:
odds[team1][team2] = 0
return odds
In [4]:
draw_teams = draw_teams_with_backtracking
In [5]:
for i in range(10):
drawn_teams = draw_teams(teams, forbidden_combinations)
print("\nFinal draw order:", drawn_teams)
Final draw order: ['E', 'A', 'B', 'D', 'C', 'F'] Final draw order: ['D', 'F', 'C', 'A', 'B', 'E'] Final draw order: ['C', 'E', 'A', 'F', 'D', 'B'] Final draw order: ['A', 'D', 'B', 'F', 'C', 'E'] Final draw order: ['C', 'A', 'D', 'B', 'E', 'F'] Final draw order: ['A', 'E', 'D', 'F', 'C', 'B'] Final draw order: ['C', 'E', 'F', 'B', 'D', 'A'] Final draw order: ['B', 'D', 'A', 'E', 'C', 'F'] Final draw order: ['B', 'E', 'C', 'F', 'D', 'A'] Final draw order: ['E', 'C', 'B', 'D', 'A', 'F']
In [6]:
odds = calculate_draw_odds(teams, forbidden_combinations, simulations=100000)
for team1, opponents in odds.items():
print(f"{team1}:")
for team2, percentage in opponents.items():
if percentage > 0:
print(f" vs {team2}: {percentage:.1f}%")
print()
E: vs A: 24.8% vs D: 16.7% vs F: 16.8% vs B: 25.0% vs C: 16.7% B: vs E: 25.0% vs D: 25.1% vs F: 24.9% vs C: 25.0% F: vs E: 16.8% vs A: 25.0% vs D: 16.6% vs B: 24.9% vs C: 16.7% A: vs E: 24.8% vs D: 25.1% vs F: 25.0% vs C: 25.0% C: vs E: 16.7% vs A: 25.0% vs D: 16.5% vs F: 16.7% vs B: 25.0% D: vs E: 16.7% vs A: 25.1% vs F: 16.6% vs B: 25.1% vs C: 16.5%
In [18]:
def draw_teams_with_presets(teams, forbidden_combinations, matchups, available_teams):
if not available_teams:
return matchups
next_slot = matchups.index(None)
for i, current_team in enumerate(available_teams):
if next_slot % 2 == 0:
next_matchups = matchups[:]
next_matchups[next_slot] = current_team
remaining_teams = available_teams[:i] + available_teams[i+1:]
result = draw_teams_with_presets(teams, forbidden_combinations, next_matchups, remaining_teams)
if result:
return result
else:
last_team = matchups[next_slot - 1]
if not is_forbidden((last_team, current_team), forbidden_combinations):
next_matchups = matchups[:]
next_matchups[next_slot] = current_team
remaining_teams = available_teams[:i] + available_teams[i+1:]
result = draw_teams_with_presets(teams, forbidden_combinations, next_matchups, remaining_teams)
if result:
return result
return None
def calculate_draw_odds_with_presets(teams, forbidden_combinations, preset_matchups=None, simulations=10000):
if preset_matchups is None:
preset_matchups = [None] * len(teams)
matchup_counts = {team: {opponent: 0 for opponent in teams if team != opponent} for team in teams}
for _ in range(simulations):
random.shuffle(teams)
available_teams = [team for team in teams if team not in preset_matchups]
matchups = draw_teams_with_presets(teams, forbidden_combinations, preset_matchups[:], available_teams)
if matchups:
for i in range(0, len(matchups) - 1, 2):
team1, team2 = matchups[i], matchups[i + 1]
matchup_counts[team1][team2] += 1
matchup_counts[team2][team1] += 1
odds = {team: {} for team in teams}
for team1 in teams:
total_matches = sum(matchup_counts[team1].values())
for team2 in matchup_counts[team1]:
if total_matches > 0:
odds[team1][team2] = (matchup_counts[team1][team2] / total_matches) * 100
else:
odds[team1][team2] = 0
return odds
In [19]:
teams = ['A', 'B', 'C', 'D', 'E', 'F']
forbidden_combinations = [('A', 'B')]
preset_matchups = ['F', None, None, None, None, None]
In [20]:
odds = calculate_draw_odds_with_presets(teams, forbidden_combinations, preset_matchups, simulations=10000)
print("Odds of drawing each team as an opponent (in %), grouped by team:\n")
for team1, opponents in odds.items():
print(f"{team1}:")
for team2, percentage in opponents.items():
print(f" vs {team2}: {percentage:.2f}%")
print()
Odds of drawing each team as an opponent (in %), grouped by team: E: vs A: 25.95% vs B: 26.64% vs C: 13.03% vs D: 13.79% vs F: 20.59% A: vs B: 0.00% vs C: 26.89% vs D: 26.67% vs E: 25.95% vs F: 20.49% D: vs A: 26.67% vs B: 26.19% vs C: 13.50% vs E: 13.79% vs F: 19.85% F: vs A: 20.49% vs B: 19.83% vs C: 19.24% vs D: 19.85% vs E: 20.59% B: vs A: 0.00% vs C: 27.34% vs D: 26.19% vs E: 26.64% vs F: 19.83% C: vs A: 26.89% vs B: 27.34% vs D: 13.50% vs E: 13.03% vs F: 19.24%
In [ ]: