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
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。