Offene Algorithmen & Code
Jeder Algorithmus, der dein Erlebnis beeinflusst, ist hier dokumentiert — in verständlicher Sprache, mit den tatsächlichen Formeln und direkten Links zum Quellcode.
Wenn ein Algorithmus entscheidet, wer dein Profil sieht, wie deine Zuverlässigkeit bewertet wird oder welche Sessions in deinem Feed erscheinen — diese Entscheidungen beeinflussen reale Begegnungen. Eine Strafe für späte Absagen ist nicht nur eine Zahl; sie ist der Unterschied zwischen einem vollen Tisch und einem abgesagten Spieleabend.
Wir glauben, dass du es verdienst zu verstehen, wie jedes Bewertungs- und Matching-System funktioniert. Nicht in vagen Marketing-Begriffen — in echter Mathematik, mit den realen Gewichtungen, Schwellenwerten und Design-Kompromissen erklärt.
Jeder Abschnitt unten dokumentiert eines unserer Algorithmensysteme. Du findest die Formel, die Überlegungen hinter wichtigen Entscheidungen und einen direkten Link zum Quellcode auf GitHub. Wenn etwas nicht stimmt, kannst du ein Issue eröffnen.
Algorithmus-Verzeichnis
Spieler-Zuverlässigkeitswert
Der Spieler-Zuverlässigkeitswert ist eine auf Teilnahme basierende Kennzahl, die deine tatsächliche Historie an Spieltischen widerspiegelt — nicht deine Beliebtheit, nicht deine sozialen Verbindungen, nur ob du auftauchst, wenn du es sagst.
So funktioniert's
Score = (weighted_sum / game_count) × 100
Begrenzt auf Bereich [0%, 100%]
| Status | Spieler-Gewichtung | Host-Gewichtung |
|---|---|---|
| Teilgenommen | +1.0 | +1.0 |
| Späte Absage (<24h) | −0.3 | −1.2 |
| Nicht erschienen | −1.0 | −1.5 |
| Entschuldigt | 0.0 | 0.0 |
| Früh abgesagt (>24h) | 0.0 | 0.0 |
Stufen-Klassifikation
≥ 95% und ≥ 5 Spiele
≥ 5 Spiele (jeder Punktestand)
< 5 Spiele
Design-Entscheidungen
- Gastgeber erhalten strengere Strafen für späte Absagen und Nichterscheinen, da sie jeden angemeldeten Teilnehmer dieses Spiels betreffen, nicht nur sich selbst.
- Troll-Resistenz: Die Anwesenheit wird durch einen gewichteten Konsens der Meldungen geklärt (siehe Anwesenheits-Auflösung) — ein einzelner Melder kann also keinen Status festlegen. Erst eine Teilnahme-Schwelle und eine Mehrheit müssen zustimmen, bevor eine Strafe greift.
- Werte werden bei jeder Anwesenheitsänderung vollständig neu berechnet (nicht delta-basiert), um Korrektheit zu garantieren und Drift zu verhindern.
Anwesenheits-Auflösung
Wenn ein Spiel endet, können Gastgeber und Teilnehmer jeweils einen Anwesenheitsbericht für dieselbe Person abgeben — und sie sind sich nicht immer einig. Die Anwesenheits-Auflösung führt diese Berichte in einem einzigen, verbindlichen Status zusammen, der in den Spieler-Zuverlässigkeitswert einfließt. Es ist ein Konsens-System mit einer bewussten Tendenz zu „Teilgenommen": eine Abwesenheit muss durch eine Mehrheit bewiesen werden, nie einfach angenommen.
Auflösungsmethoden
Jeder genehmigte Teilnehmer hat einen Bericht abgegeben, sodass der Status bei Spielende sofort feststeht — ohne Wartezeit.
Wenn die Meldungen ausbleiben, schließt sich das Spiel automatisch nach Ablauf des Zeitfensters und klärt jeden Spieler anhand der vorliegenden Berichte.
Eine Administratorin oder ein Administrator kann die Anwesenheit direkt auflösen, wenn ein Streitfall eine menschliche Entscheidung erfordert.
Wie ein Status entschieden wird
Mindestens die Hälfte der übrigen Teilnehmer muss berichten. Darunter gilt der Spieler als „Teilgenommen".
Wenn der Gastgeber eine Person als „Entschuldigt" markiert, setzt sich das durch — der Gastgeber ist nur für Entschuldigungen maßgeblich.
Mehr als die Hälfte der gewichteten Stimmen muss auf „Nicht erschienen" lauten, damit eine Abwesenheit festgehalten wird.
Alles andere — ein Gleichstand, keine Berichte oder ein Solo-Spiel — wird als „Teilgenommen" aufgelöst.
Berichte können bis zu 72 Stunden nach Spielende abgegeben werden; Spiele schließen 12 Stunden nach ihrer geplanten Endzeit automatisch ab.
Design-Entscheidungen
- Standard Teilgenommen: Kein einzelner Bericht kann einen Spieler jemals bestrafen. Eine Abwesenheit erfordert eine bewiesene Mehrheit.
- Der Gastgeber kann entschuldigen, aber nur der Konsens kann ein „Nicht erschienen" festlegen — die Gastgeber-Befugnis ist bewusst begrenzt.
- Berichte werden gewichtet, sodass unzuverlässige Melder weniger Einfluss haben. Die genauen Schwellen zum Missbrauchsschutz werden bewusst nicht veröffentlicht.
SL-Bewertungen & Rezensionen
SL-Bewertungen aggregieren Community-Feedback für Spielleiter in einen Durchschnittswert und eine Rezensionsanzahl. Nur veröffentlichte Rezensionen fließen in die Aggregation ein — gemeldete oder versteckte Rezensionen werden vollständig ausgeschlossen.
So funktioniert's
Durchschnittsbewertung = COALESCE(AVG(rating), 0)
Anzahl Bewertungen = COUNT(*) WHERE status = 'published'
Kompetenzabzeichen = TOP 3 Tags nach Häufigkeit in veröffentlichten Bewertungen
Nur Rezensionen mit Status „veröffentlicht" sind eingeschlossen. Gemeldete oder versteckte Rezensionen werden von allen Berechnungen ausgeschlossen.
Design-Entscheidungen
- Nur veröffentlichte Rezensionen zählen für den Durchschnitt. Gemeldete oder versteckte Rezensionen werden ausgeschlossen, um Manipulation zu verhindern und Fairness zu gewährleisten.
- Aggregate werden neu berechnet, wenn eine Rezension erstellt oder gelöscht wird oder ihren Status ändert (z. B. wenn eine gemeldete Rezension versteckt oder wiederhergestellt wird). So bleibt der angezeigte Wert mit dem aktuellen veröffentlichten Bestand synchron.
Spieler-Entdeckung
Die Spieler-Entdeckung schlägt dir nahegelegene Spieler basierend auf Geschmackskompatibilität und sozialer Überschneidung vor. Sie nutzt deine Spielsystem-Präferenzen, Vibe-Präferenzen, Team-Mitgliedschaften und sozialen Verbindungen, um Leute zu finden, mit denen du gerne spielst. Die Ergebnisse werden von einem Hintergrund-Job vorberechnet und aus dem Cache geliefert für schnelle Ladezeiten.
Verarbeitungspipeline
Führt eine einzelne Abfrage über die 4-stellige Geohash-Kachel (~20 km) und die umgebende 3-stellige Kachel (~100 km) gleichzeitig aus, sodass Stadt- und Regionalnachbarn zusammen erfasst werden. Blockierte Nutzer und bestehende Folgen werden per SQL-Unterabfrage ausgeschlossen. Der geografische Kandidaten-Pool ist auf 50 begrenzt, um den Speicher zu schonen.
Wenn der Betrachter Lieblingsspielsysteme hat, werden zusätzliche Kandidaten mit denselben Präferenzen einbezogen — auch außerhalb des geografischen Radius — um Geschmacksaffinität abzubilden.
Eine einzelne SQL-JOIN-Abfrage berechnet alle Überschneidungen (gemeinsame Spielsysteme, Vibes, Teams und gegenseitige Folgen) direkt in der Datenbank. Dadurch wird das Laden großer Datenmengen in PHP vermieden. Die Datenbank liefert höchstens 100 bewertete Zeilen zurück.
Berechnet Geschmacksähnlichkeit (Jaccard auf Spielsystemen + Vibes) und soziale Überschneidung (Team-Überschneidung + gegenseitige Folgen). Ergebnisse sind datenschutzbewusst: versteckte Felder reduzieren verfügbare Signale.
Ergebnisse werden von einem Hintergrund-Job vorberechnet und pro Betrachter und Geohash-Kachel 5 Minuten lang zwischengespeichert. Die Seite liest nur aus dem Cache — wenn der Cache leer ist, wird ein „Wir suchen noch"-Status angezeigt, während der Job läuft. Paginiert mit 12 pro Seite.
So funktioniert's
Geschmack: J(A, B) = |A ∩ B| / |A ∪ B|
Computed on game systems + vibes, averaged
Sozial: (Team-Überschneidung + gegenseitiges Folgen) / Komponenten
Zusammengesetzt:
if taste & social: score = taste × 0.7 + social × 0.3
if taste only: score = taste
if social only: score = social
| Komponente | Gewichtung (beide verfügbar) |
|---|---|
| Geschmacksähnlichkeit | 0.7 |
| Soziale Überschneidung | 0.3 |
Wenn nur ein Signaltyp verfügbar ist, erhält er 100% Gewichtung.
Design-Entscheidungen
- Datenschutzbewusste Neugewichtung: Wenn ein Kandidat versteckte Felder hat (Spielsysteme, Vibes, Teams), werden diese Signale von der Bewertung ausgeschlossen und die verbleibenden Signale erhalten anteilig mehr Gewicht.
- Blockierte Nutzer werden vollständig vom Kandidatenpool ausgeschlossen — sie erscheinen nie als Entdeckungsergebnis.
- Wenn alle Signale versteckt sind (nur Standort sichtbar), erscheint der Kandidat mit „In der Nähe" als einzigem Treffergrund, damit die UI trotzdem etwas Sinnvolles anzeigt.
Session-Empfehlungen
Session-Empfehlungen schlagen dir Spiele und Kampagnen vor, die zu deinen Präferenzen passen. Sie nutzen einen zweistufigen Ansatz, um die besten Treffer zuerst anzuzeigen, ohne Nutzer zu benachteiligen, die keine Vibe-Präferenzen festgelegt haben.
Two-Query-Ansatz
Findet Sessions, die deine Lieblings-Spielsysteme UND Lieblings-Vibes teilen. Das sind die stärksten Treffer.
Findet Sessions nach Lieblings-Spielsystemen unabhängig von Vibes. Zeigt relevante Sessions auch ohne Vibe-Überschneidung.
Ergebnisse werden nach Typ+ID dedupliziert, wobei erweiterte Ergebnisse zuerst angezeigt werden. Maximal 12 Empfehlungen gesamt.
Präferenzauflösung
erlaubt = (Favoriten + implizierte_Favoriten) − vermiedene
Boosted: erlaubt UND Lieblingsvibes
Fallback: erlaubt (alle Vibes)
| Regel | Verhalten |
|---|---|
| Basis-Spiel favorisiert | Erweiterungen werden zu impliziten_Favoriten |
| Explizit vermieden | Hat immer Vorrang vor Favorit oder implizit |
| Vibe-Exklusivität | Einen favorisieren vermeidet automatisch seinen Partner |
Design-Entscheidungen
- Favorisierte Basisspiele schließen automatisch ihre Erweiterungen als „implizite Favoriten" ein — du musst nicht jede Erweiterung einzeln favorisieren.
- Explizite Meidungs-Präferenzen haben immer Vorrang vor Favoriten oder impliziten — wenn du ein System meidest, bleibt es ausgeschlossen, auch wenn es eine Erweiterung eines Favoriten ist.
- Vibe-Gegenseitigkeit: Einen Vibe zu favorisieren meidet automatisch seinen Partner (z. B. „Kompetitiv" meidet automatisch „Kooperativ").
Treffen
Ein Treffen (Gathering) ist eine leichtere, systemübergreifende Session wie ein Brettspiel-Abend. In den Entdeckungs-Feeds sind Treffen auf etwa eines pro Seite begrenzt und werden bei gleichem Datum knapp unter fokussierten Einzelsystem-Spielen eingeordnet, damit sie nie spezifische Spiele verdrängen. In deinen Empfehlungen erscheint ein Treffen, sobald eines der angebotenen Systeme deinen Favoriten entspricht — behandelt wie jedes andere Spiel.
Näherungs-Engine
Die Näherungs-Engine betreibt geografische Abfragen zum Finden nahegelegener Sessions, Spieler und Veranstaltungsorte. Sie nutzt einen zweiphasigen Ansatz: einen schnellen Bounding-Box-Filter gefolgt von präziser Haversine-Abstandsberechnung.
Zweiphasen-Ansatz
Nutzt einen zusammengesetzten (Breitengrad, Längengrad) B-Baum-Index für schnelle Zeileneliminierung. Das Rechteck ist die kleinste Box, die den Suchkreis enthält — ihre Ecken reichen über den Kreis hinaus, sodass nichts übersehen wird.
Wendet die Haversine-Formel für präzise Abstandsberechnung an und filtert Ergebnisse auf den exakten Radius.
So funktioniert's
d = 2R × arcsin(√(
sin²(Δlat / 2) +
cos(lat₁) × cos(lat₂) × sin²(Δlng / 2)
))
wobei R = 6371 km (Erdradius)
Geohash-Kachelgrößen
| Präzision | Ungefähre Größe | Verwendung |
|---|---|---|
| 4 chars | ~20km × 20km | Städtisches Caching |
| 5 chars | ~4.9km × 4.9km | Nachbarschaftsebene |
| 6 chars | ~0.6km × 1.2km | Veranstaltungsortebene |
Hub-Ergebnisse werden pro Geohash-Kachel (5-stellig ≈ 4,9 km × 4,9 km) mit 15-minütiger TTL zwischengespeichert.
Design-Entscheidungen
- Die Bounding-Box ist das kleinste Rechteck, das den Suchkreis umschließt (ihre Ecken ragen über den Kreis hinaus). Die Haversine-Formel filtert dann auf den genauen Radius — dieser zweiphasige Ansatz nutzt den B-Baum-Index für Geschwindigkeit.
Standort-Offenlegung & Datenschutz
Jede Adresse und Entfernung, die du siehst — auf einer Spiel-, Kampagnen- oder Veranstalterseite — wird von einem einzigen Service entschieden. Die Standort-Offenlegung staffelt, wie viel von einem Ort sichtbar wird, basierend auf der Art des Ortes und deinem Verhältnis zum Gastgeber. Datenschutz ist der Standard, nicht die Ausnahme.
Adress-Stufen
Vollständige Straßenadresse
Nur der Ortsname
„In deiner Nähe" (geohash-basiert)
Nichts sichtbar (blockierter Betrachter oder nicht auflösbarer Ort)
Entscheidungsmatrix (private Orte)
| Dein Verhältnis zum Gastgeber | Angezeigte Adresse |
|---|---|
| Gastgeber oder genehmigter Teilnehmer | Exakt |
| Freund oder Teammitglied | Stadt |
| Fremder oder Gast | Region |
| Blockiert | Keine |
Verifizierte gewerbliche Veranstaltungsorte (Cafés, Spieleläden, Bibliotheken, Gemeindezentren, Conventions, Bars) zeigen jedem ihre exakte Adresse — sie sind öffentliche Räume.
Entfernungsanzeige
Genaue Entfernung (z. B. „4,2 km entfernt")
Auf das nächste 5-km-Raster gerundet (z. B. „≈ 5 km entfernt"), mit einer 5-km-Schwelle — exakte Positionen lassen sich nicht trilaterieren.
Design-Entscheidungen
- Fail-closed: Wenn sich etwas nicht bestimmen lässt, offenbart der Service das Mindeste (Region oder nichts) — nie mehr.
- Genaue Entfernungen sind verifizierten öffentlichen Orten vorbehalten. Private Orte erhalten immer eine gerasterte Entfernung, um Trilateration zu verhindern.
- Eine öffentliche Veranstalterseite erfordert einen gewerblichen Typ, der verifiziert oder admin-verwaltet ist. „Sonstige" und typenlose Orte kommen nie infrage.
Trending & Beliebt
Trending in deiner Nähe zeigt standortbezogene Spiele-Sessions basierend auf der Teilnehmerbeteiligung in deinem geografischen Bereich.
Auswahlkriterien
| Parameter | Wert |
|---|---|
| Geografischer Bereich | Geohash-4-Kachel (~20km × 20km) (~20km × 20km) |
| Zeitraum | Nächste 14 Tage |
| Sichtbarkeit | Nur öffentliche Sessions |
| Sortierung | participants DESC, created_at DESC |
| Obergrenze | Top 5 per tile |
| Cache-TTL | 10 minutes |
Design-Entscheidungen
- Das 14-Tage-Zeitfenster verhindert, dass historisch beliebte Spiele dominieren — nur anstehende Sessions werden berücksichtigt.
- Geohash-4-Begrenzung (~20 km × 20 km) hält die Ergebnisse echt lokal, statt beliebte Spiele von der anderen Seite der Stadt anzuzeigen.
Plattform-Score
Der Plattform-Score rangiert Spielsysteme nach Community-Engagement mittels einer gewichteten Formel, die Favoriten, Spiele gesamt, Kampagnen und aktive (geplante) Sessions berücksichtigt.
So funktioniert's
score = (favorites × w₁) + (games × w₂)
+ (campaigns × w₃) + (active_games × w₄)
| Metrik | Brettspiele | Pen-&-Paper-RPGs |
|---|---|---|
| Favoriten | 10 | 10 |
| Spiele gesamt | 3 | 3 |
| Kampagnen | 5 | 15 |
| Aktive Spiele (geplant) | 20 | 10 |
Design-Entscheidungen
- Brettspiele gewichten aktive Sessions am höchsten (20 Punkte), da ein aktuell geplantes Spiel das stärkste Signal für Community-Engagement ist.
- TTRPGs gewichten Kampagnen am höchsten (15 Punkte), da laufendes Kampagnenspiel die primäre Aktivitätskennzahl für Tabletop-Rollenspielgruppen ist.
Lies den Code selbst
Jeder hier dokumentierte Algorithmus läuft aus unserem Open-Source-Repository. Klone es, prüfe es, eröffne ein Issue — es gehört dir.