This commit is contained in:
team3
2026-09-16 15:03:56 +02:00
parent a639e40a23
commit bfaf0313c1
3 changed files with 484 additions and 195 deletions

View File

@@ -260,7 +260,7 @@ def drehen():
"""Einer dreht, alle sehen dasselbe Ergebnis."""
laeuft = (
letzter_dreh["ergebnis"]
and time.monotonic() - letzter_dreh["start"] < suggestions.DREH_DAUER
and time.monotonic() - letzter_dreh["start"] < letzter_dreh["ergebnis"]["dauer"]
)
if laeuft:
return {"started": False, "reason": "dreht bereits"}
@@ -283,7 +283,7 @@ def letzter():
return {"running": False, "result": None}
vergangen = time.monotonic() - letzter_dreh["start"]
return {
"running": vergangen < suggestions.DREH_DAUER,
"running": vergangen < ergebnis["dauer"],
# Wer später dazukommt, überspringt den bereits gelaufenen Teil
"elapsed": round(vergangen, 2),
"result": ergebnis,

View File

@@ -1,4 +1,4 @@
"""Filmvorschläge fürs Rad.
"""Filmvorschläge für die Ziehung.
Jede Sitzung darf einen Film vorschlagen. Die Sitzung erkennt ein Cookie —
ohne Anmeldung geht es nicht genauer, und für einen Filmabend im Freundeskreis
@@ -37,7 +37,19 @@ COOKIE = "filmabend_sid"
# So lange läuft die Animation im Browser. Der Server merkt sich das
# Ergebnis mit, damit eine Seite, die mitten im Dreh geladen wird, es
# trotzdem bekommt.
DREH_DAUER = 4.2
DREH_DAUER = 11.2
# Die Ziehung läuft wie das Öffnen einer Lootbox: ein Streifen aus
# Postern rast vorbei und bremst auf dem Gewinner aus. Der Streifen ist
# so lang, und an dieser Stelle steht der Treffer.
STREIFEN_LAENGE = 64
STREIFEN_ZIEL = 56
# Manchmal bricht nach dem Halt die Halterung: die Bahn rutscht ein paar
# Poster zurück, und ein anderer gewinnt. So lange dauert das im Browser
# zusätzlich (Ruhe plus Rückfahrt — die Werte stehen auch in WheelTab.vue).
BRUCH_DAUER = 3.7
BRUCH_ANTEIL = 0.5
def init():
@@ -112,11 +124,19 @@ def ersetzen(session_id, movie, name=None):
return anlegen(session_id, movie, name)
def _versatz():
"""Wo genau im Poster die Marke stehen bleibt — nie exakt mittig.
Jedes zweite Mal ganz knapp an der Kante: fast der andere."""
if random.random() < 0.5:
return round(random.choice((-1, 1)) * random.uniform(0.34, 0.46), 3)
return round(random.uniform(-0.3, 0.3), 3)
def ziehen():
"""Server lost aus, damit alle Seiten dasselbe Ergebnis sehen.
Der Zielwinkel gehört dazu: sonst dreht jede Seite woanders hin und
der Zeiger stünde am Ende auf einem anderen Segment.
Der Streifen gehört dazu: sonst zeigt jede Seite andere Poster
vorbeirauschen, und der Treffer stünde am Ende woanders.
"""
eintraege = alle()
if not eintraege:
@@ -130,26 +150,38 @@ def ziehen():
}
frisch = [i for i, e in enumerate(eintraege) if e["movie_id"] not in gesehen]
treffer = random.choice(frisch) if frisch else random.randrange(len(eintraege))
schritt = 360 / len(eintraege)
runden = 5 + random.randrange(3)
# Der Zeiger steht oben, also muss die Mitte des Zielsegments dorthin.
# Ein einzelner Vorschlag ist ein Vollkreis mit Cover — der soll nach
# dem Dreh aufrecht stehen, also bei 0° enden statt bei 180°.
if len(eintraege) == 1:
winkel = runden * 360
else:
winkel = runden * 360 + (360 - (treffer * schritt + schritt / 2))
# Blockweise gemischt: jeder Vorschlag kommt gleich oft vorbei
streifen = []
while len(streifen) < STREIFEN_LAENGE:
block = list(range(len(eintraege)))
random.shuffle(block)
streifen.extend(block)
streifen = streifen[:STREIFEN_LAENGE]
# Wo die Bahn hält — beim Bruch zweimal, und erst der zweite Halt zählt
stopps = [{"position": STREIFEN_ZIEL, "versatz": _versatz()}]
ziel = STREIFEN_ZIEL
if random.random() < BRUCH_ANTEIL:
ziel = STREIFEN_ZIEL - random.randint(1, 4)
stopps.append({"position": ziel, "versatz": _versatz()})
# Der erste Halt zeigt einen anderen — sonst wäre der Bruch egal
andere = [i for i in range(len(eintraege)) if i != treffer]
streifen[STREIFEN_ZIEL] = random.choice(andere) if andere else treffer
streifen[ziel] = treffer
def karte(e):
return {k: v for k, v in e.items() if k not in ("session_id", "user_id")}
return {
"index": treffer,
"winkel": winkel,
"dauer": DREH_DAUER,
"gewinner": {
k: v
for k, v in eintraege[treffer].items()
if k not in ("session_id", "user_id")
},
"anzahl": len(eintraege),
"streifen": streifen,
"stopps": stopps,
"dauer": DREH_DAUER + (BRUCH_DAUER if len(stopps) > 1 else 0),
# Der Streifen zeigt diesen Stand, auch wenn danach jemand einen
# Vorschlag dazutut
"karten": [karte(e) for e in eintraege],
"gewinner": karte(eintraege[treffer]),
}