Рефакторинг 2 циклов while для завершения

У меня есть раздел php-кода, который я написал для того, чтобы создать список случайных матчей для 16 клубов, которые играют по 30 игр в течение сезона. У меня проблема в том, что код никогда не завершается. Если я уменьшу количество недель; $ w, он начинает иногда завершить около 15, любой выше 20, и это никогда не завершается. Можно ли как-то реорганизовать этот код, чтобы он в конце концов завершился?

set_time_limit(0);
ini_set('max_execution_time', 0);
ini_set('memory_limit','960M');

$fixtures = array();

$drawnFixtures = array();

$allFixtures = array(
[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [1, 8], [1, 9], [1, 10], [1, 11], [1, 12], [1, 13], [1, 14], [1, 15], [1, 16],
[2, 1], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2, 8], [2, 9], [2, 10], [2, 11], [2, 12], [2, 13], [2, 14], [2, 15], [2, 16],
[3, 1], [3, 2], [3, 4], [3, 5], [3, 6], [3, 7], [3, 8], [3, 9], [3, 10], [3, 11], [3, 12], [3, 13], [3, 14], [3, 15], [3, 16],
[4, 1], [4, 2], [4, 3], [4, 5], [4, 6], [4, 7], [4, 8], [4, 9], [4, 10], [4, 11], [4, 12], [4, 13], [4, 14], [4, 15], [4, 16],
[5, 1], [5, 2], [5, 3], [5, 4], [5, 6], [5, 7], [5, 8], [5, 9], [5, 10], [5, 11], [5, 12], [5, 13], [5, 14], [5, 15], [5, 16],
[6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 7], [6, 8], [6, 9], [6, 10], [6, 11], [6, 12], [6, 13], [6, 14], [6, 15], [6, 16],
[7, 1], [7, 2], [7, 3], [7, 4], [7, 5], [7, 6], [7, 8], [7, 9], [7, 10], [7, 11], [7, 12], [7, 13], [7, 14], [7, 15], [7, 16],
[8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7], [8, 9], [8, 10], [8, 11], [8, 12], [8, 13], [8, 14], [8, 15], [8, 16],
[9, 1], [9, 2], [9, 3], [9, 4], [9, 5], [9, 6], [9, 7], [9, 8], [9, 10], [9, 11], [9, 12], [9, 13], [9, 14], [9, 15], [9, 16],
[10, 1], [10, 2], [10, 3], [10, 4], [10, 5], [10, 6], [10, 7], [10, 8], [10, 9], [10, 11], [10, 12], [10, 13], [10, 14], [10, 15], [10, 16],
[11, 1], [11, 2], [11, 3], [11, 4], [11, 5], [11, 6], [11, 7], [11, 8], [11, 9], [11, 10], [11, 12], [11, 13], [11, 14], [11, 15], [11, 16],
[12, 1], [12, 2], [12, 3], [12, 4], [12, 5], [12, 6], [12, 7], [12, 8], [12, 9], [12, 10], [12, 11], [12, 13], [12, 14], [12, 15], [12, 16],
[13, 1], [13, 2], [13, 3], [13, 4], [13, 5], [13, 6], [13, 7], [13, 8], [13, 9], [13, 10], [13, 11], [13, 12], [13, 14], [13, 15], [13, 16],
[14, 1], [14, 2], [14, 3], [14, 4], [14, 5], [14, 6], [14, 7], [14, 8], [14, 9], [14, 10], [14, 11], [14, 12], [14, 13], [14, 15], [14, 16],
[15, 1], [15, 2], [15, 3], [15, 4], [15, 5], [15, 6], [15, 7], [15, 8], [15, 9], [15, 10], [15, 11], [15, 12], [15, 13], [15, 14], [15, 16],
[16, 1], [16, 2], [16, 3], [16, 4], [16, 5], [16, 6], [16, 7], [16, 8], [16, 9], [16, 10], [16, 11], [16, 12], [16, 13], [16, 14], [16, 15]
);$w = 0;

while ($w < 30) {

$g = 0;

$games = '<ul class="fixtures">';

while ($g < 8) {

$randomKey = array_rand($allFixtures);
$randomResult = $allFixtures[$randomKey];

$homeTeam = $randomResult[0];
$awayTeam = $randomResult[1];

$fixture = $homeTeam . 'v' . $awayTeam;

if(!in_array($homeTeam,$fixtures) && !in_array($awayTeam,$fixtures) && !in_array($fixture,$drawnFixtures)) {

$fixtures[] = $homeTeam;
$fixtures[] = $awayTeam;
$games .= '<li>' . $fixture . '</li>';

$drawnFixtures[] = $fixture;
$g++;

}

}

$games .= '</ul>';

$w++;
$fixtures = array();

echo $games;

}

1

Решение

Когда вы пытаетесь получить случайное значение из осветительных приборов, возможны ситуации, когда у вас будут неподходящие условия для получения любого значения из $allFixtures, Например, проверьте этот вывод:

  • 3 неделя, игра 1: 9 на 10
  • Неделя 3, игра 2: 4 на 13
  • Неделя 3, игра 3: 11v6
  • Неделя 3, игра 4: 3 на 14
  • !!! Неделя 3, игра 5: 2 на 5
  • Неделя 3, игра 6: 16 на 1
  • Неделя 3, игра 7: 7 на 15
  • Неделя 3, игра 8: 8 на 12

затем

  • Неделя 9, игра 1: 13 на 4
  • Неделя 9, игра 2: 14 на 11
  • Неделя 9, игра 3: 10v7
  • Неделя 9, игра 4: 12 на 16
  • Неделя 9, игра 5: 1 на 15
  • !!! Неделя 9, игра 6: 5 на 2
  • Неделя 9, игра 7: 8v3
  • Неделя 9, игра 8: 6 на 9

А потом

  • 16 неделя, игра 1: 16 на 12
  • 16 неделя, игра 2: 7 на 13
  • 16 неделя, игра 3: 8 на 15
  • 16 неделя, игра 4: 14 на 3
  • 16 неделя, игра 5: 4 на 1
  • 16 неделя, игра 6: 6 на 10
  • 16 неделя, игра 7: 9 на 11
  • ???

Как видите, лучшим кандидатом на w16g8 является либо 2v5, либо 5v2, но в то же время оба кандидата уже используются (w3g5 и w9g6). Таким образом, любые перетасовки начальных матчей приведут вас к ситуациям, когда пара команд не может играть, потому что они уже играли.

Я не математик, и на данный момент у меня меньше знаний о комбинаторике, чем я хотел, но я могу предложить рандомизировать значения с помощью этого подхода:

$template = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];

shuffle($template);

$allFixtures = [];

for ($i = 0; $i < 16; $i++) {
for ($j = 0; $j < 16; $j++) {
if ($i == $j) {
continue;
}

$allFixtures[] = [$template[$i], $template[$j]];
}
}

$output = '';

for ($week = 1; $week <= 30; $week++) {
$this_week_players = [];

for ($game = 1; $game <= 8; $game++) {
foreach ($allFixtures as $key => $fixture) {
if (in_array($fixture[0], $this_week_players)) {
continue;
}

if (in_array($fixture[1], $this_week_players)) {
continue;
}

$this_week_players = array_merge($this_week_players, $fixture);

$output .= sprintf('<li>Week %s, game %s: %sv%s</li>', $week, $game, $fixture[0], $fixture[1]);

unset($allFixtures[$key]);

break;
}
}
}

echo sprintf('<ul class="fixtures">%s</ul>', $output);

Это даст вам правильное распределение командных пар, а также исключит ситуацию, с которой вы столкнулись в своем коде.

Я думаю, ваш код (даже если в нем много ненужных движений тела) будет работать нормально, даже если вы просто измените способ создания исходных миксов, а не весь подход, как я. Главное — способ распределения команды пары в начальном списке смесей. Ваш код останавливает ответ, потому что он зацикливается и снова зацикливается для поиска значения, которое уже использовалось ранее и не может быть использовано сейчас.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]