Skip to content

Commit

Permalink
Introduce Calculate Elo API for external use.
Browse files Browse the repository at this point in the history
This should make it possible for external use to calculate the ELo based on Either (Ptnml or WDL) and elo0, elo1 bounds (elo_model is optional and defaults to "normalized").

The format is:
https://tests.stockfishchess.org/api/calc_elo?LL=93&LD=18711&DD=58877&WD=18739&WW=100&elo0=-1.75&elo1=0.25

needs testing.
  • Loading branch information
peregrineshahin committed Jul 9, 2023
1 parent 1c3f5b3 commit e360949
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
1 change: 1 addition & 0 deletions server/fishtest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def group_finder(username, request):
config.add_route("api_download_nn", "/api/nn/{id}")
config.add_route("api_get_elo", "/api/get_elo/{id}")
config.add_route("api_actions", "/api/actions")
config.add_route("api_calc_elo", "/api/calc_elo")

config.scan()
return config.make_wsgi_app()
85 changes: 85 additions & 0 deletions server/fishtest/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,91 @@ def get_elo(self):
run["elo"] = a
return run

@view_config(route_name="api_calc_elo")
def calc_elo(self):
W = self.request.params.get("W")
D = self.request.params.get("D")
L = self.request.params.get("L")
LL = self.request.params.get("LL")
LD = self.request.params.get("LD")
DD = self.request.params.get("DD")
WD = self.request.params.get("WD")
WW = self.request.params.get("WW")
elo0 = self.request.params.get("elo0")
elo1 = self.request.params.get("elo1")
elo_model = self.request.params.get("elo_model", "normalized")

if elo_model not in ["BayesElo", "logistic", "normalized"]:
self.handle_error(
"Valid Elo models are: BayesElo, logistic, and normalized."
)

isPtnml = all(
value is not None
and (
(
isinstance(value, (int, float))
or isinstance(value, str)
and value.replace(".", "").replace("-", "").isdigit()
)
and float(value) >= 0
)
for value in [LL, LD, DD, WD, WW, elo0, elo1]
)

isWdl = not isPtnml and all(
value is not None
and (
(
isinstance(value, (int, float))
or isinstance(value, str)
and value.replace(".", "").replace("-", "").isdigit()
)
and float(value) >= 0
)
for value in [W, D, L, elo0, elo1]
)

if not isPtnml and not isWdl:
self.handle_error(
"Invalid or missing parameters. Please provide all values as valid numbers."
)

if isPtnml:
LL = int(LL)
LD = int(LD)
DD = int(DD)
WD = int(WD)
WW = int(WW)
if (LL + LD + DD + WD + WW) * 2 > 2**32:
self.handle_error("Number of games exceeds the limit.")
if LL + LD + DD + WD + WW == 0:
self.handle_error("No games to calculate Elo.")
results = {
"pentanomial": [LL, LD, DD, WD, WW],
}
if isWdl:
W = int(W)
D = int(D)
L = int(L)
if W + D + L > 2**32:
self.handle_error("Number of games exceeds the limit.")
if W + D + L == 0:
self.handle_error("No games to calculate Elo.")
results = {
"wins": W,
"draws": D,
"losses": L,
}
elo0 = float(elo0)
elo1 = float(elo1)
alpha = 0.05
beta = 0.05
a = SPRT_elo(
results, alpha=alpha, beta=beta, elo0=elo0, elo1=elo1, elo_model=elo_model
)
return a

@view_config(route_name="api_request_task")
def request_task(self):
self.validate_request("/api/request_task")
Expand Down

0 comments on commit e360949

Please sign in to comment.