Skip to content

Instantly share code, notes, and snippets.

@bgnori
Created July 1, 2017 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bgnori/59699c08ccff3296a9cf03d5dbf1520a to your computer and use it in GitHub Desktop.
Save bgnori/59699c08ccff3296a9cf03d5dbf1520a to your computer and use it in GitHub Desktop.
python3 ShogiELOtourney.py --verbose --resolve --tournament ryuuou30th-2.json --out expected-r1750.json --override 307:1750
[7, 235,
[3 ,
[1, 231,
[1, 207,
[1, 233,
[1, 280, 307]
]
]
],
[1,
[1, 194, 269],
[1,
[1, 182, 249],
175
]
]
]
]
import math
import json
import urllib.request
from lxml import html
import numpy
from scipy.stats import binom
def prepare_url(n):
return "http://kishi.a.la9.jp/2017R/1{0}.html".format(n)
def get_rating(n):
"""
>>> get_rating(175)
1858
>>> get_rating(231)
1759
"""
def ELO_Ea(Ra, Rb):
return 1.0 / (1.0+ math.pow(10, (Rb - Ra) / 400.0))
def ELO_UpdateDiff(Ra, *results):
"""
>>> ELO_UpdateDiff(1613, *((0, 1609), (0.5, 1477), (1, 1388), (1, 1586), (0, 1720)))
-6
"""
x = 0.0
for wl, opp in results:
x += (wl - ELO_Ea(Ra, opp))
# ELO_K=16
return 16 * x
def matchwc(n, Ra, Rb):
"""
>>> matchwc(1, 1700, 1779)
0.3882
>>> matchwc(3, 1700, 1870)
0.1831
"""
Ea = ELO_Ea(Ra, Rb)
return binom.sf(n/2, n, Ea)
#t = 1000*1000
#return sum(numpy.random.binomial(n, Ea, t) >= n/2) / t
def visit(t, f_leaf, f_node, is_node):
n, left, right = t
if is_node(left):
lv = visit(left, f_leaf, f_node, is_node)
else:
lv = f_leaf(left)
if is_node(right):
rv = visit(right, f_leaf, f_node, is_node)
else:
rv = f_leaf(right)
return f_node(n, lv, rv)
class PlayerInfo:
def __init__(self):
self.n = None
self.name = None
self.rating = None
def __repr__(self):
return "{0}(id={1}, r={2})".format(self.name, self.n, self.rating)
class Resolver:
def __init__(self, d):
self.override = d
def resolve(self, s):
return PlayerInfo()
def json2tourney(self, j):
def is_node(x):
return isinstance(x, list)
def f_leaf(leaf):
return self.resolve(leaf)
def f_node(n, lv, rv):
return (n, lv, rv)
return visit(j, f_leaf, f_node, is_node)
def do_override(self, n, v):
return self.override.get(n, v)
class IntRatingResolver(Resolver):
def resolve(self, s):
p = PlayerInfo()
p.name = s
p.rating = int(s)
return p
class WebIdResolver(Resolver):
def resolve(self, s):
p = PlayerInfo()
with urllib.request.urlopen(prepare_url(s)) as page:
h = html.parse(page)
tr = h.xpath("/html/body//table/tr")
td = tr[4].xpath('td')
p.n = int(s)
p.name = h.xpath("/html/head/title")[0].text
p.rating = self.do_override(p.n, int(td[4].text))
return p
def tournamentwc(t):
def is_node(x):
return isinstance(x, tuple)
def f_leaf(leaf):
return {leaf:1.0}
def f_node(n, lv, rv):
d = {}
for left, p in lv.items():
for right, q in rv.items():
wc = matchwc(n, left.rating, right.rating)
d[left] = d.get(left, 0.0) + p*q * wc
d[right] = d.get(right, 0.0) + p*q * (1 - wc)
return d
return visit(t, f_leaf, f_node, is_node)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="verbose", action="store_true")
parser.add_argument("--override", nargs='+')
parser.add_argument("--player")
parser.add_argument("--resolve", help="interpret as id and get rating from web.", action="store_true")
parser.add_argument("--tournament", help="calculate tournament winning chance, specified in json file")
parser.add_argument("--winningchance", help="calculate winning chance based on ratings", action="store_true")
parser.add_argument("--opp", action="append")
parser.add_argument("--out", help="file name for output")
args = parser.parse_args()
print(args)
override = {}
if args.override:
for s in args.override:
n, r = s.split(":")
override[int(n)] = int(r)
if args.resolve:
resolver = WebIdResolver(override)
else:
resolver = IntRatingResolver(override)
if args.player:
p = resolver.resolve(args.player)
print(p)
if args.winningchance:
for opp in args.opp:
opp = resolver.resolve(opp)
wc = matchwc(1, p.rating, opp.rating)
print(p.name, p.rating, opp.name, opp.rating, wc)
if args.tournament:
with open(args.tournament) as f:
j = json.load(f)
if args.verbose:
print(j)
t = resolver.json2tourney(j)
if args.verbose:
print(t)
w = tournamentwc(t)
if args.verbose:
print(w)
print(sum(w.values()))
with open(args.out, 'w') as g:
json.dump([(repr(k), v) for k, v in w.items()], g)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment