@ilcavero 完全正确。
我实现了类似的东西。我的代码假设无法运行“对抗”排序解决平局,除非(a)所有玩家都互相比赛并且(b)一名玩家赢得所有比赛或一名球员输掉平局球队之间的所有比赛。
这个 if 语句避免了这样的问题:
爱丽丝需要领先于鲍勃,落后于卡尔。 Bob 需要在 Carl 之前并在 Alice 之后,但 Alice 需要在 Carl 之后。它打破了。它还可以避免因某人没有参加的比赛而对其进行惩罚或奖励。
代码确实解决了如下所示的关系:
我们可以先移除击败其他玩家的爱丽丝,并将她置于平局之上:
- 爱丽丝
- 鲍勃和卡尔
由于鲍勃输给了卡尔,我们可以将他从平局中移除,并将他置于平局下方的位置(此时将只是卡尔)。解决:
- 爱丽丝
- 卡尔
- 鲍勃
我在排序时将排名保持在这样的结构中($this->sortedTeams):
[
1 => [$id => $team, $id => $team, $id = $team], // 3 teams tied for first position.
4 => [$id => $team], // One team in 4th position.
5 => [$id => $team, $id => $team] // 2 teams tied in 5th position.
]
这是我的 TeamSorter 类中处理头对头比较的代码:
private function headToHead() {
foreach ($this->findTies() as $position)
$this->headToHeadThisPosition($position);
ksort($this->sortedTeams);
}
private function headToHeadThisPosition($position) {
// Teams that are tied.
$teams = $this->sortedTeams[$position];
// Every team must play every other team, or head to head doesn't work.
if (!$this->tiedTeamsHaveAllPlayedEachother($teams)) return;
// If we have a winner, it assumes $position, and other(s) assume
// $positon + 1, moving away from first place.
if ($winner_nid = $this->tiedPositionHasWinner($teams))
$position = $this->removeFromTie('winner', $winner_nid, $position);
// If we have a loser, it assumes $position + 1 (moving away from first
// place), other(s) stay at $position.
if ($loser_nid = $this->tiedPositionHasLoser($teams))
$this->removeFromTie('loser', $loser_nid, $position);
// Recursively call this function if we might resolve a tie at $position
// before going on to the next position.
if ($this->recursionNeeded($position))
$this->headToHeadThisPosition($position);
}
private function recursionNeeded($position) {
$teams = $this->sortedTeams[$position];
return
count($this->sortedTeams[$position]) > 1
&&
$this->tiedTeamsHaveAllPlayedEachother($this->sortedTeams[$position])
&&
$this->tiedPositionHasWinner($this->sortedTeams[$position]);
}