重构2 while循环,以便完成

时间:2016-03-06 12:04:42

标签: php algorithm while-loop combinatorics

我有一段我编写的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 个答案:

答案 0 :(得分:0)

当您尝试从灯具中获取随机值时,如果您有不适当的条件从$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);

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

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