mirror of
https://github.com/283375/arcaea-offline.git
synced 2025-07-01 04:06:27 +00:00
193 lines
6.1 KiB
Python
193 lines
6.1 KiB
Python
from datetime import datetime, timezone
|
|
from typing import Optional
|
|
from uuid import UUID, uuid4
|
|
|
|
from sqlalchemy import Integer, String, Text, Uuid, case, func, inspect, select, text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
from sqlalchemy_utils import create_view
|
|
|
|
from ._base import ModelBase, ModelViewBase, ReprHelper
|
|
from .chart_info import ChartInfo
|
|
from .difficulty import Difficulty
|
|
|
|
__all__ = [
|
|
"CalculatedPotential",
|
|
"PlayResult",
|
|
"PlayResultBest",
|
|
"PlayResultCalculated",
|
|
]
|
|
|
|
|
|
class PlayResult(ModelBase, ReprHelper):
|
|
__tablename__ = "play_result"
|
|
|
|
id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True)
|
|
uuid: Mapped[UUID] = mapped_column(
|
|
Uuid, nullable=False, unique=True, default=lambda: uuid4()
|
|
)
|
|
song_id: Mapped[str] = mapped_column(String)
|
|
rating_class: Mapped[int] = mapped_column(Integer)
|
|
played_at: Mapped[Optional[datetime]] = mapped_column(
|
|
default=lambda: datetime.now(timezone.utc)
|
|
)
|
|
score: Mapped[int]
|
|
pure: Mapped[Optional[int]]
|
|
pure_early: Mapped[Optional[int]]
|
|
pure_late: Mapped[Optional[int]]
|
|
far: Mapped[Optional[int]]
|
|
far_early: Mapped[Optional[int]]
|
|
far_late: Mapped[Optional[int]]
|
|
lost: Mapped[Optional[int]]
|
|
|
|
max_recall: Mapped[Optional[int]]
|
|
clear_type: Mapped[Optional[int]]
|
|
modifier: Mapped[Optional[int]]
|
|
comment: Mapped[Optional[str]] = mapped_column(Text)
|
|
|
|
|
|
class PlayResultCalculated(ModelViewBase, ReprHelper):
|
|
__tablename__ = "play_results_calculated"
|
|
|
|
id: Mapped[int]
|
|
uuid: Mapped[UUID]
|
|
song_id: Mapped[str]
|
|
rating_class: Mapped[int]
|
|
score: Mapped[int]
|
|
pure: Mapped[Optional[int]]
|
|
pure_early: Mapped[Optional[int]]
|
|
pure_late: Mapped[Optional[int]]
|
|
shiny_pure: Mapped[Optional[int]]
|
|
far: Mapped[Optional[int]]
|
|
far_early: Mapped[Optional[int]]
|
|
far_late: Mapped[Optional[int]]
|
|
lost: Mapped[Optional[int]]
|
|
played_at: Mapped[Optional[datetime]]
|
|
max_recall: Mapped[Optional[int]]
|
|
modifier: Mapped[Optional[int]]
|
|
clear_type: Mapped[Optional[int]]
|
|
potential: Mapped[float]
|
|
comment: Mapped[Optional[str]]
|
|
|
|
__table__ = create_view(
|
|
name=__tablename__,
|
|
selectable=select(
|
|
PlayResult.id,
|
|
Difficulty.song_id,
|
|
Difficulty.rating_class,
|
|
PlayResult.score,
|
|
PlayResult.pure,
|
|
(
|
|
case(
|
|
(
|
|
(
|
|
ChartInfo.notes.is_not(None)
|
|
& PlayResult.pure.is_not(None)
|
|
& PlayResult.far.is_not(None)
|
|
& (ChartInfo.notes != 0)
|
|
),
|
|
PlayResult.score
|
|
- func.floor(
|
|
(PlayResult.pure * 10000000.0 / ChartInfo.notes)
|
|
+ (PlayResult.far * 0.5 * 10000000.0 / ChartInfo.notes)
|
|
),
|
|
),
|
|
else_=text("NULL"),
|
|
)
|
|
).label("shiny_pure"),
|
|
PlayResult.far,
|
|
PlayResult.lost,
|
|
PlayResult.played_at,
|
|
PlayResult.max_recall,
|
|
PlayResult.modifier,
|
|
PlayResult.clear_type,
|
|
case(
|
|
(PlayResult.score >= 10000000, ChartInfo.constant / 10.0 + 2), # noqa: PLR2004
|
|
(
|
|
PlayResult.score >= 9800000, # noqa: PLR2004
|
|
ChartInfo.constant / 10.0
|
|
+ 1
|
|
+ (PlayResult.score - 9800000) / 200000.0,
|
|
),
|
|
else_=func.max(
|
|
(ChartInfo.constant / 10.0)
|
|
+ (PlayResult.score - 9500000) / 300000.0,
|
|
0,
|
|
),
|
|
).label("potential"),
|
|
PlayResult.comment,
|
|
)
|
|
.select_from(Difficulty)
|
|
.join(
|
|
ChartInfo,
|
|
(Difficulty.song_id == ChartInfo.song_id)
|
|
& (Difficulty.rating_class == ChartInfo.rating_class),
|
|
)
|
|
.join(
|
|
PlayResult,
|
|
(Difficulty.song_id == PlayResult.song_id)
|
|
& (Difficulty.rating_class == PlayResult.rating_class),
|
|
),
|
|
metadata=ModelViewBase.metadata,
|
|
cascade_on_drop=False,
|
|
)
|
|
|
|
|
|
class PlayResultBest(ModelViewBase, ReprHelper):
|
|
__tablename__ = "play_results_best"
|
|
|
|
id: Mapped[int]
|
|
uuid: Mapped[UUID]
|
|
song_id: Mapped[str]
|
|
rating_class: Mapped[int]
|
|
score: Mapped[int]
|
|
pure: Mapped[Optional[int]]
|
|
pure_early: Mapped[Optional[int]]
|
|
pure_late: Mapped[Optional[int]]
|
|
shiny_pure: Mapped[Optional[int]]
|
|
far: Mapped[Optional[int]]
|
|
far_early: Mapped[Optional[int]]
|
|
far_late: Mapped[Optional[int]]
|
|
lost: Mapped[Optional[int]]
|
|
played_at: Mapped[Optional[datetime]]
|
|
max_recall: Mapped[Optional[int]]
|
|
modifier: Mapped[Optional[int]]
|
|
clear_type: Mapped[Optional[int]]
|
|
potential: Mapped[float]
|
|
comment: Mapped[Optional[str]]
|
|
|
|
__table__ = create_view(
|
|
name=__tablename__,
|
|
selectable=select(
|
|
*[
|
|
col
|
|
for col in inspect(PlayResultCalculated).columns
|
|
if col.name != "potential"
|
|
],
|
|
func.max(PlayResultCalculated.potential).label("potential"),
|
|
)
|
|
.select_from(PlayResultCalculated)
|
|
.group_by(PlayResultCalculated.song_id, PlayResultCalculated.rating_class)
|
|
.order_by(PlayResultCalculated.potential.desc()),
|
|
metadata=ModelViewBase.metadata,
|
|
cascade_on_drop=False,
|
|
)
|
|
|
|
|
|
class CalculatedPotential(ModelViewBase, ReprHelper):
|
|
__tablename__ = "calculated_potential"
|
|
|
|
b30: Mapped[float]
|
|
|
|
_select_bests_subquery = (
|
|
select(PlayResultBest.potential.label("b30_sum"))
|
|
.order_by(PlayResultBest.potential.desc())
|
|
.limit(30)
|
|
.subquery()
|
|
)
|
|
__table__ = create_view(
|
|
name=__tablename__,
|
|
selectable=select(func.avg(_select_bests_subquery.c.b30_sum).label("b30")),
|
|
metadata=ModelViewBase.metadata,
|
|
cascade_on_drop=False,
|
|
)
|