工作原因接触到了瑞士轮这种赛制,记录一下瑞士轮比赛对手编排的算法
瑞士轮有两个规则
- 选择积分相近的对手进行比赛
- 不会重复比赛
写出来的算法如下:
type player struct {
Id int64
Score int64
Opponent map[int64]struct{} // 曾经遇到过的对手
}
// pickTablePlayer 计算瑞士轮比赛排列
func pickTablePlayer(players []int64, playerOpponentMap map[int64]map[int64]struct{}) ([]int64, bool) {
if len(players) < 2 {
return players, true
}
whitePlayer := players[0]
opponentMap, _ := playerOpponentMap[whitePlayer]
for i := range players {
if i != 0 {
// 判断是否已经比过
if _, has := opponentMap[players[i]]; !has {
// 选中
res := make([]int64, 2)
res[0] = whitePlayer
res[1] = players[i]
// 组装剩下排序的数据
var nextRound []int64
nextRound = append(nextRound, players[1:i]...)
nextRound = append(nextRound, players[i+1:]...)
pick, ok := pickTablePlayer(nextRound, playerOpponentMap) // 进行下一轮排序
if ok {
return append(res, pick...), true // 成功,结果上浮
}
}
}
}
return nil, false // 失败,上层重算
}
func CreateSwissRound(players []player) (playerBattleList [][]int64, emptyPlayer int64, ok bool) {
ok = true
// 判断轮空选手
total := len(players)
if total%2 != 0 {
emptyPlayer = players[total-1].Id
players = players[:total]
}
// 转换数据结构
var playerIds []int64
var playerOpponentMap = make(map[int64]map[int64]struct{})
for _, v := range players {
playerIds = append(playerIds, v.Id)
if _, has := playerOpponentMap[v.Id]; !has {
playerOpponentMap[v.Id] = v.Opponent
}
}
// 计算比赛排序
playerList, ok := pickTablePlayer(playerIds, playerOpponentMap)
if !ok {
return playerBattleList, emptyPlayer, ok
}
// 转换为二维数组
for i := 0; i < len(playerList)/2; i++ {
playerBattleList = append(playerBattleList, []int64{
playerList[i*2],
playerList[i*2+1],
})
}
return
}
- 本文链接:
- 版权声明: 本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。