Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add level and level_progress to stats api routes #648

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
10 changes: 10 additions & 0 deletions app/api/v1/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import app.usecases.performance
from app.constants import regexes
from app.constants.gamemodes import GameMode
from app.constants.level import get_level
from app.constants.level import get_level_precise
from app.constants.mods import Mods
from app.objects.beatmap import Beatmap
from app.objects.beatmap import ensure_osu_file_is_available
Expand Down Expand Up @@ -263,6 +265,14 @@ async def api_get_player_info(
# extra fields are added to the api response
"rank": rank + 1 if rank is not None else 0,
"country_rank": country_rank + 1 if country_rank is not None else 0,
"level": get_level(int(mode_stats["tscore"])),
"level_progress": int(
(
get_level_precise(mode_stats["tscore"])
- get_level(mode_stats["tscore"])
)
* 100,
),
}

return ORJSONResponse({"status": "success", "player": api_data})
Expand Down
2 changes: 2 additions & 0 deletions app/api/v2/models/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ class PlayerStats(BaseModel):
sh_count: int
s_count: int
a_count: int
level: int
level_progress: int
9 changes: 9 additions & 0 deletions app/api/v2/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from app.api.v2.models.players import Player
from app.api.v2.models.players import PlayerStats
from app.api.v2.models.players import PlayerStatus
from app.constants.level import get_level
from app.constants.level import get_level_precise
from app.repositories import stats as stats_repo
from app.repositories import users as users_repo

Expand Down Expand Up @@ -108,6 +110,13 @@ async def get_player_mode_stats(
)

response = PlayerStats.from_mapping(data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add level and level_progress to data instead. this will cause issues when instantiated otherwise as pydantic will not be happy about these values missing


# NOTE: kinda cursed, but that should do it
response.level = get_level(int(data["tscore"]))
response.level_progress = int(
(get_level_precise(data["tscore"]) - get_level(data["tscore"])) * 100,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this specific pattern seems to repeat itself quite a lot. could we have a function that returns a tuple of level and level_progress instead and use that where needed?

)

return responses.success(response)


Expand Down
141 changes: 141 additions & 0 deletions app/constants/level.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from __future__ import annotations

import math

LEVEL_GRAPH = [
NiceAesth marked this conversation as resolved.
Show resolved Hide resolved
0,
30000,
130000,
340000,
700000,
1250000,
2030000,
3080000,
4440000,
6150000,
8250000,
10780000,
13780000,
17290000,
21350000,
26000000,
31280000,
37230000,
43890000,
51300000,
59500000,
68530000,
78430000,
89240000,
101000000,
113750000,
127530000,
142380000,
158340000,
175450000,
193750000,
213280000,
234080000,
256190000,
279650000,
304500000,
330780000,
358530000,
387790000,
418600000,
451000000,
485030000,
520730000,
558140000,
597300000,
638250000,
681030000,
725680000,
772240000,
820750000,
871250000,
923780000,
978380000,
1035090000,
1093950000,
1155000000,
1218280000,
1283830000,
1351690001,
1421900001,
1494500002,
1569530004,
1647030007,
1727040013,
1809600024,
1894750043,
1982530077,
2072980138,
2166140248,
2262050446,
2360750803,
2462281446,
2566682603,
2673994685,
2784258433,
2897515180,
3013807324,
3133179183,
3255678529,
3381359353,
3510286835,
3642546304,
3778259346,
3917612824,
4060911082,
4208669948,
4361785907,
4521840633,
4691649139,
4876246450,
5084663609,
5333124496,
5650800094,
6090166168,
6745647103,
7787174786,
9520594614,
12496396305,
17705429349,
26931190829,
]


def get_required_score_for_level(level: int) -> int:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am ..not sure how i feel about functions living in constants?

if level <= 0:
return 0
if level <= 100:
return LEVEL_GRAPH[level - 1]
return LEVEL_GRAPH[99] + 100000000000 * int(level - 100)


def get_level(score: int) -> int:
if score <= 0:
return 1

if score >= LEVEL_GRAPH[99]:
return 100 + int((score - LEVEL_GRAPH[99]) / 100000000000)

for idx, v in enumerate(LEVEL_GRAPH, start=0):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you probably want bisect.bisect_left(LEVEL_GRAPH, score) instead

https://docs.python.org/3/library/bisect.html

if v > score:
return idx

return 1


def get_level_precise(score: int) -> float:
baseLevel = get_level(score)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
baseLevel = get_level(score)
base_level = get_level(score)

etc, use pep8 naming please

baseLevelScore = get_required_score_for_level(baseLevel)
scoreProgress = score - baseLevelScore
scoreLevelDifference = get_required_score_for_level(baseLevel + 1) - baseLevelScore

res = float(scoreProgress) / float(scoreLevelDifference) + float(baseLevel)
if math.isinf(res) or math.isnan(res):
return 0

return res
Loading