No description
  • Dart 94.9%
  • CMake 1.7%
  • Python 1.3%
  • C++ 1.2%
  • Shell 0.7%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Sebastian 0e550661d5 Abgeschlossen ist wirklich zu, und der Bereich bleibt stehen
Nacharbeit aus einem Review des Standes seit 1.11.1.

Abschluss: der Riegel hing allein an der Oberflaeche - eine Regel, die
allein an der Anzeige haengt, faellt beim ersten Aufruf von woanders.
Ein neuer Waechter _assertRunning prueft Leitung UND Status und sitzt
jetzt am Melden, am Zuruecknehmen, am Ansetzen eines Tisches bei "jeder
gegen jeden" und am Starten der Uhr. Fortsetzen zaehlt als Anspringen
und wird mitgeprueft; Pausieren und Verstellen nicht - beide setzen
eine laufende Uhr voraus und koennen keine in Gang setzen.

Bereich: beim Abschliessen sprang die Anzeige auf den Baum, und zwar in
genau der Bewegung, mit der man das letzte Ergebnis eingetippt hat.
_runStep haelt jetzt fest, was zu sehen ist. Ein abgeschlossenes Event
aus der Historie oeffnet weiter auf dem Baum - das ist die erste
Ansicht und keine Umschaltung.

Regeln: die Beschreibung der Dokumentenliste nannte die Sammelseite als
zweite Adresse, sie steht an dritter Stelle, und datiert sind zwei von
vier statt drei. In der Klassen-Doku und in CLAUDE.md nachgezogen.

Ein haengender Doc-Kommentar in event.dart, uebriggeblieben von
kMaxPlayersPerEvent, ist ein normaler Kommentar geworden.

Drei neue Tests: ein abgeschlossenes Turnier weist Meldung, Uhr und
Tischansage ab, und der Bereich bleibt beim Abschliessen stehen.

Version 1.14.1+29.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 11:43:20 +02:00
android Ein Name und ein Zeichen: de.dompasero.turnierwart und das Hexagon 2026-08-23 22:03:20 +02:00
assets/sounds Ausfuehrliche Doku in docs/, und "overtime" aus einem neuronalen Modell 2026-08-24 15:20:33 +02:00
docs Kein Feldlimit, der Weg durch den Baum, Ton auf dem Medienkanal 2026-08-24 22:14:52 +02:00
lib Abgeschlossen ist wirklich zu, und der Bereich bleibt stehen 2026-08-25 11:43:20 +02:00
linux Ein Name und ein Zeichen: de.dompasero.turnierwart und das Hexagon 2026-08-23 22:03:20 +02:00
test Abgeschlossen ist wirklich zu, und der Bereich bleibt stehen 2026-08-25 11:43:20 +02:00
tool Ausfuehrliche Doku in docs/, und "overtime" aus einem neuronalen Modell 2026-08-24 15:20:33 +02:00
.gitignore Turnierwart: Draft-Turnierleitung für Linux-Desktop 2026-08-23 09:57:50 +02:00
.metadata Android als zweite Plattform, Oberfläche für schmale Bildschirme 2026-08-23 10:53:16 +02:00
analysis_options.yaml Turnierwart: Draft-Turnierleitung für Linux-Desktop 2026-08-23 09:57:50 +02:00
CLAUDE.md Abgeschlossen ist wirklich zu, und der Bereich bleibt stehen 2026-08-25 11:43:20 +02:00
pubspec.lock Der laufende Tisch ueberlebt die Uebergabe, die Uhr startet wirklich neu 2026-08-24 16:45:26 +02:00
pubspec.yaml Abgeschlossen ist wirklich zu, und der Bereich bleibt stehen 2026-08-25 11:43:20 +02:00
README.md Kein Feldlimit, der Weg durch den Baum, Ton auf dem Medienkanal 2026-08-24 22:14:52 +02:00

turnierwart

Leitet Magic-Draft-Events: Paarungen nach Schweizer System, K.O.-Baum und Tabelle nach den offiziellen Turnierregeln. Ausgelegt auf den klassischen Draft-Pod jeder Größe. Läuft auf dem Linux-Desktop und auf Android, alles liegt lokal — ohne Konto, ohne Cloud, ohne Netz.

Dokumentation

Datei Inhalt
docs/einstieg.md Ohne Vorwissen: Entstehung, Sprachwahl, jede Datei einzeln, Tests, erster eigener Lauf
docs/projekt.md Technisch: Schichten, Datenmodell, Zustandsfluss, Referenz, Entscheidungen
docs/regeln.md Die Turnierregeln, wie sie hier gerechnet werden — mit Zahlenbeispielen
docs/betrieb.md Der Turnierabend: anlegen, Uhr, melden, korrigieren, übergeben, sichern
docs/bauen.md Bauen und Ausliefern für Linux und Android, Versionierung, Klänge, Icons
docs/fehlerquellen.md Selbst prüfen: was hier schiefgehen kann und wie man einen Verdacht belegt

CLAUDE.md daneben ist kein Ersatz dafür, sondern die Kurzfassung der Entscheidungen für die Arbeit am Quelltext — dicht geschrieben und ohne Einführung.

Was es kann

  • Vier Modi: reines Schweizer System, reines K.O., Schweizer Vorrunde mit anschließendem Top-Cut (der Normalfall beim Draft) und „jeder gegen jeden".
  • Paarung ohne Wiedersehen. In kleinen Feldern wird die optimale Paarung exakt berechnet, nicht geschätzt. Ist eine rematchfreie Runde möglich, findet die App sie; ist keine möglich, weist sie das aus, statt es zu verschweigen.
  • Tabelle nach den offiziellen Regeln (MTR 5.3): Matchpunkte, dann OMW%, GW% und OGW%. Die Werte stehen sichtbar in der Tabelle — bei Punktgleichstand ist genau das die Antwort auf „warum steht der vor mir?".
  • Ergebnisse in einem Klick. Fünf Knöpfe je Tisch: 2:0, 2:1, Remis, 1:2, 0:2. Eine Korrektur ist derselbe Handgriff wie die Erstmeldung.
  • Rundenuhr mit zwei akustischen Zurufen: zwei lange Pieptöne bei zehn Minuten Restzeit, drei tiefere und das gesprochene Wort „overtime" beim Ablauf. Sie läuft nach einem Neustart weiter und hält mit der letzten Meldung der Runde von selbst an.
  • Byes bei ungerader Teilnehmerzahl, automatisch an den letzten der Tabelle, der noch keines hatte, und sofort als 2:0 gewertet.
  • Aussteigen mitten im Turnier: die Punkte bleiben in der Tabelle stehen, gepaart wird nicht mehr.
  • Übergabe an ein anderes Gerät als Datei — der Draft beginnt am Rechner und geht am Telefon weiter, ohne dass jemand doppelt tippt.
  • Spielerstamm mit Vor- und Nachnamen, Historie aller abgeschlossenen Events und Export in vier Fassungen.
  • Regeln an Bord: die offiziellen Dokumente (MTR, JAR, Regelwerk) verlinkt und die App selbst erklärt — nachgeschlagen wird zwischen zwei Runden.

Ein Abend in acht Schritten

Neues Event  →  Modus und Teilnehmer wählen  →  Turnier starten
     →  Uhr starten  →  Ergebnisse melden  →  Nächste Runde auslosen
     →  Top-Cut auslosen  →  Turnier abschließen  →  Export

Ausführlich in docs/betrieb.md.

Namen

Erfasst werden Vorname und Nachname getrennt, der Nachname freiwillig. Angezeigt wird davon so wenig wie möglich:

Im Turnier sind Angezeigt wird
Anna Bauer, Bert Meier Anna, Bert
Anna Bauer, Anna Meier Anna B., Anna M.
Anna Bauer, Anna Berger, Anna Meier Anna Bauer, Anna Berger, Anna M.

Gerechnet wird über das Feld dieses Turniers, nicht über den Spielerstamm: dass es im Stamm eine dritte Anna gibt, ändert nichts daran, wie der Zettel von heute Abend zu lesen ist.

Die zentralen Rechenregeln

Alles Turnierrechnende steckt in lib/core/tournament/ — reines Dart, ohne Datenbank und ohne Flutter, vollständig durch Tests abgesichert. Ausführlich in docs/regeln.md.

Tabelle (standings.dart): Matchpunkte 3/1/0. Danach OMW% (Mittel der Match-Winrate aller Gegner), GW% (eigene Spiel-Winrate), OGW%. Jeder Einzelwert hat einen Boden von 33 % — sonst würde bestraft, wer gegen einen Aussteiger gelost wurde. Ein Bye zählt als 2:0-Sieg für den Spieler, ist aber kein Gegner und geht nicht in OMW%/OGW% ein.

Paarung (swiss_pairing.dart): Der Punktabstand innerhalb eines Tisches geht quadratisch in die Kosten ein, ein Wiedersehen mit sehr hohem Aufschlag. Aus allen möglichen Paarungen wird die günstigste gewählt — bei bis zu 14 Spielern exakt und nicht geschätzt.

Baum (bracket.dart): klassische Setzung, 1 gegen den Letzten; die beiden Bestgesetzten können sich frühestens im Finale treffen. Krumme Cut-Größen füllen den Baum mit Freilosen für die oberen Setzplätze.

Jeder gegen jeden (round_robin.dart): kein Rundenraster. Alle Begegnungen stehen beim Start fest, gespielt wird, sobald zwei Spieler frei sind.

Tabelle und Baum werden nie gespeichert, immer gerechnet. Es gibt genau eine Wahrheit — die gemeldeten Ergebnisse. Eine Korrektur wirkt sich damit sofort überall aus.

Ausgabeformate

Drei Fassungen desselben Events, und die Trennlinie liegt zwischen Festbreitenschrift und proportionaler:

Fassung Wofür
Chat Der ganze Verlauf, ohne Spalten, die beim Einfügen zerfallen
Bericht Jede Runde mit Paarungen, Zwischentabelle und Tiebreakern
Turnierstand JSON — die einzige Fassung, die sich wieder einlesen lässt

Technik

Flutter für Linux-Desktop und Android, Riverpod für den Zustand, Drift/SQLite für die lokale Datenbank. Material 3, hell und dunkel nach Systemeinstellung. Die Datenbank liegt unter ~/Dokumente/turnierwart.sqlite.

Bauen und starten

flutter test
flutter build linux --release
./build/linux/x64/release/bundle/turnierwart

Wird aus einer Flatpak-Umgebung heraus gearbeitet (etwa VSCodium), fehlt darin clang++. Der Build läuft dann über den Host:

flatpak-spawn --host sh -lc '~/development/flutter/bin/flutter build linux --release'

Android braucht JDK 21 und --target-platform android-arm64 — beides samt Begründung in docs/bauen.md.

Aufbau

lib/
  core/
    tournament/   Regelkern ohne I/O: Tabelle, Paarung, Baum, jeder gegen jeden
    database/     Drift-Schema, Repository, zusammengesetzter Event-Zustand
    transfer/     Austauschformat: reine Daten und ein Parser
    models/       Event-Typen, Namen, Sortierung
    theme/        Farben und Schrift
  features/
    events/       Übersicht, Anlege-Dialog, Event-Bildschirm, Anmeldung, Baum
    rounds/       Partienliste, Rundenuhr, „jeder gegen jeden"
    standings/    Die Tabelle
    players/      Spielerstamm, Namensfelder, Teilnehmerauswahl
    export/       Die vier Fassungen, Datei schreiben, Übergabe
    settings/     Rundenzeit, Bildschirm, Klangprobe
tool/             Erzeugt Icons und Klänge
docs/             Diese Dokumentation

Tests

flutter test

196 Tests in zwölf Dateien. Der Regelkern ist ohne Datenbank testbar und wird deshalb direkt geprüft; die Datenbanktests laufen gegen SQLite im Arbeitsspeicher, die Widget-Tests gegen die echte Oberfläche. Was dabei dreimal eine Stunde gekostet hat, steht in docs/einstieg.md.

Grenzen

  • Keine Obergrenze für das Feld. Ein Draft-Pod ist acht Leute, und lange stand genau das als Schranke im Code. Es war die Größe eines Anwendungsfalls und nie die Grenze der Rechnung: das Schweizer System paart bis 14 Spieler exakt und darüber nach einem Näherungsverfahren, „jeder gegen jeden" rotiert über beliebig viele, und der Baum füllt die nächstgrößere Zweierpotenz.
  • Ein Gerät führt. Die Übergabe ist keine Synchronisierung; wer abgegeben hat, sieht nur noch zu.
  • Kein Mehrbenutzerbetrieb, keine Anmeldung, kein Server. Die Datenbank ist eine Datei auf dem Gerät.
  • Best-of-3. Andere Matchformate kennt die Ergebniseingabe nicht.
  • Android-APK nur für arm64 — kein 32-Bit-Telefon, kein Emulator.