Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
elo-rating
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
huangzhihao
elo-rating
Commits
95fa4b2c
Commit
95fa4b2c
authored
Aug 12, 2020
by
ziho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit
parents
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
774 additions
and
0 deletions
+774
-0
elo.ipynb
+479
-0
elorating.py
+222
-0
readme.md
+73
-0
No files found.
elo.ipynb
0 → 100644
View file @
95fa4b2c
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import random"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class Player:\n",
" def __init__(self,name,rating):\n",
" self.name=name\n",
" self.rating=rating\n",
" self.wins=0\n",
" self.losses=0\n",
" self.draw=0\n",
" self.num_game=0\n",
" \n",
"\n",
"class EloRatingSystem:\n",
" WIN=1\n",
" LOSS=0\n",
" DRAW=0.5\n",
" def __init__(self,base_rating=1500,recordSaveFile='gameRecord.txt'):\n",
" self.base_rating=base_rating\n",
" self.players={}\n",
" \n",
" self.saveFile=recordSaveFile\n",
" \n",
" self.readFlag=False\n",
" \n",
" def addModel(self,name):\n",
" p=Player(name,self.base_rating)\n",
" self.players[name]=p\n",
" return p\n",
" \n",
" def addModels(self,models):\n",
" for m in models:\n",
" self.addModel(m)\n",
" print('add model to system:{}'.format(models))\n",
" \n",
" def check(self,name,online=True):\n",
" if name not in self.players:\n",
" if online:\n",
" print('{} not in player list,please use <addmodel> to add it'.format(name))\n",
" return False\n",
" return True\n",
" \n",
"\n",
" def playgame(self,p1,p2,winrate,numgames=1,online=True):\n",
" '''\n",
" result [int]: \n",
" 假设没有平局,赢了算1,输了算0,平局是0.5\n",
" '''\n",
" self.readFlag=True\n",
" if not self.check(p1,online) or not self.check(p2,online):\n",
" return\n",
" \n",
" if online:\n",
" #只是避免把文件里读出来的再写回去\n",
" with open(self.saveFile,'a') as f:\n",
" f.write('{},{},{},{}\\n'.format(p1,p2,winrate,numgames))\n",
" \n",
" player1=self.players[p1]\n",
" player2=self.players[p2]\n",
" \n",
" p1_win=int(numgames*winrate)\n",
" p2_win=numgames-p1_win\n",
"\n",
" player1.wins+=p1_win\n",
" player2.losses+=p1_win\n",
" player2.wins+=p2_win\n",
" player1.losses+=p2_win\n",
" player1.num_game+=numgames\n",
" player2.num_game+=numgames\n",
" \n",
" R1=player1.rating\n",
" R2=player2.rating \n",
" \n",
" def expectScore(rating1,rating2):\n",
" #base on https://en.wikipedia.org/wiki/Elo_rating_system\n",
" #same function as E1=1/(1+10**((rating1-rating2)/400))\n",
" Q1=10**(rating1/400)\n",
" Q2=10**(rating2/400)\n",
" E1=Q1/(Q1+Q2)\n",
" E2=Q2/(Q1+Q2)\n",
" return E1,E2\n",
" \n",
" def choose_k(rating):\n",
" #参考FIDE:https://gobase.org/studying/articles/elo/\n",
" #另有EGD规则:http://europeangodatabase.eu/EGD/EGF_rating_system.php\n",
" if rating<2000:\n",
" return 30\n",
" elif rating>2400:\n",
" return 10\n",
" else:\n",
" return 130-rating/20\n",
" \n",
" \n",
" E1,E2=expectScore(R1,R2)\n",
" \n",
" k=choose_k(R1)\n",
" player1.rating=R1+k*(winrate-E1)\n",
" k=choose_k(R2)\n",
" player2.rating=R2+k*(1-winrate-E2)\n",
" \n",
" if player1.rating<0:\n",
" player1.rating=50\n",
" elif player2.rating<0:\n",
" player2.rating=50\n",
" \n",
" if online:\n",
" #print('{}\\'s rating:{}->{} ; {}\\'s rating:{}->{}'.format(p1,R1,player1.rating,p2,R2,player2.rating))\n",
" pass \n",
" \n",
" def readRecords(self,filename):\n",
" if self.readFlag:\n",
" print('[warning] system is running! will not do anything')\n",
" return\n",
" self.readFlag=True\n",
" with open(filename,'r') as f:\n",
" lines=f.readlines()\n",
" for l in lines:\n",
" record=l.split(',')\n",
" self.playgame(record[0],record[1],float(record[2]),int(record[3]),False)\n",
" self.summary()\n",
" \n",
" def summary(self):\n",
" players=list(self.players.values())\n",
" def sortKey(p):\n",
" return p.rating\n",
" players.sort(key=sortKey,reverse=True)\n",
" \n",
" print('{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}'.format('model','rating','games','wins','losses'))\n",
" for p in players:\n",
" print('{:<10s}{:<10.2f}{:<10d}{:<10d}{:<10d}'.format(str(p.name),p.rating,p.num_game,p.wins,p.losses))\n",
" \n",
" def getPlayers(self,sortByRank=False):\n",
" players=list(self.players.values())\n",
" if sortByRank: \n",
" def sortKey(p):\n",
" return p.rating\n",
" players.sort(key=sortKey,reverse=True)\n",
" return players \n",
" \n",
" def getRating(self):\n",
" return [p.rating for p in list(self.players.values())]\n",
" \n",
" def getNearPlayer(self,name):\n",
" #获取同等级的对手,以供匹配,相差200分以内吧\n",
" res=[]\n",
" if not self.check(name):\n",
" return\n",
" R=self.players[name].rating\n",
" for p in self.players.values():\n",
" if abs(p.rating-R)<200 and p.name!=name:\n",
" res.append(p.name)\n",
" if len(res)==0:\n",
" return None\n",
" return res\n",
" \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"models=[str(i) for i in range (0,50000,1000)]\n",
"models\n",
"\n",
"def pk(model1,model2,num_games):\n",
" winrate=1-0.5**(abs(int(model1)-int(model2))/1000) #假设新模型以一定概率战胜旧模型\n",
" res=random.choices([elo.WIN,elo.DRAW,elo.LOSS],weights=[winrate,0,1-winrate],k=1) \n",
" if int(model1)>int(model2):\n",
" return res[0]\n",
" else:\n",
" return 1-res[0]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"add model to system:['0', '1000', '2000', '3000', '4000', '5000', '6000', '7000', '8000', '9000', '10000', '11000', '12000', '13000', '14000', '15000', '16000', '17000', '18000', '19000', '20000', '21000', '22000', '23000', '24000', '25000', '26000', '27000', '28000', '29000', '30000', '31000', '32000', '33000', '34000', '35000', '36000', '37000', '38000', '39000', '40000', '41000', '42000', '43000', '44000', '45000', '46000', '47000', '48000', '49000']\n",
"model rating games wins losses \n",
"0 1500.00 0 0 0 \n",
"1000 1500.00 0 0 0 \n",
"2000 1500.00 0 0 0 \n",
"3000 1500.00 0 0 0 \n",
"4000 1500.00 0 0 0 \n",
"5000 1500.00 0 0 0 \n",
"6000 1500.00 0 0 0 \n",
"7000 1500.00 0 0 0 \n",
"8000 1500.00 0 0 0 \n",
"9000 1500.00 0 0 0 \n",
"10000 1500.00 0 0 0 \n",
"11000 1500.00 0 0 0 \n",
"12000 1500.00 0 0 0 \n",
"13000 1500.00 0 0 0 \n",
"14000 1500.00 0 0 0 \n",
"15000 1500.00 0 0 0 \n",
"16000 1500.00 0 0 0 \n",
"17000 1500.00 0 0 0 \n",
"18000 1500.00 0 0 0 \n",
"19000 1500.00 0 0 0 \n",
"20000 1500.00 0 0 0 \n",
"21000 1500.00 0 0 0 \n",
"22000 1500.00 0 0 0 \n",
"23000 1500.00 0 0 0 \n",
"24000 1500.00 0 0 0 \n",
"25000 1500.00 0 0 0 \n",
"26000 1500.00 0 0 0 \n",
"27000 1500.00 0 0 0 \n",
"28000 1500.00 0 0 0 \n",
"29000 1500.00 0 0 0 \n",
"30000 1500.00 0 0 0 \n",
"31000 1500.00 0 0 0 \n",
"32000 1500.00 0 0 0 \n",
"33000 1500.00 0 0 0 \n",
"34000 1500.00 0 0 0 \n",
"35000 1500.00 0 0 0 \n",
"36000 1500.00 0 0 0 \n",
"37000 1500.00 0 0 0 \n",
"38000 1500.00 0 0 0 \n",
"39000 1500.00 0 0 0 \n",
"40000 1500.00 0 0 0 \n",
"41000 1500.00 0 0 0 \n",
"42000 1500.00 0 0 0 \n",
"43000 1500.00 0 0 0 \n",
"44000 1500.00 0 0 0 \n",
"45000 1500.00 0 0 0 \n",
"46000 1500.00 0 0 0 \n",
"47000 1500.00 0 0 0 \n",
"48000 1500.00 0 0 0 \n",
"49000 1500.00 0 0 0 \n"
]
}
],
"source": [
"elo=EloRatingSystem()\n",
"elo.addModels(models)\n",
"elo.summary()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"model rating games wins losses \n",
"49000 3045.67 5002 3388 1614 \n",
"48000 2980.58 5746 3496 2250 \n",
"47000 2868.33 6564 3516 3048 \n",
"46000 2818.49 6540 3328 3212 \n",
"45000 2742.48 6228 3316 2912 \n",
"44000 2673.12 5896 3148 2748 \n",
"43000 2605.95 5942 3102 2840 \n",
"42000 2574.61 6292 3272 3020 \n",
"41000 2470.60 6142 3206 2936 \n",
"40000 2448.55 5884 3034 2850 \n",
"39000 2388.98 5954 3018 2936 \n",
"37000 2295.24 5952 3040 2912 \n",
"38000 2282.79 6082 3062 3020 \n",
"36000 2204.54 5938 3012 2926 \n",
"35000 2186.72 6008 3030 2978 \n",
"34000 2088.25 5944 3000 2944 \n",
"33000 1999.89 6004 3062 2942 \n",
"32000 1952.80 5854 2958 2896 \n",
"31000 1881.68 6102 3098 3004 \n",
"30000 1810.49 5962 2992 2970 \n",
"29000 1753.48 5976 3016 2960 \n",
"27000 1712.87 5920 2978 2942 \n",
"28000 1657.39 6024 3024 3000 \n",
"26000 1557.71 6070 3016 3054 \n",
"24000 1517.55 6062 3066 2996 \n",
"25000 1511.32 5948 2984 2964 \n",
"23000 1432.79 6176 3098 3078 \n",
"22000 1317.84 6166 3042 3124 \n",
"21000 1258.16 6064 3010 3054 \n",
"20000 1254.75 6032 2996 3036 \n",
"19000 1210.90 6138 3018 3120 \n",
"18000 1052.93 5950 2926 3024 \n",
"17000 1012.31 6060 2988 3072 \n",
"15000 934.62 5898 2870 3028 \n",
"16000 923.44 5918 2902 3016 \n",
"14000 922.92 5854 2880 2974 \n",
"13000 779.87 5804 2852 2952 \n",
"12000 715.08 6146 3018 3128 \n",
"11000 687.11 5880 2876 3004 \n",
"10000 579.16 6010 2912 3098 \n",
"8000 504.51 6006 2914 3092 \n",
"9000 487.08 6156 2992 3164 \n",
"7000 387.35 6008 2904 3104 \n",
"5000 359.80 5924 2856 3068 \n",
"6000 341.27 5982 2860 3122 \n",
"4000 263.29 6234 3018 3216 \n",
"3000 225.60 6516 3216 3300 \n",
"2000 163.61 6318 2904 3414 \n",
"1000 76.26 5620 2188 3432 \n",
"0 34.34 5044 1568 3476 \n"
]
}
],
"source": [
"for i in range(5000): \n",
" players=elo.getPlayers(sortByRank=True) #选择分数相近的作为比赛对手\n",
" black=random.choice(players).name\n",
" matchList=elo.getNearPlayer(black)\n",
" if matchList: \n",
" white=random.choice(matchList)\n",
" else:\n",
" continue #谁都打不过,或者谁都打不过\n",
" \n",
" num=2\n",
" winrate=pk(black,white,num) #就比一局\n",
" elo.playgame(black,white,winrate,numgames=num)\n",
"\n",
"elo.summary()"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"add model to system:['0', '1000', '2000', '3000', '4000', '5000', '6000', '7000', '8000', '9000', '10000', '11000', '12000', '13000', '14000', '15000', '16000', '17000', '18000', '19000', '20000', '21000', '22000', '23000', '24000', '25000', '26000', '27000', '28000', '29000', '30000', '31000', '32000', '33000', '34000', '35000', '36000', '37000', '38000', '39000', '40000', '41000', '42000', '43000', '44000', '45000', '46000', '47000', '48000', '49000']\n",
"model rating games wins losses \n",
"49000 3045.67 5002 3388 1614 \n",
"48000 2980.58 5746 3496 2250 \n",
"47000 2868.33 6564 3516 3048 \n",
"46000 2818.49 6540 3328 3212 \n",
"45000 2742.48 6228 3316 2912 \n",
"44000 2673.12 5896 3148 2748 \n",
"43000 2605.95 5942 3102 2840 \n",
"42000 2574.61 6292 3272 3020 \n",
"41000 2470.60 6142 3206 2936 \n",
"40000 2448.55 5884 3034 2850 \n",
"39000 2388.98 5954 3018 2936 \n",
"37000 2295.24 5952 3040 2912 \n",
"38000 2282.79 6082 3062 3020 \n",
"36000 2204.54 5938 3012 2926 \n",
"35000 2186.72 6008 3030 2978 \n",
"34000 2088.25 5944 3000 2944 \n",
"33000 1999.89 6004 3062 2942 \n",
"32000 1952.80 5854 2958 2896 \n",
"31000 1881.68 6102 3098 3004 \n",
"30000 1810.49 5962 2992 2970 \n",
"29000 1753.48 5976 3016 2960 \n",
"27000 1712.87 5920 2978 2942 \n",
"28000 1657.39 6024 3024 3000 \n",
"26000 1557.71 6070 3016 3054 \n",
"24000 1517.55 6062 3066 2996 \n",
"25000 1511.32 5948 2984 2964 \n",
"23000 1432.79 6176 3098 3078 \n",
"22000 1317.84 6166 3042 3124 \n",
"21000 1258.16 6064 3010 3054 \n",
"20000 1254.75 6032 2996 3036 \n",
"19000 1210.90 6138 3018 3120 \n",
"18000 1052.93 5950 2926 3024 \n",
"17000 1012.31 6060 2988 3072 \n",
"15000 934.62 5898 2870 3028 \n",
"16000 923.44 5918 2902 3016 \n",
"14000 922.92 5854 2880 2974 \n",
"13000 779.87 5804 2852 2952 \n",
"12000 715.08 6146 3018 3128 \n",
"11000 687.11 5880 2876 3004 \n",
"10000 579.16 6010 2912 3098 \n",
"8000 504.51 6006 2914 3092 \n",
"9000 487.08 6156 2992 3164 \n",
"7000 387.35 6008 2904 3104 \n",
"5000 359.80 5924 2856 3068 \n",
"6000 341.27 5982 2860 3122 \n",
"4000 263.29 6234 3018 3216 \n",
"3000 225.60 6516 3216 3300 \n",
"2000 163.61 6318 2904 3414 \n",
"1000 76.26 5620 2188 3432 \n",
"0 34.34 5044 1568 3476 \n"
]
}
],
"source": [
"#从比赛记录中读取\n",
"#每一行是一条记录: \n",
"#黑棋,白棋,胜率,比赛场次\n",
"\n",
"elo=EloRatingSystem()\n",
"elo.addModels(models)\n",
"elo.readRecords('gameRecord.txt')"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x23c9ba99208>]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import matplotlib\n",
"import matplotlib.pyplot as plt\n",
"plt.plot([int(m) for m in models],[int(r) for r in elo.getRating()])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "py3(myenv)",
"language": "python",
"name": "base"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
elorating.py
0 → 100644
View file @
95fa4b2c
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#----------------------------------------------
# 参考代码:
# https://github.com/sublee/elo
# https://github.com/HankSheehan/EloPy
# 参考资料:
# https://en.wikipedia.org/wiki/Elo_rating_system
# https://en.wikipedia.org/wiki/Go_ranks_and_ratings#Elo-like_rating_systems_as_used_in_Go
# https://gobase.org/studying/articles/elo/
#
# CGOS用的bayesELO的介绍,没用这个,它公式不是很清楚
# http://www.yss-aya.com/cgos/19x19/bayes.html
# https://www.remi-coulom.fr/Bayesian-Elo/
#
#---------------------------------------------
import
numpy
as
np
import
random
def
main
():
models
=
[
str
(
i
)
for
i
in
range
(
0
,
50000
,
1000
)]
play
(
models
)
#模拟5000盘游戏
elo
=
EloRatingSystem
()
#初始化
elo
.
addModels
(
models
)
#添加模型
elo
.
readRecords
(
'gameRecord.txt'
)
#从记录里恢复模型
#测试函数与示例
def
play
(
models
,
total_game
=
5000
):
elo
=
EloRatingSystem
(
recordSaveFile
=
'gameRecord.txt'
)
#初始化
elo
.
addModels
(
models
)
#添加模型
elo
.
summary
()
#查看现有模型
for
i
in
range
(
total_game
):
players
=
elo
.
getPlayers
(
sortByRank
=
True
)
#选择分数相近的作为比赛对手
black
=
random
.
choice
(
players
)
.
name
matchList
=
elo
.
getNearPlayer
(
black
)
if
matchList
:
white
=
random
.
choice
(
matchList
)
else
:
continue
#找不到对手,谁都打不过,或者谁都打不过
num
=
1
#比赛局数
winrate
=
pk
(
black
,
white
,
num
)
elo
.
playgame
(
black
,
white
,
winrate
,
numgames
=
num
)
#得到胜率后时用elo.playgame
elo
.
summary
()
#测试用pk函数
def
pk
(
model1
,
model2
,
num_games
):
winrate
=
1
-
0.5
**
(
abs
(
int
(
model1
)
-
int
(
model2
))
/
1000
)
#假设新模型以一定概率战胜旧模型
res
=
random
.
choices
([
1
,
0.5
,
0
],
weights
=
[
winrate
,
0
,
1
-
winrate
],
k
=
1
)
if
int
(
model1
)
>
int
(
model2
):
return
res
[
0
]
else
:
return
1
-
res
[
0
]
#以上是测试代码
class
Player
:
def
__init__
(
self
,
name
,
rating
):
self
.
name
=
name
self
.
rating
=
rating
self
.
wins
=
0
self
.
losses
=
0
self
.
draw
=
0
self
.
num_game
=
0
class
EloRatingSystem
:
WIN
=
1
LOSS
=
0
DRAW
=
0.5
def
__init__
(
self
,
base_rating
=
1500
,
recordSaveFile
=
'gameRecord.txt'
):
self
.
base_rating
=
base_rating
self
.
players
=
{}
self
.
saveFile
=
recordSaveFile
self
.
readFlag
=
False
def
addModel
(
self
,
name
):
p
=
Player
(
name
,
self
.
base_rating
)
self
.
players
[
name
]
=
p
return
p
def
addModels
(
self
,
models
):
for
m
in
models
:
self
.
addModel
(
m
)
print
(
'add model to system:{}'
.
format
(
models
))
def
check
(
self
,
name
,
online
=
True
):
if
name
not
in
self
.
players
:
if
online
:
print
(
'{} not in player list,please use <addmodel> to add it'
.
format
(
name
))
return
False
return
True
def
playgame
(
self
,
p1
,
p2
,
winrate
,
numgames
=
1
,
online
=
True
):
'''
result [int]:
假设没有平局,赢了算1,输了算0,平局是0.5
'''
self
.
readFlag
=
True
if
not
self
.
check
(
p1
,
online
)
or
not
self
.
check
(
p2
,
online
):
return
if
online
:
#只是避免把文件里读出来的再写回去
with
open
(
self
.
saveFile
,
'a'
)
as
f
:
f
.
write
(
'{},{},{},{}
\n
'
.
format
(
p1
,
p2
,
winrate
,
numgames
))
player1
=
self
.
players
[
p1
]
player2
=
self
.
players
[
p2
]
p1_win
=
int
(
numgames
*
winrate
)
p2_win
=
numgames
-
p1_win
player1
.
wins
+=
p1_win
player2
.
losses
+=
p1_win
player2
.
wins
+=
p2_win
player1
.
losses
+=
p2_win
player1
.
num_game
+=
numgames
player2
.
num_game
+=
numgames
R1
=
player1
.
rating
R2
=
player2
.
rating
def
expectScore
(
rating1
,
rating2
):
#base on https://en.wikipedia.org/wiki/Elo_rating_system
#same function as E1=1/(1+10**((rating1-rating2)/400))
Q1
=
10
**
(
rating1
/
400
)
Q2
=
10
**
(
rating2
/
400
)
E1
=
Q1
/
(
Q1
+
Q2
)
E2
=
Q2
/
(
Q1
+
Q2
)
return
E1
,
E2
def
choose_k
(
rating
):
#参考FIDE:https://gobase.org/studying/articles/elo/
#另有EGD规则:http://europeangodatabase.eu/EGD/EGF_rating_system.php
if
rating
<
2000
:
return
30
elif
rating
>
2400
:
return
10
else
:
return
130
-
rating
/
20
E1
,
E2
=
expectScore
(
R1
,
R2
)
k
=
choose_k
(
R1
)
player1
.
rating
=
R1
+
k
*
(
winrate
-
E1
)
k
=
choose_k
(
R2
)
player2
.
rating
=
R2
+
k
*
(
1
-
winrate
-
E2
)
# if player1.rating<0:
# player1.rating=0
# elif player2.rating<0:
# player2.rating=0
if
online
:
#print('{}\'s rating:{}->{} ; {}\'s rating:{}->{}'.format(p1,R1,player1.rating,p2,R2,player2.rating))
pass
def
readRecords
(
self
,
filename
):
'''
读取比赛记录
'''
if
self
.
readFlag
:
print
(
'[warning] system is running! will not do anything'
)
return
self
.
readFlag
=
True
with
open
(
filename
,
'r'
)
as
f
:
lines
=
f
.
readlines
()
for
l
in
lines
:
record
=
l
.
split
(
','
)
self
.
playgame
(
record
[
0
],
record
[
1
],
float
(
record
[
2
]),
int
(
record
[
3
]),
False
)
self
.
summary
()
def
summary
(
self
):
players
=
list
(
self
.
players
.
values
())
def
sortKey
(
p
):
return
p
.
rating
players
.
sort
(
key
=
sortKey
,
reverse
=
True
)
print
(
'{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}'
.
format
(
'model'
,
'rating'
,
'games'
,
'wins'
,
'losses'
))
for
p
in
players
:
print
(
'{:<10s}{:<10.2f}{:<10d}{:<10d}{:<10d}'
.
format
(
str
(
p
.
name
),
p
.
rating
,
p
.
num_game
,
p
.
wins
,
p
.
losses
))
def
getPlayers
(
self
,
sortByRank
=
False
):
#默认按模型排序,加入选项可以按分数排序
players
=
list
(
self
.
players
.
values
())
if
sortByRank
:
def
sortKey
(
p
):
return
p
.
rating
players
.
sort
(
key
=
sortKey
,
reverse
=
True
)
return
players
def
getRating
(
self
):
#获取分数,按模型输入顺序排,用来画图
return
[
float
(
p
.
rating
)
for
p
in
list
(
self
.
players
.
values
())]
def
getNearPlayer
(
self
,
name
):
#获取同等级的对手,以供匹配,相差200分以内吧
res
=
[]
if
not
self
.
check
(
name
):
return
R
=
self
.
players
[
name
]
.
rating
for
p
in
self
.
players
.
values
():
if
abs
(
p
.
rating
-
R
)
<
200
and
p
.
name
!=
name
:
res
.
append
(
p
.
name
)
if
len
(
res
)
==
0
:
return
None
return
res
if
__name__
==
'__main__'
:
main
()
readme.md
0 → 100644
View file @
95fa4b2c
#### 基本类
```
python
class
EloRatingSystem
:
def
__init__
(
self
,
base_rating
=
1500
,
recordSaveFile
=
'gameRecord.txt'
)
def
addModel
(
self
,
name
)
def
addModels
(
self
,
models
):
#添加一个/多个模型
def
check
(
self
,
name
,
online
=
True
):
#检查模型是否在列表中
def
playgame
(
self
,
p1
,
p2
,
winrate
,
numgames
=
1
,
online
=
True
):
#进行比赛,此过程将更新模型的rating
def
readRecords
(
self
,
filename
):
#读取比赛记录
def
summary
(
self
):
#总结整体情况
def
getPlayers
(
self
,
sortByRank
=
False
):
#返回player类型的列表,默认按模型排序,加入选项可以按分数排序
def
getRating
(
self
):
#获取分数,按模型输入顺序排,用来画图
def
getNearPlayer
(
self
,
name
):
#获取同等级的对手,以供匹配,相差200分以内吧
```
#### 公式
详细的见 https://en.wikipedia.org/wiki/Elo_rating_system
A对B的胜率估计如下,Ra,Rb为elo rating
$$
E_A=
\f
rac{1}{1+10^{(R_B-R_A)/400}}
$$
$$
E_B=1-E_A
$$
更新公式,Sa为实际胜率,K为随rating变化的常数,一般在rating较高时较小
$$
R_A'=R_A+K(S_A-E_A)
$$
#### 参考代码:
https://github.com/sublee/elo
https://github.com/HankSheehan/EloPy
#### 参考资料:
https://en.wikipedia.org/wiki/Elo_rating_system
https://en.wikipedia.org/wiki/Go_ranks_and_ratings#Elo-like_rating_systems_as_used_in_Go
https://gobase.org/studying/articles/elo/
CGOS用的bayesELO的介绍,没用这个,它公式不是很清楚
http://www.yss-aya.com/cgos/19x19/bayes.html
https://www.remi-coulom.fr/Bayesian-Elo/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment