"""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()}