-
-
Save bgnori/59699c08ccff3296a9cf03d5dbf1520a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
python3 ShogiELOtourney.py --verbose --resolve --tournament ryuuou30th-2.json --out expected-r1750.json --override 307:1750 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[7, 235, | |
[3 , | |
[1, 231, | |
[1, 207, | |
[1, 233, | |
[1, 280, 307] | |
] | |
] | |
], | |
[1, | |
[1, 194, 269], | |
[1, | |
[1, 182, 249], | |
175 | |
] | |
] | |
] | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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