Я ищу алгоритм для создания графика для набора команды. Например, представьте себе спортивный сезон, в котором каждая команда играет друг друга, один раз в качестве домашней команды, а другой в качестве команды посетителя на другое поле команд.
Сгенерировать набор из всех игр в сезоне легко, если команды - это список команд, которые будут выполнять следующие команды:
set((x, y) for x in teams for y in teams if x != y)
Но я также хочу ЗАКАЗАТЬ игры в хронологическом порядке в таком что он удовлетворяет ограничению действительного графика игры, а также выглядит "естественно случайным".
Ограничение состоит в том, что список игр должен быть сгруппирован в число раундов, в которых каждый раунд состоит из n/2 игр (где n - это количество команд), в которых каждая команда сопряжена с другой.
Чтобы сделать график более естественным, две команды не должны сталкиваться с каждым другие дважды в последовательных раундах. То есть, если (a, b) воспроизводится в одном раунд, игра (b, a) не должна воспроизводиться во внешнем.
Кроме того, насколько это возможно, каждая команда должна играть в каждом раунде, команда гостей и другие раунды в качестве домашней команды. Я не думаю, что это можно всегда выполнять это ограничение, поэтому более приятно есть предмет. Например, одна команда не должна играть в 8 домашних игр и затем 8 прочь игры.
Вот что я получил сейчас. Основная проблема алгоритма заключается в том, что он часто застревает в петле. Особенно, когда количество команд - 16 и более. Это также очень неэффективно, потому что основывается на использовании функции случайных выборок и надеется получить ее правильно:
from random import sample
def season_schedule_order(teams, pairs):
n_games_per_round = len(teams) // 2
last_pairs = set()
while pairs:
r_pairs = set(sample(pairs, n_games_per_round))
# Check that each team is present once in the round.
r_teams = set(x for (x, y) in r_pairs) | set(y for (x, y) in r_pairs)
if r_teams != teams:
continue
# Check that two teams doesn't face each other again.
rev_pairs = set((y, x) for (x, y) in r_pairs)
if rev_pairs & last_pairs:
continue
pairs -= r_pairs
for p in r_pairs:
yield p
last_pairs = r_pairs
teams = set(['aik', 'djurgarden', 'elfsborg', 'gais',
'gefle', 'hacken', 'halmstad', 'helsingborg'])
pairs = set((x, y) for x in teams for y in teams if x != y)
for (ht, at) in season_schedule_order(teams, pairs):
print '%-20s %-20s' % (ht, at)