1 from __future__ import print_function
3 from ortools.constraint_solver import pywrapcp
5 def print_solution(sol):
6 for i in range(num_matches):
7 home_team = collector.Value(sol, home_teams[i])
8 away_team = collector.Value(sol, away_teams[i])
9 matchnum = collector.Value(sol, matchnums[i])
10 #print("%2d. %d vs. %d (matchnum %d)" % (i, home_team, away_team, matchnum))
11 print("%2d. %d vs. %d (matchnum %2d, excitedness %d)" % (i, home_team, away_team, matchnum, excitedness[matchnum]))
14 solver = pywrapcp.Solver("schedule_shifts")
17 num_matches = (num_teams * (num_teams - 1)) // 2
19 # Create supermatch variables.
21 for match_idx in range(num_matches):
22 matchnums.append(solver.IntVar(0, num_matches - 1, "matchnum(%i)" % (match_idx)))
23 solver.Add(solver.AllDifferent(matchnums));
25 # Create list of matches.
28 home_teams_for_match_num = []
29 away_teams_for_match_num = []
30 for team_idx_1 in range(num_teams):
31 for team_idx_2 in range(num_teams):
32 if team_idx_2 > team_idx_1:
33 home_teams_for_match_num.append(team_idx_1)
34 away_teams_for_match_num.append(team_idx_2)
35 if team_idx_2 - team_idx_1 == 1:
37 elif team_idx_2 - team_idx_1 == 2:
41 print("matchnum ", match_num , " plays: ", team_idx_1, " - ", team_idx_2, " excited: " , excitedness[match_num])
42 match_num = match_num + 1
44 # Create match variables.
47 for match_idx in range(num_matches):
48 home_teams.append(solver.IntVar(0, num_teams - 1, "home_team_on_match(%i)" % (match_idx)))
49 away_teams.append(solver.IntVar(0, num_teams - 1, "away_team_on_match(%i)" % (match_idx)))
50 matches_flat = home_teams + away_teams
52 for match_num in range(num_matches):
53 # home_teams_var[i] = home_teams[match_num_var[i]]
54 #solver.Add(matchnums[match_num].IndexOf(home_teams) == team_idx_1) # home_teams[matchnums[match_num]] == team_idx_1
55 #solver.Add(matchnums[match_num].IndexOf(away_teams) == team_idx_2)
56 solver.Add(home_teams[match_num] == solver.Element(home_teams_for_match_num, matchnums[match_num]))
57 solver.Add(away_teams[match_num] == solver.Element(away_teams_for_match_num, matchnums[match_num]))
59 ## A team can never play two matches in a row
60 for match_idx in range(num_matches - 1):
61 solver.Add(home_teams[match_idx] != home_teams[match_idx + 1])
62 solver.Add(away_teams[match_idx] != home_teams[match_idx + 1])
63 solver.Add(home_teams[match_idx] != away_teams[match_idx + 1])
64 solver.Add(away_teams[match_idx] != away_teams[match_idx + 1])
66 # More waiting time is good
68 for match_idx in range(num_matches - 2):
70 (home_teams[match_idx] == home_teams[match_idx + 2]) +
71 (home_teams[match_idx] == away_teams[match_idx + 2]))
73 (away_teams[match_idx] == home_teams[match_idx + 2]) +
74 (away_teams[match_idx] == away_teams[match_idx + 2]))
75 tired_matches.append(home_tired)
76 tired_matches.append(away_tired)
78 # double-tired is not cool
79 if match_idx < num_matches - 4:
80 home_doubletired = home_tired * (
81 (home_teams[match_idx] == home_teams[match_idx + 4]) +
82 (home_teams[match_idx] == away_teams[match_idx + 4]))
83 away_doubletired = away_tired * (
84 (away_teams[match_idx] == home_teams[match_idx + 4]) +
85 (away_teams[match_idx] == away_teams[match_idx + 4]))
86 tired_matches.append(home_doubletired * 100)
87 tired_matches.append(away_doubletired * 100)
89 sum_tiredness = solver.Sum(tired_matches)
91 ## TFK can not play the first match
92 solver.Add(home_teams[0] != 0)
93 solver.Add(away_teams[0] != 0)
94 solver.Add(home_teams[1] != 0)
95 solver.Add(away_teams[1] != 0)
97 # Group final comes last
98 solver.Add(home_teams[num_matches - 1] == 0)
99 solver.Add(away_teams[num_matches - 1] == 1)
101 # Put the more excitedness last
102 sum_excitedness = solver.Sum([(matchnums[match_num].IndexOf(excitedness) * match_num) for match_num in range(num_matches)])
103 objective = solver.Maximize(sum_excitedness - 10 * sum_tiredness, 1)
105 # TODO: AllowedAssignments
106 # TODO: multiple fields/groups, objectives of getting TV time (esp. for interesting matches)
107 # TODO: objective on getting more interesting matches last
109 db = solver.Phase(matchnums, solver.CHOOSE_FIRST_UNBOUND,
110 solver.ASSIGN_MIN_VALUE)
111 search_log = solver.SearchLog(1000000, objective)
112 #global_limit = solver.TimeLimit(1000)
113 global_limit = solver.TimeLimit(100000000)
115 ## Create the solution collector.
116 #solution = solver.Assignment()
117 #solution.Add(matches_flat)
118 #solution.Add(matchnums)
120 ##collector = solver.AllSolutionCollector(solution)
121 ##collector = solver.LastSolutionCollector(solution)
122 #collector = solver.FirstSolutionCollector(solution)
124 #solver.Solve(db, [collector, search_log, objective, global_limit])
125 #print("Solutions found:", collector.SolutionCount())
126 #print("Time:", solver.WallTime(), "ms")
128 ## Display a few solutions picked at random.
129 #a_few_solutions = [0]
130 #for sol in a_few_solutions:
131 # print_solution(sol)
136 solver.NewSearch(db, [search_log, objective, global_limit])
138 while solver.NextSolution():
139 #print("objective = ", sum_excitedness.Value())
140 for i in range(num_matches):
141 home_team = home_teams[i].Value()
142 away_team = away_teams[i].Value()
143 matchnum = matchnums[i].Value()
147 if home_team == home_teams[i - 2].Value():
148 tiredness = tiredness + 1
149 if home_team == away_teams[i - 2].Value():
150 tiredness = tiredness + 1
151 if away_team == home_teams[i - 2].Value():
152 tiredness = tiredness + 1
153 if away_team == away_teams[i - 2].Value():
154 tiredness = tiredness + 1
156 print("%2d. %d vs. %d (matchnum %2d, excitedness %d, tiredness %d)" % (i, home_team, away_team, matchnum, excitedness[matchnum], tiredness))