工作原因接触到了瑞士轮这种赛制,记录一下瑞士轮比赛对手编排的算法

瑞士轮有两个规则

  1. 选择积分相近的对手进行比赛
  2. 不会重复比赛

写出来的算法如下:

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
}