单循环赛制的PHP实现


单循环赛制是一种多队伍进行比赛,每只队伍均能和其他队伍进行一次比赛的赛制。百科链接

比如有6只队伍,需要进行5轮比赛。编排如下:

想象一下赛场上站着每只队伍的代表,站两排,然后移动位置

轮数左侧右侧
第一轮16
25
34
第二轮15
64
23
第三轮14
53
62
第四轮13
42
56
第五轮12
36
45

可能不太直观的看出来过程,下边用图标示一下移动的队伍。

直观的看,也看不出来如何用程序实现。再把两排看成一排试试。。。

轮数站成一排的效果(尾尾相接)
第一轮1 2 3 4 5 6
第二轮1 6 2 3 4 5
第三轮1 5 6 2 3 4
第四轮1 4 5 6 2 3
第五轮1 3 4 5 6 2

清晰明了了:从第二轮开始,每轮从队尾抽过来1个队站在第一队后边。

PHP代码验证:

$teams = range(1, 6);
$loop = count($teams) - 1;
$half = count($teams) / 2;
for ($i=1; $i <= $loop; $i++) { 
    echo "第 $i 轮:", PHP_EOL;
    if ($i == 1) {
        $tmpTeams = $teams;
    }else{
        $x = $i - 1;
        $tmpTeams = array_merge([$teams[0]], array_slice($teams, -$x), array_slice($teams, 1, -$x));
    }
    $left = array_slice($tmpTeams, 0, $half);
    $right = array_slice($tmpTeams, $half);
    $right = array_reverse($right);

    echo '   left: ', implode(',', array_map(function($v){return str_pad($v, 3, ' ', STR_PAD_LEFT);}, $left)), PHP_EOL;
    echo '  right: ', implode(',', array_map(function($v){return str_pad($v, 3, ' ', STR_PAD_LEFT);}, $right)), PHP_EOL;
    echo PHP_EOL;
}

结果如下:

第 1 轮:
left: 1, 2, 3
right: 6, 5, 4

第 2 轮:
left: 1, 6, 2
right: 5, 4, 3

第 3 轮:
left: 1, 5, 6
right: 4, 3, 2

第 4 轮:
left: 1, 4, 5
right: 3, 2, 6

第 5 轮:
left: 1, 3, 4
right: 2, 6, 5

然后,封装后可使用的函数,传递一个队伍数组进来,并且提供当前是第几轮,返回左右两边的队伍数组。

/**
 * 获取单循环赛制某轮的队伍编排
 * @param array $teams 队伍数组
 * @param int $round 第几轮
 * @return array|bool 左右两只队伍的数组
 */
function getSingleLoopCompetitionTeams($teams, $round){
    // 单循环赛制轮数等于总队伍数-1
    if ($round > count($teams) - 1) {
        return false;
    }
    $half = count($teams) / 2;
    if ($round > 1) {
        $x = $round - 1;
        $teams = array_merge([$teams[0]], array_slice($teams, -$x), array_slice($teams, 1, -$x));
    }
    $left = array_slice($teams, 0, $half);
    $right = array_slice($teams, $half);
    $right = array_reverse($right);
    return [$left, $right];
}

获取某只队伍在某轮的对手:

/**
 * 获取某队伍在某轮的对手队伍
 * @param array $teams
 * @param int $round
 * @param int|string $team 队伍标识
 * @return int|string|false|null
 */
function getTargetTeam($teams, $round, $team)
{
    $result = getSingleLoopCompetitionTeams($teams, $round);
    if ($result === false) {
        return false;
    }
    list($left, $right) = $result;
    foreach ($left as $k => $lTeam) {
        if ($team == $lTeam) {
            return $right[$k];
        }
    }
    foreach ($right as $k => $rTeam) {
        if ($team == $rTeam) {
            return $left[$k];
        }
    }
    return null;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注