《社交网络》里的Mark Zackburg被女朋友甩后,在舍友的启发下,充分发挥了技术宅男自娱自乐的恶搞天分,做出了Facemash网站,对学校女生的相貌进行排名打分,结果网站访问流量过大,直接把学校网络搞瘫痪了。Facemask大受欢迎的关键就在于Zackburg基友Eduardo写在窗户上的排名公式,看电影之时就对这个排名公式非常感兴趣,上网了解下,才发现这条公式就是大名鼎鼎的ELO等级分制度。ELO的应用非常广泛,大部分棋类比赛,现在流行的MODB游戏,像11平台的DOTA天梯系统,都是采用ELO等级分。
ELO等级分制度是由匈牙利裔美国物理学家Elo创建的一个衡量各类对弈活动选手水平的评分方法,是当今对弈水平评估的公认的权威方法。被广泛应用于国际象棋、围棋、足球等运动,以及很多网游与电子竞技产业。游戏界比较著名的应用有: WOW(魔兽世界)、DOTA、LOL。
ELO计算方法
Ra:A玩家当前的积分
Rb:B玩家当前的积分
Sa:实际胜负值,胜=1,平=0.5,负=0
Ea:预期A选手的胜负值,Ea=1/(1+10^[(Rb-Ra)/400])
Eb:预期B选手的胜负值,Eb=1/(1+10^[(Ra-Rb)/400])
因为E值也为预估,则Ea+ Eb=1
R’a=Ra+K(Sa-Ea)
R’a:A玩家进行了一场比赛之后的积分
其中 K 值是一个常量系数,按照国际象棋里的标准, K 值对于大师选手为16,对于一般选手是32。K值的大小直接关系到一局游戏结束,根据胜负关系计算出的积分变化值。
关于K值
K值是一个极限值,代表理论上最多可以赢一个玩家的得分和失分,K/2就是相同rating的玩家其中一方胜利后所得的分数。国际象棋大师赛中,K=16;在大部分的游戏规则中,K=32。通常水平越高的比赛中其K值越小,这样做是为了避免少数的几场比赛就能改变高端顶尖玩家的排名。
关于分母400
公式Ea和Eb中分母的400是怎么来的呢?为何是400,不是200、100或者是其他?
根据公式可以得出,当K值相同的情况下,越高的分母,越低的积分变化。总体来说400是一个平衡的、万金油的值、让多数玩家积分保持 标准正态分布 的值。具体可以参考:http://en.chessbase.com/post/arpad-elo-and-the-elo-rating-system
实例说明
若当前A玩家积分为1500,B玩家积分为1600
预估A玩家的胜负值: Ea = 1/(1+10^[(1600-1500)/400])≈0.36
预估B玩家的胜负值: Eb = 1-Ea = 1-0.36 = 0.64
假设A玩家获胜,实际胜负值为Sa = 1
A玩家最终得分为 :R’a = 1500 + 32*(1-0.36) = 1500+20.5 = 1520
A玩家赢20分,B玩家输20分。
假设B玩家获胜,实际胜负值为Sa = 1
B队最终得分为 R’b = 1600 + 32*(1-0.64) = 1600 + 11.52 = 1612,B玩家赢12分,A玩家输12分。
class Elorating:
ELO_RESULT_WIN = 1
ELO_RESULT_LOSS = -1
ELO_RESULT_TIE = 0
ELO_RATING_DEFAULT = 1500
ratingA = 0
ratingB = 0
def __init__(self, ratingA = ELO_RATING_DEFAULT, ratingB = ELO_RATING_DEFAULT):
self.ratingA = ratingA
self.ratingB = ratingB
def setResult(self, result):
scoreAwin = self.computeScore(self.ratingA, self.ratingB)
scoreBwin = self.computeScore(self.ratingB, self.ratingA)
score_adjust = 0
if result == self.ELO_RESULT_WIN:
score_adjust = 1
elif result == self.ELO_RESULT_LOSS:
score_adjust = 0
else:
score_adjust = 0.5
self.ratingA = self.ratingA + self.computeK(self.ratingA) * (score_adjust - scoreAwin)
self.ratingB = self.ratingB + self.computeK(self.ratingB) * (score_adjust - scoreBwin)
def computeK(self, rating):
if rating >= 2400:
return 16
elif rating >= 2100:
return 24
else:
return 36
def computeScore(self, rating1, rating2):
return 1 / (1+pow(10, (rating1 - rating2) / 400))
pass