Files
horror/backend/app/punkte.py
2026-09-29 00:54:58 +02:00

76 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Erfahrung und Level — berechnet, nicht gebucht.
Punkte sind eine Formel über dem, was gerade in der Datenbank steht:
wer dabei war, bewertet, kommentiert, geantwortet und ein Herz gegeben
hat. Nimmt jemand seine Wertung zurück, sind die Punkte weg. Es gibt
kein Konto, das man pflegen oder austricksen könnte.
Je Film zählt jede Art nur einmal. Level nach Dreieckszahlen: Level L
ist erreicht, sobald L·(L−1)/2 Punkte da sind — anfangs schnell, dann
stetig langsamer, aber immer in Reichweite.
"""
from math import isqrt
from .db import connect
SCHAUEN = 10
BEWERTEN = 3
KOMMENTAR = 5
ANTWORT = 2
HERZ = 1
ZAEHLUNGEN = (
(SCHAUEN, "SELECT user_id, COUNT(*) AS n FROM watched_dabei GROUP BY user_id"),
(
BEWERTEN,
"SELECT user_id, COUNT(DISTINCT watched_id) AS n FROM ratings "
"WHERE user_id IS NOT NULL GROUP BY user_id",
),
(
KOMMENTAR,
"SELECT user_id, COUNT(DISTINCT watched_id) AS n FROM watched_notes "
"WHERE user_id IS NOT NULL AND parent_id IS NULL GROUP BY user_id",
),
(
ANTWORT,
"SELECT user_id, COUNT(DISTINCT watched_id) AS n FROM watched_notes "
"WHERE user_id IS NOT NULL AND parent_id IS NOT NULL GROUP BY user_id",
),
(
HERZ,
"SELECT h.user_id, COUNT(DISTINCT n.watched_id) AS n FROM watched_hearts h "
"JOIN watched_notes n ON n.id = h.note_id "
"WHERE h.user_id IS NOT NULL GROUP BY h.user_id",
),
)
def level(punkte):
"""Größtes L mit L·(L−1)/2 ≤ Punkte. Null Punkte sind Level 1."""
stufe = (1 + isqrt(1 + 8 * punkte)) // 2
while stufe * (stufe - 1) // 2 > punkte:
stufe -= 1
return max(1, stufe)
def stand(punkte):
stufe = level(punkte)
return {
"punkte": punkte,
"level": stufe,
# Wo das aktuelle Level begann und wo das nächste anfängt — für den Balken
"von": stufe * (stufe - 1) // 2,
"bis": stufe * (stufe + 1) // 2,
}
def alle():
"""Punktestand je user_id."""
summen = {}
with connect() as conn:
for wert, sql in ZAEHLUNGEN:
for row in conn.execute(sql):
summen[row["user_id"]] = summen.get(row["user_id"], 0) + wert * row["n"]
return {user_id: stand(p) for user_id, p in summen.items()}