]> git.sesse.net Git - ultimatescore/blobdiff - roster/test.py
Check in some scripts based on OR-tools to try to generate good group schedules.
[ultimatescore] / roster / test.py
diff --git a/roster/test.py b/roster/test.py
new file mode 100644 (file)
index 0000000..dd90b43
--- /dev/null
@@ -0,0 +1,160 @@
+from __future__ import print_function
+import sys
+from ortools.constraint_solver import pywrapcp
+
+def print_solution(sol):
+  for i in range(num_matches):
+    home_team = collector.Value(sol, home_teams[i])
+    away_team = collector.Value(sol, away_teams[i])
+    matchnum = collector.Value(sol, matchnums[i])
+    #print("%2d. %d vs. %d   (matchnum %d)" % (i, home_team, away_team, matchnum))
+    print("%2d. %d vs. %d   (matchnum %2d, excitedness %d)" % (i, home_team, away_team, matchnum, excitedness[matchnum]))
+
+# Creates the solver.
+solver = pywrapcp.Solver("schedule_shifts")
+
+num_teams = 6
+num_matches = (num_teams * (num_teams - 1)) // 2
+
+# Create supermatch variables.
+matchnums = []
+for match_idx in range(num_matches):
+  matchnums.append(solver.IntVar(0, num_matches - 1, "matchnum(%i)" % (match_idx)))
+solver.Add(solver.AllDifferent(matchnums));
+
+# Create list of matches.
+match_num = 0
+excitedness = []
+home_teams_for_match_num = []
+away_teams_for_match_num = []
+for team_idx_1 in range(num_teams):
+  for team_idx_2 in range(num_teams):
+    if team_idx_2 > team_idx_1:
+      home_teams_for_match_num.append(team_idx_1)
+      away_teams_for_match_num.append(team_idx_2)
+      if team_idx_2 - team_idx_1 == 1:
+        excitedness.append(5)
+      elif team_idx_2 - team_idx_1 == 2:
+        excitedness.append(2)
+      else:
+        excitedness.append(0)
+      print("matchnum ", match_num , " plays: ", team_idx_1, " - ", team_idx_2, "  excited: " , excitedness[match_num])
+      match_num = match_num + 1
+
+# Create match variables.
+home_teams = []
+away_teams = []
+for match_idx in range(num_matches):
+  home_teams.append(solver.IntVar(0, num_teams - 1, "home_team_on_match(%i)" % (match_idx)))
+  away_teams.append(solver.IntVar(0, num_teams - 1, "away_team_on_match(%i)" % (match_idx)))
+matches_flat = home_teams + away_teams
+
+for match_num in range(num_matches):
+  # home_teams_var[i] = home_teams[match_num_var[i]]
+  #solver.Add(matchnums[match_num].IndexOf(home_teams) == team_idx_1)  # home_teams[matchnums[match_num]] == team_idx_1
+  #solver.Add(matchnums[match_num].IndexOf(away_teams) == team_idx_2)
+  solver.Add(home_teams[match_num] == solver.Element(home_teams_for_match_num, matchnums[match_num]))
+  solver.Add(away_teams[match_num] == solver.Element(away_teams_for_match_num, matchnums[match_num]))
+
+## A team can never play two matches in a row
+for match_idx in range(num_matches - 1):
+  solver.Add(home_teams[match_idx] != home_teams[match_idx + 1])
+  solver.Add(away_teams[match_idx] != home_teams[match_idx + 1])
+  solver.Add(home_teams[match_idx] != away_teams[match_idx + 1])
+  solver.Add(away_teams[match_idx] != away_teams[match_idx + 1])
+
+# More waiting time is good
+tired_matches = []
+for match_idx in range(num_matches - 2):
+  home_tired = (
+    (home_teams[match_idx] == home_teams[match_idx + 2]) +
+    (home_teams[match_idx] == away_teams[match_idx + 2]))
+  away_tired = (
+    (away_teams[match_idx] == home_teams[match_idx + 2]) +
+    (away_teams[match_idx] == away_teams[match_idx + 2]))
+  tired_matches.append(home_tired)
+  tired_matches.append(away_tired)
+
+  # double-tired is not cool
+  if match_idx < num_matches - 4:
+    home_doubletired = home_tired * (
+      (home_teams[match_idx] == home_teams[match_idx + 4]) +
+      (home_teams[match_idx] == away_teams[match_idx + 4]))
+    away_doubletired = away_tired * (
+      (away_teams[match_idx] == home_teams[match_idx + 4]) +
+      (away_teams[match_idx] == away_teams[match_idx + 4]))
+    tired_matches.append(home_doubletired * 100)
+    tired_matches.append(away_doubletired * 100)
+
+sum_tiredness = solver.Sum(tired_matches)
+
+## TFK can not play the first match
+solver.Add(home_teams[0] != 0)
+solver.Add(away_teams[0] != 0)
+solver.Add(home_teams[1] != 0)
+solver.Add(away_teams[1] != 0)
+
+# Group final comes last
+solver.Add(home_teams[num_matches - 1] == 0)
+solver.Add(away_teams[num_matches - 1] == 1)
+
+# Put the more excitedness last
+sum_excitedness = solver.Sum([(matchnums[match_num].IndexOf(excitedness) * match_num) for match_num in range(num_matches)])
+objective = solver.Maximize(sum_excitedness - 10 * sum_tiredness, 1)
+
+# TODO: AllowedAssignments
+# TODO: multiple fields/groups, objectives of getting TV time (esp. for interesting matches)
+# TODO: objective on getting more interesting matches last
+
+db = solver.Phase(matchnums, solver.CHOOSE_FIRST_UNBOUND,
+                  solver.ASSIGN_MIN_VALUE)
+search_log = solver.SearchLog(1000000, objective)
+#global_limit = solver.TimeLimit(1000)
+global_limit = solver.TimeLimit(100000000)
+
+## Create the solution collector.
+#solution = solver.Assignment()
+#solution.Add(matches_flat)
+#solution.Add(matchnums)
+#
+##collector = solver.AllSolutionCollector(solution)
+##collector = solver.LastSolutionCollector(solution)
+#collector = solver.FirstSolutionCollector(solution)
+#
+#solver.Solve(db, [collector, search_log, objective, global_limit])
+#print("Solutions found:", collector.SolutionCount())
+#print("Time:", solver.WallTime(), "ms")
+#print()
+## Display a few solutions picked at random.
+#a_few_solutions = [0]
+#for sol in a_few_solutions:
+#  print_solution(sol)
+#
+#os.exit(0)
+
+###All
+solver.NewSearch(db, [search_log, objective, global_limit])
+num_solutions = 0
+while solver.NextSolution():
+  #print("objective = ", sum_excitedness.Value())
+  for i in range(num_matches):
+    home_team = home_teams[i].Value()
+    away_team = away_teams[i].Value()
+    matchnum = matchnums[i].Value()
+
+    tiredness = 0
+    if i >= 2:
+      if home_team == home_teams[i - 2].Value():
+        tiredness = tiredness + 1
+      if home_team == away_teams[i - 2].Value():
+        tiredness = tiredness + 1
+      if away_team == home_teams[i - 2].Value():
+        tiredness = tiredness + 1
+      if away_team == away_teams[i - 2].Value():
+        tiredness = tiredness + 1
+    print("%2d. %d vs. %d   (matchnum %2d, excitedness %d, tiredness %d)" % (i, home_team, away_team, matchnum, excitedness[matchnum], tiredness))
+  
+  print()
+  num_solutions += 1
+solver.EndSearch()