johnpoint

johnpoint

(。・∀・)ノ゙嗨
github

Go 实现瑞士轮排列算法

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

瑞士轮有两个规则

  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
}
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。