重构 2 个 while 循环,使它们完成

Refactoring 2 while loops so that they complete

我编写了一段 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;

}

当您尝试从固定装置获取随机值时,可能会遇到无法从 $allFixtures 获取任何值的不适当条件。例如,检查此输出:

  • 第 3 周,第 1 场:9v10
  • 第 3 周,第 2 场比赛:4v13
  • 第 3 周,第 3 场:11v6
  • 第 3 周,第 4 场:3v14
  • !!! 第 3 周,第 5 场:2v5
  • 第 3 周,第 6 场:16v1
  • 第 3 周,第 7 场:7v15
  • 第 3 周,第 8 场比赛:8v12

然后

  • 第 9 周,第 1 场:13v4
  • 第 9 周,第 2 场:14v11
  • 第 9 周,第 3 场:10v7
  • 第 9 周,第 4 场:12v16
  • 第 9 周,第 5 场:1v15
  • !!! 第 9 周,第 6 场:5v2
  • 第 9 周,第 7 场比赛:8v3
  • 第 9 周,第 8 场:6v9

然后

  • 第 16 周,第 1 场:16v12
  • 第 16 周,第 2 场:7v13
  • 第 16 周,第 3 场:8v15
  • 第 16 周,第 4 场:14v3
  • 第 16 周,第 5 场:4v1
  • 第 16 周,第 6 场:6v10
  • 第 16 周,第 7 场:9v11
  • ???

如您所见,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);

这将为您提供适当的团队对分配,同时这将消除您在代码中遇到的情况。

我认为,你的代码(即使它有很多不必要的身体动作)也能正常工作,即使你只是改变创建初始混合物的方式,而不是整个方法,就像我一样。主要的是在初始混合列表中分配团队对的方式。您的代码正在停止响应,因为它正在循环并再次循环以搜索以前已经使用但现在不能使用的值。