96 lines
3.1 KiB
Python
96 lines
3.1 KiB
Python
"""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
|
||
|
||
# Für den Info-Reiter: was zählt, mit der Zahl — aus denselben Konstanten
|
||
REGELN = (
|
||
("Beim Filmabend dabei", SCHAUEN),
|
||
("Film mit Sternen bewertet", BEWERTEN),
|
||
("Kommentar geschrieben", KOMMENTAR),
|
||
("Auf einen Kommentar geantwortet", ANTWORT),
|
||
("Herz vergeben", HERZ),
|
||
)
|
||
|
||
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 vorlage():
|
||
"""Der Info-Text, solange der Host keinen eigenen geschrieben hat —
|
||
die Regeln mit ihren Zahlen und die ersten Levelstufen, als Markdown."""
|
||
zeilen = ["## Erfahrung", ""]
|
||
zeilen += [f"- {was}: **+{p}**" for was, p in REGELN]
|
||
zeilen += ["", "Je Film zählt jede Art nur einmal.", "", "## Level", ""]
|
||
stufen = ", ".join(f"Level {stufe} ab {stufe * (stufe - 1) // 2}" for stufe in range(2, 8))
|
||
zeilen.append(f"{stufen} … Jedes weitere Level kostet einen Punkt mehr als das davor.")
|
||
return "\n".join(zeilen)
|
||
|
||
|
||
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()}
|