Go 实现瑞士轮排列算法
工作原因接触到了瑞士轮这种赛制,记录一下瑞士轮比赛对手编排的算法 瑞士轮有两个规则 选择积分相近的对手进行比赛 不会重复比赛 写出来的算法如下: 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 }