iT邦幫忙

2022 iThome 鐵人賽

DAY 30
2
Modern Web

30個遊戲程設的錦囊妙計系列 第 30

Trick 29: 電競天梯的積分怎麼算才不會糊掉

同學們是否玩過有天梯排名的電競遊戲?有這種賽制的對戰遊戲中,來自四面八方的玩家都可以隨意找對手玩個兩場,並在賽後增減天梯積分,積分越高,越能受到來自其他玩家們景仰的眼光。

可是某人的心中有個小小的火苗告訴他『不如去找幾個新手來痛電。只要持續讓這些新手送頭給我,很快地,我不就成為遊戲之神了嗎?』

當然,你我都不是某人,但遊戲中肯定有這樣不重武德的玩家。不過不要緊,今天要和大家分享的,就是天梯的等級要怎麼算,才能讓積分有意義,遊戲更公平。

Elo等級分制度

Elo等級分制度原本是在棋界用來衡量玩家之間的等級差異,由美國的物理學家阿帕德·埃洛(Arpad Elo)所發明,也是由他的名字來為這個制度命名。

假設一場比賽有兩位玩家互奕,他們的積分分別是R₁與R₂,那麼可以用指數分布算出他們各自勝率的期望值。

  • 玩家1的勝率 https://chart.googleapis.com/chart?cht=tx&chl=E_1%20%3D%20%7B1%20%5Cover%7B1%20%2B%2010%5E%7B(R_2%20-%20R_1)%2F400%7D%7D%7D
  • 玩家2的勝率 https://chart.googleapis.com/chart?cht=tx&chl=E_2%20%3D%20%7B1%20%5Cover%7B1%20%2B%2010%5E%7B(R_1%20-%20R_2)%2F400%7D%7D%7D

等到遊戲結束時,有勝有負或是有平手的情況,勝者的分數S為1,敗者S為0,平手的話兩人的S都是0.5。這個分數和之前算出來的期望值會有一個落差,我們要使用以下這個公式來調整他們在賽後的積分R₁與R₂。

  • R₁' = R₁ + K ( S₁ - E₁ )
  • R₂' = R₂ + K ( S₂ - E₂ )

其中的K值可以是一個遊戲自訂的數字,一般棋賽是訂為32。K值越高,那麼每一場比賽的結果影響力就越大。反之,K值小,積分的變動就比較慢。

Elo等級分通常將尚無積分的玩家定在1500分。

由以上的公式可以知道,兩人對奕時,積分高很多的玩家,贏的期望值就會高很多,因此贏了棋局後,分數不會變動太大,但是高人一等的玩家輸了棋局,積分就會掉很多。

而積分較低的玩家,因為贏的期望值較小,贏了的話,積分就容易上升,而輸了也不會影響太大。

在這個積分制度下,玩家們會想找積分比自己高的人玩,但積分高的人通常是真的比較厲害,最後的結果就是大家會傾向找積分差不多的對手來玩。如果是系統幫忙配對的話,找兩個積分相近的人放一桌就會有比較精采的比賽。

Elo雖然廣泛地被使用,也有很多不同的變形算法,不過這系統最大的問題,在於等級無法反應玩家實力的穩定性,以及時間對實力下降造成的不確定性。

以下簡短實作Elo的評分計算。

// Elo評分系統中的玩家
class EloPlayer {
    // 等級分, 預設1500
    score = 1500;
}

// Elo計算類別
class Elo {
    // K值:每場勝負的影響力
    k = 32;
    /** 計算期望值(0:輸,0.5:平手,1:贏)
     * player:待計算的玩家, opponent:對手
     */
    expectedScore(player: EloPlayer, opponent: EloPlayer): number {
        // 用公式計算期望值
        // Math.pow(a,b)可以計算a的b次方
        return 1 / (1 + Math.pow(10, (opponent.score - player.score) / 400));
    }
    /** 計算賽後更新的等級分
     * player:待計算的玩家, opponent:對手
     * score: 比賽結果(0:輸,0.5:平手,1:贏)
     */
    updateScore(player: EloPlayer, opponent: EloPlayer, score: number): number {
        // 先算期望值
        let expected = this.expectedScore(player, opponent);
        // 然後以分數落差計算等級分的變化量
        let delta = Math.round(this.k * (score - expected));
        // 回傳更新後的等級分
        return player.score + delta;
    }
}

CG示範專案

Github上也有許多Elo評分系統的函式庫可以使用。
mattwills8/elo-rank-typescript : 以TypeScript撰寫的Elo函式庫。

Glicko評分系統

Glicko評分系統由哈佛的馬克·格利克曼(Mark Glickman)教授所發明,用以解決Elo所無法照顧到的細節。

在這個評分系統中,每個人除了代表實力的分數(Rate)以外,還多了一個代表實力穩定的可信度,也就是Reliability Deviation(簡稱RD),RD的作用跟統計學中的標準差一樣,RD的值越小,可信度越高。

Glicko在計算比賽後的分數更新時,會有類似Elo的計算結果,但若是對手實力的可信度較低,那麼選手分數受影響的波動就會比較小,因此兩人的分數不像Elo那樣你加10分我就減10分的概念,而是各自因實力差距以及雙方實力的可信度而有不同的變化。

當玩家在一個遊戲裏玩得越久,勝率越來越趨穩定,他的實力可信度就會提升,在配對時就比較容易找到旗鼓相當的對手。反之,如果是剛進遊戲的新手,或是實力一下高一下低,靠運氣隨便打的玩家,那麼在配對時,系統就會傾向將實力較弱或同樣不穩定的玩家配給他當對手。

Glicko-2是Glicko的進化版,在評分與變異數的基礎上,多加了評分揮發度(Rating Volatility)的概念,也就是玩家分數在一段時間內的波動率會波及下次計算分數的波動程度。基本上的計算和Glicko很像,只是在計算上,要先算出時間範圍內玩家實力的波動率,然後再跟著其他參數一起進行計算。

Glicko-2的計算方法在論文裏有詳細解說,以及計算實例。
http://glicko.net/glicko/glicko2.pdf

雖然Glicko改進了Elo的評分系統,也大量在對戰遊戲中使用,像是著名的Dota、Guild Wars等大型線上遊戲都採用Glicko作為天梯的評分標準,但是這方法仍然要先將多人對戰的結果轉換為兩兩配對後,再來計算評分更新。

animafps/Glicko2 : 以TypeScript撰寫的Glicko2函式庫。
使用的時候要注意,Glicko2的設計是對一連串比賽結果進行評分更新的系統,原論文建議每進行10到15場比賽再進行一次計算。

TrueSkill評分系統

TrueSkill評分系統是由著名的微軟研究院所開發,是Xbox Live自動配對系統使用的演算法。從2005年的TrueSkill一代到2018年的TrueSkill二代,默默地支援著Gears of War以及Halo等大型多人遊戲的玩家評分以及配對功能。

TrueSkill同樣也在每位玩家身上儲存平均分數以及變異數,但是玩家的等級是用平均分數減去變異數的「某個倍數」,因此實力不穩定的玩家,在配對時會被當成較弱的對手。其中計算用的「某個倍數」越大,代表這個評分系統越保守,玩家需要非常穩定的戰鬥實力,才能在天梯排名中緩步上升。

在自動配對一個八人共同參與的比賽時,TrueSkill使用一個複雜的函式,將八組平均數與變異數丟進去計算,產生出一個介於0到1的適合度,在平均數與變異數都相近的情況下,算出來的適合度才會接近1,代表這組人馬適合在一起開戰。

這個演算法很好地解決了以往較難應付的多人多隊等級評比和配對問題。

論文《TrueSkill:基於貝葉斯推論的實力評分系統
scttcper/ts-trueskill : 從Python移殖過來,以TypeScript撰寫的TrueSkill函式庫。


後話

以上三種評分系統是目前遊戲界使用較多的演算法,不過除了Elo比較單純,小哈有實作過以外,另兩種的數學較為複雜,就直接向Github上求助了。


上一篇
Trick 28: 漩渦式地圖搜索演算法
下一篇
Trick 30: 平台遊戲的十二項跳躍準則
系列文
30個遊戲程設的錦囊妙計32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言