单循环赛制是一种多队伍进行比赛,每只队伍均能和其他队伍进行一次比赛的赛制。百科链接
比如有6只队伍,需要进行5轮比赛。编排如下:
想象一下赛场上站着每只队伍的代表,站两排,然后移动位置
轮数 | 左侧 | 右侧 |
第一轮 | 1 | 6 |
2 | 5 | |
3 | 4 | |
第二轮 | 1 | 5 |
6 | 4 | |
2 | 3 | |
第三轮 | 1 | 4 |
5 | 3 | |
6 | 2 | |
第四轮 | 1 | 3 |
4 | 2 | |
5 | 6 | |
第五轮 | 1 | 2 |
3 | 6 | |
4 | 5 |
可能不太直观的看出来过程,下边用图标示一下移动的队伍。
直观的看,也看不出来如何用程序实现。再把两排看成一排试试。。。
轮数 | 站成一排的效果(尾尾相接) |
第一轮 | 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;
}