Befehlszeilenschnittstelle (CLI)

Einführung

blunderDB enthält eine vollständige Befehlszeilenschnittstelle (CLI) in derselben ausführbaren Datei wie die grafische Oberfläche. Die CLI ist besonders nützlich für:

  • den Massenimport von Matches: ein ganzes Verzeichnis mit Match-Dateien (XG, SGF, MAT, BGF…) mit einem einzigen Befehl importieren,

  • die Automatisierung: blunderDB in Shell-Skripte einbinden für regelmäßige Sicherungen, geplante Exporte oder Verarbeitungsketten,

  • den Servereinsatz: Datenbanken auf Maschinen ohne grafische Umgebung verwalten,

  • die schnelle Inspektion: den Inhalt oder die Integrität einer Datenbank prüfen, ohne die grafische Oberfläche zu starten.

Die CLI verwendet genau dasselbe Datenbankformat wie die grafische Oberfläche: Beide schreiben dieselbe Datei, es gibt nichts zu synchronisieren.

Bemerkung

Wenn die Anwendung geöffnet ist, während ein Skript schreibt. Die Datei befindet sich im WAL-Modus: Ein Lesevorgang blockiert nie einen Schreibvorgang, und beide Programme arbeiten störungsfrei an derselben Datenbank. Zwei Schreibvorgänge dagegen folgen nacheinander — der zweite wartet auf die Schreibsperre (zehn Sekunden pro Anweisung, plus einige weitere Versuche) und schlägt nur fehl, wenn die Wartezeit ausgeschöpft ist, mit einer Meldung, die SQLite nennt:

Error: failed to import match: sqlite: save match: database is locked (5) (SQLITE_BUSY)

Die grafische Oberfläche überwacht die Datei nicht: Sie zeigt weiterhin an, was sie geladen hatte, bis CTRL-R die Positionen neu lädt. Nichts geht verloren, aber der Bildschirm hinkt der Datenbank hinterher.

Allgemeine Syntax

Der Modus wird automatisch erkannt: Ist das erste Argument ein CLI-Befehl, startet blunderDB im Headless-Modus, andernfalls startet es die grafische Oberfläche.

# GUI
./blunderdb

# CLI
./blunderdb <command> [options]

Die Beispiele auf dieser Seite schreiben ./blunderdb: die Binärdatei so, wie sie heruntergeladen wurde, aus dem Ordner heraus aufgerufen, in dem sie liegt. Über ein Paket installiert oder aus einem Ordner im PATH verlinkt (siehe Download und Installation), heißt sie schlicht blunderdb.

Boolesche Optionen, die als „Standard: ja“ ausgewiesen sind, werden mit der Form --option=false deaktiviert — --recursive=false, --analysis=false. Die durch ein Leerzeichen getrennte Form gibt es nicht: --recursive false belässt die Option bei ihrem Standardwert und behandelt false als überzähliges Argument.

Verfügbare Befehle

Befehl

Beschreibung

create

Erstellt eine neue Datenbank.

import

Importiert Daten (Match, Position, Stapel).

export

Exportiert Daten.

identity

Zeigt oder verschiebt die Aussteller-Identität (Signaturschlüssel der Wasserzeichen).

open

Wandelt eine passwortgeschützte Datei (.dbx) in eine gewöhnliche Datenbank um.

search

Sucht Positionen mit Filtern.

list

Zeigt den Inhalt der Datenbank an.

match

Zeigt die Positionen und Analysen eines Matches an.

collection

Verwaltet Sammlungen (Liste, Inhalt, Erstellung, Umbenennung, Löschung, Export).

anki

Stapel für verteiltes Wiederholen (Liste, Statistiken, Vorschau, Synchronisierung).

rollout

Spielt eine Stellung bis zum Ende aus, um ihre Züge oder ihre Doppler-Entscheidung zu unterscheiden (XGID oder OGID).

epc

Berechnet den Effective Pip Count und das Doppler-Urteil einer Auswürfelstellung (XGID oder OGID).

bearoff

Erstellt, listet, prüft und löscht Bearoff-Datenbanken.

analyze

Schreibt eine gammonNet-Analyse für jede Stellung, die noch keine hat.

info

Zeigt die Metadaten der Datenbank an.

edit

Bearbeitet die Metadaten und die Schwellenwerte der Datenbank.

verify

Prüft die Integrität der Datenbank.

vacuum

Komprimiert die Datenbankdatei und gewinnt freigewordenen Platz zurück.

repair

Berechnet neu, was die Datenbank aus dem Gespeicherten ableitet.

delete

Löscht Daten.

healthcheck

Fragt einen laufenden serve-Daemon ab: Exit-Code 0, wenn er bereit ist.

mcp

Stellt einem KI-Assistenten die Werkzeuge der Datenbank zur Verfügung (Model Context Protocol).

completion

Zeigt ein Shell-Vervollständigungsskript an (bash, zsh, fish).

help

Zeigt die Hilfe an.

version

Zeigt die Version an.

serve, migrate, call

Server-Modus und Migration nach PostgreSQL: siehe Headless-Modus (Server).

Jeder Befehl akzeptiert die Option --help, um seine ausführliche Hilfe anzuzeigen.

create — Eine Datenbank erstellen

Erstellt eine neue Datenbankdatei mit optionalen Metadaten.

./blunderdb create --db <path> [--user <name>] [--description <text>] [--force]

Optionen:

  • --db — Pfad zur zu erstellenden Datenbankdatei (erforderlich).

  • --user — Name des Datenbankbesitzers.

  • --description — Beschreibung der Datenbank.

  • --force — Überschreibt die Datei, falls sie bereits existiert.

  • --format — Ausgabeformat: text (Standard) oder json (Pfad, Version, Benutzer, Beschreibung, Erstellungsdatum).

Die Erweiterung .db wird automatisch hinzugefügt, falls sie fehlt. Übergeordnete Verzeichnisse werden bei Bedarf erstellt.

Beispiel:

./blunderdb create --db mes_matchs.db --user "Jean" --description "Matchs de tournoi 2025"

import — Daten importieren

Importiert Match- oder Positionsdateien in die Datenbank.

./blunderdb import --db <path> --type <type> [options]

Optionen:

  • --db — Pfad zur Datenbank (erforderlich).

  • --type — Importtyp: match, position oder batch (erforderlich).

  • --file — Zu importierende Datei (für match und position).

  • --dir — Zu importierendes Verzeichnis (für batch).

  • --recursive — Unterverzeichnisse rekursiv durchsuchen (Standard: ja).

  • --watch — Mit --type batch: hält nicht an und importiert jede Matchdatei, sobald sie erscheint, in --dir (Ctrl-C zum Beenden).

  • --watch-every — Wie oft --watch nachsieht (Standard: 10s, Untergrenze 2s).

  • --format — Ausgabeformat: text (Standard) oder json.

  • --fail-on-error — Bricht mit Fehler ab, wenn mindestens ein Element (position oder batch) nicht importiert werden konnte, selbst wenn andere erfolgreich waren.

Der Exit-Code folgt vier Regeln:

  • nichts wurde erkannt — jede Datei ist fehlgeschlagen — : Fehler, ob --fail-on-error übergeben wird oder nicht;

  • nur Duplikate — jede Datei war bereits in der Datenbank — : Erfolg. Ein erneut laufendes Verzeichnis ohne neue Datei, die gewöhnliche Nacht eines Skripts, endet mit 0 und nur duplicates von null verschieden;

  • teilweiser Fehlschlag (manche Elemente importiert, andere abgelehnt): Fehler nur, wenn --fail-on-error übergeben wird;

  • mindestens ein neues Element importiert, ohne --fail-on-error: Erfolg, wobei die abgelehnten Dateien in der Tabelle aufgeführt werden.

Einen Ordner überwachen

--watch macht aus dem Verzeichnisimport eine Überwachung: der Befehl kehrt nicht zurück und importiert jede Matchdatei, die im Ordner erscheint. Es ist die Form ohne Oberfläche des überwachten Ordners der Anwendung.

# Importer ce que le dossier contient déjà, puis surveiller ce qui arrive
./blunderdb import --db base.db --type batch --dir ~/XG/Matches
./blunderdb import --db base.db --type batch --dir ~/XG/Matches --watch

Nur erscheinende Dateien werden importiert: was der Ordner beim Start enthält, wird als bekannt vermerkt und in Ruhe gelassen — eine Überwachung auf vier Jahre Matches zu richten darf nicht alle importieren. Die beiden obigen Befehle ergänzen sich also genau wie erhofft.

Eine Datei wird erst importiert, wenn ihre Größe sich gesetzt hat, also zweimal unverändert gesehen wurde: ein Match, das ein anderes Programm gerade schreibt, wächst von einem Blick zum nächsten, und es halb geschrieben zu importieren ergäbe einen Syntaxfehler, mit dem niemand etwas anfangen kann. Der Ordner wird nicht rekursiv durchlaufen. Eine unlesbar gewordene Netzwerkfreigabe beendet die Überwachung nicht, und ihr Inhalt gilt bei ihrer Rückkehr nicht als neu.

Ctrl-C hält zwischen zwei Dateien an, nie mitten in einer: die gerade importierte Datei wird fertig, und ihr Bericht erscheint, bevor der Befehl zurückkehrt.

Ein Match importieren

Unterstützte Formate: eXtreme Gammon (.xg, .xgp), GNUbg (.sgf), Jellyfish (.mat, .txt), BGBlitz (.bgf) und HedgeHog (.ogxm).

./blunderdb import --db base.db --type match --file match.xg

# Successfully imported match (ID: 1)
#
# Match Details:
#   Players: Kévin Unger vs Maxence Job
#   Event: HSBT Paris 2023
#   Match Length: 7
#   Games: 7

--format json liefert dieselben Felder in einem einzigen Dokument:

{
  "type": "match",
  "match_id": 1,
  "player1": "Kévin Unger",
  "player2": "Maxence Job",
  "event": "HSBT Paris 2023",
  "location": "Paris, Fédération Française de Bridge",
  "match_length": 7,
  "games": 7
}

Positionen importieren

Importiert Positionen aus einer Textdatei, eine JSON-Position pro Zeile. Das ist genau das, was export --type positions schreibt: Die beiden Befehle entsprechen sich, ein Export lässt sich unverändert wieder importieren, ohne dass etwas nachbearbeitet wird.

./blunderdb import --db base.db --type position --file positions.txt

# Successfully imported 4 positions

Eine Zeile, so wie export sie erzeugt — das Brett nimmt den größten Teil ein, sechsundzwanzig Punkte gefolgt von den ausgetragenen Steinen:

{"id":1,"board":{"points":[{"checkers":0,"color":0},{"checkers":1,"color":1},…],"bearoff":[0,0]},"cube":{"owner":-1,"value":0},"dice":[0,0],"score":[7,7],"player_on_roll":0,"decision_type":1,"has_jacoby":0,"has_beaver":0,"individually_imported":true,"flagged":false}

Analyse und Kommentare werden über dieses Format nicht mitgeführt: Es trägt nur die Position, sonst nichts. Um eine ganze Bibliothek zu verschieben, ist export --type database nötig.

Stapelimport

Importiert alle Match-Dateien eines Verzeichnisses in einem einzigen Vorgang. Dies ist die effizienteste Methode, um eine große Anzahl von Matches zu importieren.

./blunderdb import --db base.db --type batch --dir ./matchs/
./blunderdb import --db base.db --type batch --dir ./matchs/ --recursive=false
./blunderdb import --db base.db --type batch --dir ./matchs/ --format json --fail-on-error

Eine zusammenfassende Tabelle zeigt für jede Datei, ob der Import erfolgreich war (✓), fehlgeschlagen ist (✗) oder ein Duplikat war (⊘). Ein Duplikat zählt nicht als Fehlschlag, und ein Stapel, der nur Duplikate enthält, ist ein Erfolg (siehe die Regeln oben).

Batch importing from: ./matchs/ (recursive: true)

Found 3 match file(s) to import

[1/3] Importing: 02_NDT_FR.txt... ERROR: failed to parse file: ingest: parse gnubg file: invalid MAT file: no match header found
[2/3] Importing: test.mat... DUPLICATE
[3/3] Importing: test.xg... OK (ID: 1, 341 positions)

====================================================================
IMPORT SUMMARY
====================================================================
Status  File           ID  Player 1     Player 2     Games  Positions  Error
------  ----           --  --------     --------     -----  ---------  -----
✗       02_NDT_FR.txt                                0      0          failed to parse file: ingest: ...
⊘       test.mat                                     0      0
✓       test.xg        1   Kévin Unger  Maxence Job  7      341
--------------------------------------------------------------------
Total: 3 files | Success: 1 | Duplicates: 1 | Failed: 1 | Positions imported: 341

--format json liefert dasselbe, von einem Skript auswertbar: ein Objekt pro Datei in files, dann die Summen. Eine ruhige Nacht lässt allein duplicates von null verschieden und failed bei null, und der Exit-Code bleibt bei 0; nur ein Stapel, in dem nichts erkannt wurde, endet mit einem Fehler.

{
  "files": [
    {"file_path": "02_NDT_FR.txt", "success": false, "error": "failed to parse file: …"},
    {"file_path": "test.xg", "success": true, "positions": 341}
  ],
  "total": 3,
  "success": 1,
  "duplicates": 1,
  "failed": 1,
  "positions_imported": 341
}

export — Daten exportieren

Exportiert den Inhalt der Datenbank in Dateien.

./blunderdb export --db <path> --type <type> --file <output> [options]

Optionen:

  • --db — Quelldatenbank (erforderlich).

  • --type — Exporttyp: database, positions, matches oder mat (Export eines oder mehrerer Matches als Jellyfish-Transkription .mat) (erforderlich).

  • --file — Ausgabedatei (erforderlich, außer bei --type mat in Verbindung mit --dir).

  • --dir — Ausgabeverzeichnis für den .mat-Stapelexport (mehrere Matches, eine Datei pro Match; ohne --match-ids werden alle Matches exportiert).

  • --analysis — Analysen einbeziehen (Standard: ja).

  • --comments — Kommentare einbeziehen (Standard: ja).

  • --filters — Filterbibliothek einbeziehen (Standard: ja).

  • --played-moves — Gespielte Züge einbeziehen (Standard: ja).

  • --matches — Matches einbeziehen (Standard: ja).

  • --collections — Sammlungen einbeziehen (Standard: nein).

  • --collection-ids — Zu exportierende Sammlungs-IDs (durch Kommas getrennt).

  • --match-ids — Zu exportierende Match-IDs (durch Kommas getrennt, leer = alle).

  • --tournament-ids — Zu exportierende Turnier-IDs (durch Kommas getrennt).

  • --password — Verpackt das Ergebnis in einen verschlüsselten Container (.dbx).

  • --watermark — Schreibt eine signierte Herkunftserklärung in die exportierte Datei (siehe Eine Datenbank weitergeben: Herkunft und Passwort).

  • --watermark-note — Freier Text zum Wasserzeichen (Nutzungsbedingungen, Kontakt); zusammen mit --watermark verwendet.

  • --format — Ausgabeformat: text (Standard) oder json (ein Dokument, das den Export zusammenfasst: Pfad, Größe in Byte, Anzahlen).

Beispiele:

./blunderdb export --db base.db --type database --file sauvegarde.db
./blunderdb export --db base.db --type positions --file positions.txt
./blunderdb export --db base.db --type matches --file selection.db --match-ids 1,3,5

# .mat : un match, puis plusieurs (ou tous) dans un répertoire
./blunderdb export --db base.db --type mat --match-ids 5 --file match5.mat
./blunderdb export --db base.db --type mat --match-ids 5,9,12 --dir sorties/
./blunderdb export --db base.db --type mat --dir sorties/

# .dbx : filigrané et protégé par mot de passe
./blunderdb export --db cours.db --type database --file cours-diffusion.dbx \
    --watermark "Cours de Jean Dupont — 12 mars 2026" \
    --watermark-note "Merci de ne pas rediffuser." \
    --password secret

Ein Wasserzeichen wird mit der lokalen Aussteller-Identität signiert (siehe den Befehl identity weiter unten): Es ist fälschungssicher, aber nicht unentfernbar — die Datei bleibt eine gewöhnliche SQLite-Datenbank. Es schützt nichts, es sagt nur, woher die Datei stammt. Ein Passwort schützt den Transport der Datei (die verlegte Kopie, den versehentlich verschickten Anhang), nicht die Datenbank selbst: Wer das Passwort erhalten hat, kann sie öffnen. blunderDB zeichnet auf der Empfängerseite niemals etwas auf (kein Register, kein Protokoll) — siehe ADR-0007.

identity — Aussteller-Identität

Zeigt oder verschiebt Ihre Aussteller-Identität: den Ed25519-Schlüssel, der jedes Wasserzeichen signiert. Er entsteht beim ersten gesetzten Wasserzeichen von selbst; es ist nichts einzurichten. Er gehört zu einer Person, nicht zu einer Datenbank: Alles, was Sie markieren, trägt einen einzigen öffentlichen Fingerabdruck.

./blunderdb identity
./blunderdb identity --name "Jean Dupont"
./blunderdb identity --export jean.bdbid --passphrase pw
./blunderdb identity --import jean.bdbid --passphrase pw

Optionen:

  • --name — Ändert den angezeigten Namen der Identität.

  • --export — Exportiert die Identität in eine .bdbid-Datei.

  • --import — Importiert eine Identität aus einer .bdbid-Datei.

  • --passphrase — Optionale Passphrase, die die exportierte/importierte Datei schützt (die lokale Identität selbst bleibt bewusst ungeschützt).

  • --format — Ausgabeformat: text (Standard) oder json (Name, Fingerabdruck, Speicherpfad).

Die exportierte Datei erlaubt jedem, der sie besitzt, in Ihrem Namen zu signieren — geben Sie sie nicht weiter. Umbenennen ändert nur eine Beschriftung: Bereits markierte Dateien behalten den Namen, unter dem sie versiegelt wurden, und lassen sich weiterhin prüfen.

open — Eine geschützte Datei öffnen

Wandelt eine passwortgeschützte Datei (.dbx) in eine gewöhnliche Datenbank um. Das Passwort wird einmal abgefragt; danach ist es eine normale Datei.

./blunderdb open --db cours.dbx --password secret
./blunderdb open --db cours.dbx --password secret --file ./mon-cours.db

Optionen:

  • --db — Zu öffnende .dbx-Datei (erforderlich).

  • --password — Passwort des Containers (erforderlich).

  • --file — Ausgabepfad für die gewöhnliche Datenbank (Standard: gleicher Name, Endung .db).

Was das Passwort schützt: den Transport der Datei — die im Downloads-Ordner vergessene Kopie, den versehentlich verschickten Anhang. Nicht die Datenbank: Wer das Passwort erhalten hat, kann sie öffnen. Der Container-Kopf liegt im Klartext vor, sodass blunderdb info die Herkunft einer geschützten Datei ohne deren Passwort liest.

search — Positionen suchen

Sucht Positionen in der Datenbank anhand kombinierbarer Kriterien.

./blunderdb search --db <path> [options]

Hauptoptionen:

  • --db — Datenbank (erforderlich).

  • --format — Ausgabeformat: table, json oder xgid (Standard: table).

  • --limit — Maximale Anzahl an Ergebnissen (0 = unbegrenzt).

  • --offset — Die ersten n Ergebnisse überspringen, bevor gezählt wird; zusammen mit --limit ergibt das die Paginierung.

  • --export — Ergebnisse in eine neue Datenbank exportieren.

  • --query-help — Zeigt die Liste der Token an, die --query versteht, und beendet sich danach. Es wird keine Datenbank geöffnet: --db ist überflüssig.

Verfügbare Filter:

  • --decision — Entscheidungstyp: checker oder cube.

  • --dice — Würfelwurf. 5,3 sucht Positionen, bei denen beide Würfel übereinstimmen (unabhängig von der Reihenfolge). 5 sucht Positionen, bei denen eine 5 auf einem der beiden Würfel erscheint (der Wert des zweiten Würfels wird ignoriert). Impliziert --decision checker, wenn kein Wert für --decision angegeben ist.

  • --pip-min / --pip-max — Bereich der Pip-Count-Differenz.

  • --winrate-min / --winrate-max — Bereich der Gewinnrate (%).

  • --cube — Wert des Dopplerwürfels.

  • --score1 / --score2 — Spielstände der Spieler.

  • --match-length — Matchlänge.

  • --error-min — Schwellenwert dafür, was ein Fehler in der Position kostet: der Abstand zwischen dem besten und dem zweitbesten Zug, oder der größte der drei Doppler-Fehler. In Equity-Punkten — --error-min 0.1 behält Positionen, bei denen ein Irrtum mindestens ein Zehntel Punkt kostet. Es sagt nichts darüber aus, was dort tatsächlich gespielt wurde.

  • --move-error-min / --move-error-max — Schwellenwert für den Fehler des tatsächlich gespielten Zuges von Spieler 1. In Tausendstel Equity (Millipunkten): --move-error-min 50, also ein Zwanzigstel Punkt. Das ist das Token E der Suchgrammatik, unverändert übernommen.

  • --has-analysis — Nur Positionen mit Analyse.

  • --off1-min / --off2-min — Mindestanzahl ausgewürfelter Steine (Spieler 1/2).

  • --match-ids — Nach Match-IDs filtern (durch Kommas getrennt).

  • --tournament-ids — Nach Turnier-IDs filtern (durch Kommas getrennt).

  • --position-ids — Nach Positions-IDs filtern: Intervall 2,7 (Positionen 2 bis 7) oder explizite, durch Semikolons getrennte Liste 5;10;15.

  • --individual — Nur einzeln importierte Stellungen, also die, die Sie selbst hinzugefügt haben, und nicht die aus einem Match-Import.

  • --flagged — Nur die in der Ursprungssoftware zum Studium markierten Stellungen (eXtreme-Gammon-Markierungen). Nicht rückwirkend: Bereits importierte Matches müssen erneut importiert werden, um ihre Markierungen zu liefern.

  • --has-comment — Nur die Stellungen mit einem Kommentar. Die Herkunft spielt keine Rolle: Eine von Hand eingetippte Notiz und ein beim Match-Import mitgebrachter Kommentar zählen beide. Match- oder Turnierkommentare werden nicht herangezogen.

  • --no-comment — Nur die Stellungen ohne Kommentar. Schließt sich mit --has-comment gegenseitig aus.

Warnung

--error-min und --move-error-min messen nicht dasselbe und verwenden nicht dieselbe Einheit: Der Faktor ist tausend. Der erste wird in Equity-Punkten angegeben (0.1), die beiden anderen in Tausendsteln (100) — ein Punkt entspricht 1000 Tausendsteln. --move-error-min beantwortet „wo habe ich gefehlt“; --error-min beantwortet „welche Positionen waren heikel“.

Was search ausgibt:

--format table (der Standard) liefert eine Zeile pro Position: die ID, den Spielstand, den Wert des Dopplers, den Entscheidungstyp, den Wurf, die beste Entscheidung und ihre Equity. Die beiden letzten Spalten bleiben für eine Position ohne Analyse leer.

Found 5 position(s)

ID  Score  Cube  Type  Dice  Best Move  Equity
--  -----  ----  ----  ----  ---------  ------
2   7-7    0     cube        No Double  -0.005
4   7-7    0     cube        No Double  -0.027
6   7-7    0     cube        No Double  -0.161
8   7-7    0     cube        No Double  0.256
10  7-7    0     cube        No Double  -0.234

--format json liefert eine Tabelle derselben Positionen. Die Felder id, score, cube, decision_type (checker oder cube) und dice sind immer vorhanden; best_move, equity und xgid erscheinen nur, wenn die Position eine Analyse trägt, die sie liefert. Die Zeile Found n position(s) wird weiterhin vor der Tabelle ausgegeben: Ein Skript, das nur JSON erwartet, muss die erste Zeile überspringen oder --export verwenden.

[
  {
    "id": 5266,
    "score": [
      5,
      4
    ],
    "cube": 1,
    "decision_type": "checker",
    "dice": [
      4,
      3
    ],
    "best_move": "10/3",
    "equity": 0.565
  }
]

--format xgid gibt eine XGID pro Zeile aus, und sonst nichts. Es gibt nur Positionen aus, deren gespeicherte Analyse eine XGID trägt: eine Position, die aus einem Textexport in die Anwendung eingefügt wurde, oder eine BGF-Datei, die eine mitführt. Positionen aus dem Import eines XG-, GNUbg- oder Jellyfish-Matches tragen keine, und die Ausgabe bleibt dann leer. Der Unterbefehl collection show erzeugt die XGID dagegen aus dem Brett neu.

Die Abfragesprache:

Die obigen Optionen decken nur einen Teil der Filter ab. --query gibt Zugang zur Abfragesprache der Anwendung — derjenigen der Befehlszeile — und damit zu allen Filtern, die nicht auf dem Brett gezeichnet werden: Zugmuster, Kommentartext, Spieler, Datum, Equity, ausgeschlossene Würfe, Zonen und Blots.

Die Grammatik steht an genau einer Stelle, Suchfilter. Ihre Tabelle nennt jedes Token, seine Form und die entsprechende Option von search, sofern es eine gibt. Diese Seite wiederholt sie nicht.

./blunderdb search --db base.db --query 's p>30 E>50'
./blunderdb search --db base.db --query 's m"13/11" t"blunder" pl"Alice" T>2026/01/01'

Das Ordnen der Nachbarn einer Stellung läuft über dieselbe Grammatik: --query 's like42', allein oder gefolgt von weiteren Token, um die geordnete Menge einzuschränken.

--query-help ruft die Liste in Erinnerung, ohne eine Datenbank zu öffnen:

$ ./blunderdb search --query-help
blunderdb search --query — the interface's query language

A query is the same text the application's command bar takes:
  s cube p>30 E>50        cube decisions, 30+ pips behind, 50+ millipoints of error
  s m"13/11" T>2026/01/01 played 13/11, imported this year

Flags (no value):
  cube score   match the cube / the score of the position on the board
  d            match the decision type (checker or cube)
  …

Ranges — each takes x>n, x<n or xa,b (lower-case: you; upper-case: the opponent):
  p P          pip count difference / absolute pip count
  …
  E            error of the played move, in millipoints
  T            creation date, T>2026/01/01

Values:
  t"tag"       comment text (";" separates alternatives)
  …

--query ersetzt die Filteroptionen, statt sie zu ergänzen: eine Kombination wird abgelehnt, unter Nennung der betreffenden Option. Die Optionen, die sagen, wo gesucht und wie angezeigt wird — --db, --format, --limit, --offset, --export — bleiben gültig.

Ein Token, das nichts erkennt, lässt den Befehl scheitern, statt die Suche stillschweigend einzuengen. Zwei Einschränkungen ergeben sich daraus, dass es auf der Kommandozeile kein Brett gibt: Das Steinmuster lässt sich nicht tippen, und die fünf Token, die das Brett lesen — cube, score, d, D/D1 und x — vergleichen hier mit einem leeren Brett. Eine Suche, die eines davon braucht, wird vollständig mit Optionen geschrieben, da sich --query nicht mit ihnen kombinieren lässt — zum Beispiel die Doppler-Entscheidungen mit mindestens 30 Pips Rückstand und einem Fehler von mindestens 50 Millipunkten:

./blunderdb search --db base.db --decision cube --pip-min 30 --move-error-min 50

Beispiele:

./blunderdb search --db base.db --decision cube
./blunderdb search --db base.db --individual
./blunderdb search --db base.db --error-min 0.1
./blunderdb search --db base.db --tournament-ids 1 --export cubes.db

# 6-5 dans les deux ordres, puis un 6 sur l'un des deux dés
./blunderdb search --db base.db --dice 6,5
./blunderdb search --db base.db --dice 6

# Pagination
./blunderdb search --db base.db --format json --limit 10 --offset 20

list — Inhalt auflisten

Zeigt den Inhalt der Datenbank an.

./blunderdb list --db <path> --type <type> [--limit <n>] [--offset <n>]

Typen:

  • matches — Liste der importierten Matches.

  • tournaments — Liste der Turniere.

  • positions — Liste der Positionen (standardmäßig 10; --offset <n> überspringt die ersten n). Gelesen wird nur das angezeigte Fenster, unabhängig von der Größe der Datenbank. Mit --format csv wird daraus ein tabellarischer Export: eine Zeile pro Position mit XGID, Phase, Spielstand, Doppler, Pips und den abgeleiteten Analysespalten.

  • imports — Die aufgezeichneten Importe, neueste zuerst: Kennung, Datum, Format, Quelle, importierte / übersprungene / angereicherte Partien, unlesbare Dateien und neue Stellungen. Mit --batch <id> wird der vollständige Bericht eines Imports gezeigt: markierte Stellungen, Stellungen ohne Analyse, PR über diesen Stapel und dessen fünf schlechteste Entscheidungen (siehe Der Importbericht).

  • stats — Bericht der Leistungsstatistiken: PR / Snowie ER / MWC (global, Steine, Cube), gleitender PR über die letzten N Entscheidungen, Top-Blunders, Aufschlüsselung nach Cube-Aktion und Histogramm der Fehlergrößen.

  • players — Vergleichstabelle, eine Zeile je Spieler der Datenbank: Matches, Siege/Niederlagen, gezählte Entscheidungen, PR gesamt / Steine / Doppler, Snowie ER, Fehler, Blunders und Glück. Das ist das Kommandozeilen-Gegenstück zum Reiter Spieler des Statistik-Fensters.

  • moves — Tabellarischer Export der aufgezeichneten Züge, einer pro Zeile, mit dem zugehörigen Match auf jeder Zeile wiederholt: Bezeichner, Datum, Spieler, Länge, Zugnummer und -art, Stellung, Würfel, gespielter Zug, Würfelaktion, Glück. --format csv erforderlich.

  • analyses — Tabellarischer Export der gespeicherten Analysen, eine pro Zeile: Engine, Tiefe, bester Zug und seine Equity, Fehler des gespielten Zuges, beste Würfelaktion und ihr Fehler, die sechs Gewinnraten. --format csv erforderlich.

  • tags — Das Tag-Vokabular der Datenbank: jedes #Wort, das in einem Kommentar steht, mit der Zahl der Stellungen, die es tragen, das meistgenutzte zuerst. Bei einer Datenbank ganz ohne Tag zeigt es das empfohlene Vokabular statt einer leeren Liste (siehe Tags). Akzeptiert --format json und --format csv.

Tabellarische Exporte

Drei Typen — positions, moves und analyses — lassen sich als CSV exportieren, für ein Notebook, eine Tabellenkalkulation oder ein Skript:

./blunderdb list --db base.db --type positions --format csv > positions.csv
./blunderdb list --db base.db --type moves     --format csv > moves.csv
./blunderdb list --db base.db --type analyses  --format csv > analyses.csv

--limit gilt nur, wenn Sie es angeben. Der Standardwert (10) existiert, damit ein im Terminal ausgegebenes list nicht die ganze Datenbank vorbeiscrollen lässt; ein Export landet in einer Datei, die ein Programm liest, und ihn stillschweigend bei zehn Zeilen abzuschneiden wäre eine Falle, die niemand bemerkt, bis die Zahlen falsch sind.

Die Spalten sind ein Vertrag. Ein Notebook oder ein Skript, das gegen diese Namen geschrieben wurde, muss weiter funktionieren: Spalten werden am Ende hinzugefügt, nie umbenannt und nie umgestellt. Jede Equity steht in ganzzahligen Millipunkten, weil sie so gespeichert wird und weil eine Fließkommazahl in einer CSV eine Locale einlädt, sie umzuformatieren.

Parquet wird nicht angeboten, und das ist gemessen statt dogmatisch: eine spaltenorientierte Bibliothek wiegt mehrere Megabyte in einer Binärdatei, deren Größe ein verfolgtes Anliegen ist, während alles, wofür dieser Export da ist, CSV in einer Zeile liest (pd.read_csv, polars.read_csv, read.csv, eine Tabellenkalkulation). Parquet lohnt sich bei zig Millionen Zeilen; eine zehn Jahre alte Backgammon-Bibliothek hat hunderttausend. Wenn eines Tages der Unterschied auf einer echten Datenbank messbar ist, ist diese Messung das, was die Frage wieder öffnet.

Ein Beispiel-Jupyter-Notebook begleitet diese Exporte (notebooks/blunderdb-analyse.ipynb im Repository): PR im Zeitverlauf, die Verteilung der Fehlergrößen, die zehn schlimmsten Entscheidungen mit ihrer XGID. Es benutzt nichts als diese drei CSV-Dateien und wird jede Nacht in der Continuous Integration ausgeführt — ein Notebook, das niemand laufen lässt, ist ein Notebook, das aufgehört hat zu funktionieren, ohne dass es jemand merkt.

Optionen (nur Typ stats) :

  • --metric — Angezeigte Metrik: pr oder mwc (Standard: pr).

  • --player — Auf den angegebenen Spieler beschränken.

  • --tournament — Auf eine oder mehrere Turnier-IDs beschränken (durch Kommas getrennt).

  • --from — Startdatum (JJJJ-MM-TT).

  • --to — Enddatum (JJJJ-MM-TT).

  • --decision-type — Entscheidungstyp: all, checker oder cube (Standard: all).

  • --top-blunders — Anzahl der aufgelisteten schlimmsten Fehler (Standard: 10).

  • --format — Ausgabeformat: text oder json (Standard: text).

Optionen (nur Typ imports) :

  • --batch — Kennung eines Stapels: zeigt dessen vollständigen Bericht statt der Liste.

  • --queue — Mit --batch: die Studienliste des Laufs statt seines Berichts — die Stellungen, die einen zweiten Blick lohnen, in der Reihenfolge, in der man sie durchgeht (siehe Die Studienliste). Zuerst die Entscheidungen, die etwas gekostet haben, dann die im Ursprungsprogramm markierten Stellungen, dann die knappen Würfelentscheidungen; eine Stellung erscheint nur einmal.

  • --format — Ausgabeformat: text oder json (Standard: text).

Die gemessene Hälfte des Berichts wird bei jedem Aufruf neu berechnet: ein Stapel, dessen Stellungen inzwischen analysiert wurden, liefert die heutigen Zahlen, nicht die vom Tag des Imports.

Optionen (nur Typ players) :

  • --from / --to — Datumsgrenzen (JJJJ-MM-TT), etwa die Tage eines Turniers.

  • --tournament — Auf eine oder mehrere Turnier-IDs einschränken.

  • --format — Ausgabeformat: text, json oder csv (Standard: text).

--player und --decision-type gelten für diesen Typ nicht: Die Tabelle umfasst alle Spieler und teilt Steine und Doppler bereits in getrennte Spalten auf.

Bemerkung

Ein Gedankenstrich „—“ (in CSV ein leeres Feld) steht für einen nie gemessenen Wert, nicht zu verwechseln mit null. Das gilt für das Glück bei jedem Match, das vor Schemaversion 2.15.0 importiert wurde, sowie für die Formate, die es nicht transportieren (BGF, Jellyfish .mat): Importieren Sie die Quelldateien erneut, um es zu erhalten. Die Spalte luck_rolls gibt an, über wie viele Würfe der Mittelwert geht.

Jeder Typ gibt einen Block pro Element aus, angeführt von der gefundenen Gesamtzahl. Die letzte Zeile nennt das angezeigte Fenster, begrenzt durch --limit (Standardwert 10 für Positionen) und verschoben durch --offset:

Found 3859 position(s):

ID: 1
  Score: 7-7
  Player on roll: 0
  Decision: Checker play

ID: 2
  Score: 7-7
  Player on roll: 0
  Decision: Cube action

…

(Showing 1-10 of 3859 positions, use --offset and --limit to see more)

Beispiele:

# Les imports enregistrés, puis le compte rendu de l'un d'eux
./blunderdb list --db base.db --type imports
./blunderdb list --db base.db --type imports --batch 3

./blunderdb list --db base.db --type stats
./blunderdb list --db base.db --type stats --metric mwc --player "Alice"
./blunderdb list --db base.db --type stats --decision-type checker --from 2026-01-01
./blunderdb list --db base.db --type stats --format json

# Un tableau par joueur, borné aux dates d'une compétition
./blunderdb list --db base.db --type players --from 2026-03-01 --to 2026-03-08
./blunderdb list --db base.db --type players --format csv

./blunderdb list --db base.db --type matches
./blunderdb list --db base.db --type positions --limit 20

match — Ein Match anzeigen

Zeigt die Positionen und Analysen eines importierten Matches an.

./blunderdb match --db <path> --id <id> [--format <format>] [--output <file>]

Optionen:

  • --db — Datenbank (erforderlich).

  • --id — ID des anzuzeigenden Matches (erforderlich).

  • --format — Ausgabeformat: json, text oder summary (Standard: json).

  • --output — Ausgabedatei (Standard: Standardausgabe).

Beispiele:

./blunderdb match --db base.db --id 1 --format summary
./blunderdb match --db base.db --id 1 --format text
./blunderdb match --db base.db --id 1 --output match1.json

collection — Sammlungen verwalten

Verwaltet Sammlungen, diese von Hand ausgewählten Stellungsmengen im Panel Sammlungen der grafischen Oberfläche. Jeder Unterbefehl nimmt --db entgegen; list und show akzeptieren --format text (Standard), json oder csv, wie list.

./blunderdb collection <subcommand> [options]

Unterbefehle:

  • list — Liste der Sammlungen: id, Name, Anzahl Positionen, Beschreibung.

  • show --id <id> — Positionen einer Sammlung: id, Index (die 1-basierte Nummer, die in der Statusleiste der grafischen Oberfläche angezeigt wird), Spielstand, Entscheidungstyp und XGID.

  • create --name <Name> [--description <Text>] — Erstellt eine leere Sammlung.

  • filter --id <id> --query <Abfrage> — Macht eine Sammlung lebendig: ihr Inhalt wird zum Ergebnis einer Suche, das bei jedem Öffnen neu ausgewertet wird. Die Abfrage wird in der Suchgrammatik der Anwendung geschrieben (siehe Suchfilter). --clear macht daraus wieder eine von Hand erstellte Liste und behält die enthaltenen Stellungen.

  • rename --id <id> --name <Name> [--description <Text>] — Benennt eine Sammlung um (die Beschreibung bleibt erhalten, wenn sie nicht angegeben wird).

  • delete --id <id> [--confirm] — Löscht eine Sammlung; ihre Positionen bleiben in der Datenbank.

  • export --id <id[,id…]> --out <Datei.db> [--analysis=false] [--comments=false] [--watermark <Text>] [--watermark-note <Text>] — Exportiert eine oder mehrere Sammlungen in eine neue Datenbankdatei, über denselben Aufruf wie das Exportfenster der grafischen Oberfläche (siehe den Befehl export für das Wasserzeichen).

Das von show angezeigte XGID ist, wenn vorhanden, das mit der Analyse der Position gespeicherte (BGF- und XGP-Importe); andernfalls wird es aus dem Brett erzeugt, genau wie Position kopieren in der grafischen Oberfläche es tut — die Matchlänge ist dann der größere der beiden verbleibenden Spielstände, da eine gespeicherte Position den tatsächlichen Wert nicht festhält.

Beispiele:

./blunderdb collection list --db base.db

# Found 2 collection(s):
#
# ID  Name              Positions  Description
# --  ----              ---------  -----------
# 1   Ouvertures blitz  0          À revoir
# 2   Videaux ratés     0

Eine Datenbank ohne Sammlung antwortet mit No collections found in database und endet trotzdem mit dem Exit-Code 0.

./blunderdb collection show --db base.db --id 3 --format csv

./blunderdb collection create --db base.db --name "Ouvertures blitz"
./blunderdb collection rename --db base.db --id 3 --name "Ouvertures"
./blunderdb collection delete --db base.db --id 3 --confirm

# Exporter deux collections, marquées de leur origine
./blunderdb collection export --db base.db --id 3,4 --out ouvertures.db \
    --watermark "Cours de Jean Dupont - 12 mars 2026"

anki — Stapel für verteiltes Wiederholen

Zeigt und pflegt die Stapel für verteiltes Wiederholen (FSRS) des Anki-Panels der grafischen Oberfläche. Die Wiederholung einer Karte erfordert das Brett und bleibt der grafischen Oberfläche vorbehalten; die CLI listet, misst und synchronisiert neu.

./blunderdb anki <subcommand> [options]

Unterbefehle:

  • decks [--format text|json|csv] — Liste der Stapel: Quelle, Anzahl Karten, fällige Karten, neue Karten.

  • stats --deck <id> [--format text|json] — Wiederholungsstatistiken eines Stapels: Gesamtzahl, neu, in Lernphase, zu wiederholen, jetzt fällig, sowie seine FSRS-Parameter.

  • forecast [--deck <id>] [--days <n>] [--format text|json|csv] — Fällige Karten je Kalendertag (UTC) über die nächsten n Tage (Standard 30, Maximum 365); Tag 0 nimmt alle überfälligen Karten auf; --deck 0 (Standard) umfasst alle Stapel.

  • sync --deck <id> — Fügt für jede Position der Stapelquelle, die noch keine hat, eine Karte hinzu; bestehende Karten behalten ihren Zeitplan.

  • retention --deck <id> [--format text|json] — die gemessene Retention eines Stapels, verglichen mit dem von seinem Besitzer gewählten Ziel.

  • card --id <id> --action suspend|unsuspend|bury|remove [--format text|json] — wirkt auf eine Karte. Aussetzen legt sie beiseite, ohne ihre Historie zu verlieren (sie kommt in keiner Sitzung mehr vor); Vergraben verbirgt sie bis zum nächsten Tag, ohne etwas über ihren Wert zu sagen; Entfernen löscht sie aus dem Stapel — die Stellung selbst bleibt in der Bibliothek, ein Stapel ist nur eine darüber gelegte Lernliste.

  • log [--deck <id>] [--limit <n>] [--format text|json] — das Wiederholungsprotokoll, das jüngste zuerst (--deck 0, der Standard, umfasst alle Stapel; --limit steht standardmäßig auf 20). Das Protokoll ist das, was dem Planer tatsächlich gesagt wurde, im Gegensatz zu dem, was er heute vorsieht: der einzige Ort, an dem eine versehentlich eingegebene Note sichtbar wird.

Ein auf einer Sammlung beruhender Stapel liest seine Sammlung erneut ein. Ein auf einer Suche beruhender Stapel behält die Suche so bei, wie die grafische Oberfläche sie gespeichert hat (Befehl, Brett und Kennungen der zu diesem Zeitpunkt gefundenen Positionen): Die Suchgrammatik lebt in der grafischen Oberfläche, die CLI synchronisiert daher anhand der gespeicherten Kennungen neu und meldet dies auf der Fehlerausgabe — öffnen Sie den Stapel in der grafischen Oberfläche, um die Suche selbst erneut auszuführen.

Beispiele:

./blunderdb anki decks --db base.db
./blunderdb anki stats --db base.db --deck 2 --format json
./blunderdb anki forecast --db base.db --deck 2 --days 14
./blunderdb anki sync --db base.db --deck 2
./blunderdb anki card --db base.db --id 12 --action suspend
./blunderdb anki log --db base.db --deck 2 --limit 50

# Day         Due
# ---         ---
# 2026-09-02  12
# 2026-09-03  4
# ...
#
# 37 card(s) due over 14 day(s)

stats — Wiederkehrende Fehler

Gruppiert die Fehler eines Filters nach Spielplan und nach Thema, die teuerste Gruppe zuerst: die Tabelle Wiederkehrende Fehler im Reiter Fehler des Stats-Panels (siehe Stats-Panel). Die globalen Statistiken bleiben unter list --type stats.

./blunderdb stats recurring --db <fichier> [options]

Optionen:

  • --player <nom> — Nur die Entscheidungen dieses Spielers.

  • --tournament <ids>, --from <AAAA-MM-JJ>, --to <AAAA-MM-JJ>, --decision-type all|checker|cube — Derselbe Filter wie bei list --type stats.

  • --limit <n> — Anzahl der als Text angezeigten Gruppen (Standard 20, 0 für alle).

  • --format text|json — Das JSON enthält jede Gruppe mit der vollständigen Liste ihrer Stellungen.

  • --quiz — Zieht zufällig Stellungen aus denen der drei teuersten Gruppen (--quiz-size <n>, Standard 20) und gibt sie aus: Es sind die Kennungen, die das Quiz und quiz_grade beurteilen. In JSON das Feld Quiz.

  • --deck <Name> — Legt einen Anki-Stapel dieses Namens an, gefüllt mit allen Stellungen der drei teuersten Gruppen.

  • --group <Rang> — Mit --quiz oder --deck: die Gruppe dieses Rangs (1 für die teuerste) statt der ersten drei.

Ein Thema eines Steinzugs ist gammon, blots, point oder passive; ein Würfelthema ist offer_missed, offer_premature, answer_wrong_pass oder answer_wrong_take. Fehler, die keine Regel benennt, fallen aus der Rangfolge: Sie werden gesondert aufgeführt, eine Zeile pro Spielplan (Feld Unthemed in JSON), weil die Erklärung sich erst ab 60 mp äußert, oberhalb der Schwelle Fehler. Die Spalte COST (PR) ist der Anteil am PR des Filters, den die Gruppe ausmacht.

Beispiele:

./blunderdb stats recurring --db base.db --player "Alice"
./blunderdb stats recurring --db base.db --decision-type checker --format json
./blunderdb stats recurring --db base.db --quiz --format json
./blunderdb stats recurring --db base.db --group 1 --deck "Mon pire groupe"

stats training — Die PR des Entscheidungs-Quiz, die PR der Matches und die Anki-Retention, nach Kalenderfenster zusammengefasst, wie der Reiter Training des Stats-Panels (siehe Stats-Panel).

./blunderdb stats training --db <fichier> [options]

Optionen:

  • --window week|month — Das Kalenderfenster (Standard week).

  • --player <Name>, --tournament <ids>, --from <JJJJ-MM-TT>, --to <JJJJ-MM-TT>, --decision-type all|checker|cube — Der Match-Filter; die Journale von Quiz und Anki tragen keinen Spieler.

  • --format text|json — Das JSON enthält auch die Liste der Quiz-Sitzungen.

Jede Reihe behält ihre Stichprobenzahl: Ein Fenster ohne Entscheidung ist im Text ein Strich, im JSON eine Zählung von null, nie ein Nullwert.

Beispiele:

./blunderdb stats training --db base.db --player "Alice"
./blunderdb stats training --db base.db --window month --format json

cubematrix — Dopplerwürfel-Matrix

Liefert das Dopplerwürfel-Urteil einer Stellung bei jedem Punktestand eines Matches: für jede away × away-Zelle, ob die Stellung ein Doppel ist und ob sie angenommen wird. Reine Berechnung: keine Datenbank wird geöffnet, die Stellung kommt als XGID oder als OGID (OpenGammon).

./blunderdb cubematrix [options] '<XGID|OGID>'

Optionen:

  • --format — Ausgabeformat: text oder json (Standard: text).

  • --match-length — Matchlänge, die das Raster abdeckt, von 1 bis 25 (Standard: 7).

  • --ply — Suchtiefe jeder Zelle, 0 oder 2 (Standard: 2).

  • --prune-k — Anzahl der vom Beschneidungsnetz behaltenen Kandidatenzüge (Standard: 12).

  • --jobs — Parallel laufende Suchen (Standard: eine pro Kern). Das Raster ist unabhängig vom Wert identisch; nur die Zeit ändert sich.

Der eigene Punktestand der Stellung wird ignoriert — das Raster ersetzt ihn —, ihr Dopplerwürfel aber bleibt erhalten: gefragt wird, bei welchem Punktestand man diesen Würfel drehen würde. Das Raster gilt durchgehend nach Crawford.

Jede Zelle ist eine eigene Suche, denn die Engine berücksichtigt den Punktestand: eine einzige, durch verschiedene Match-Equities gelesene Suche wäre genau dort falsch, wo der Punktestand zählt.

Beispiele:

# Grille d'un match en 5 points
./blunderdb cubematrix --match-length 5 'XGID=-b----E-C---eE---c-e----B-:0:0:1:00:0:0:0:7:10'

# Les équités de chaque case, pour un script
./blunderdb cubematrix --format json '<XGID>'

Ausgabe text: ein Raster, dessen Zeilen die dem Spieler am Zug noch fehlenden Punkte sind und dessen Spalten die des Gegners, dann die Legende der Kürzel ND / DT / DP / TG und der Grund jeder abgelehnten Zelle.

rollout — Rollout einer Stellung

Spielt eine Stellung sehr oft mit gammonNet aus, um zu entscheiden, was eine Suche nicht entscheidet: zwei Züge, die nur wenige Tausendstel auseinanderliegen, oder eine Doppler-Entscheidung, bei der das Modell zögert. Mit Würfeln werden seine Züge gespielt (die besten in der Tiefe des Rollouts, mindestens 2 Ply, oder die mit --move genannten); ohne Würfel seine Doppler-Entscheidung (Kein Doppel und Doppel/Annahme; Doppel/Aufgabe ist genau +1 wert). Die Stellung stammt aus einer XGID oder einer OGID oder aus einer Datenbank (--db und --id); ohne --store wird nichts gespeichert.

./blunderdb rollout [options] '<XGID|OGID>'
./blunderdb rollout --db <path> --id <position> [--store] [options]

Optionen:

  • --preset — Ausgangseinstellung: fast (Standard: 216 Partien, nach 7 Halbzügen abgebrochen, Stopp bei JSD 3 nach 108) oder standard (1296 Partien, nach 11 abgebrochen, Stopp bei JSD 3 nach 324). Beide spielen mit 0 Ply — das Netz allein, für Züge, Doppler und Blätter; --ply 1 oder mehr spielt tiefer, bei mehrfach längerer Zeit. Die folgenden Optionen überschreiben sie einzeln.

  • --games, --min-games, --truncation, --jsd, --ply, --candidates — Die Parameter des Rollouts (--truncation 0 spielt jede Partie bis zum Ende, --jsd 0 hält nie vor dem Ende an).

  • --move — Ein zu spielender Zug, in blunderDB-Notation (wiederholbar).

  • --seed — Startwert der Würfel, standardmäßig fest: derselbe Befehl liefert dieselben Zahlen.

  • --jobs — Parallel gespielte Partien (Standard: eine pro Kern); nur die Laufzeit ändert sich.

  • --format — Ausgabeformat: text oder json (Standard: text).

  • --db, --id — Die Datenbank und die Kennung der zu spielenden Stellung, anstelle einer XGID.

  • --store — Speichert den abgeschlossenen Rollout an der Stellung, als zweite Analyse mit eigenen Einstellungen, neben der importierten oder berechneten Analyse, die er nie ersetzt. Ein abgebrochener Rollout wird nicht gespeichert; von zwei Rollouts mit denselben Einstellungen bleibt die längere Serie erhalten, ein Rollout mit anderen Einstellungen kommt daneben hinzu.

  • --list — Zeigt die auf der Position gespeicherten Rollouts an, vom neuesten zum ältesten, statt einen auszuspielen.

Alle Kandidaten spielen dieselben Würfel, das Glück jedes Wurfs wird aus dem Ergebnis jeder Partie herausgerechnet (Varianzreduktion), die ersten beiden Würfe werden stratifiziert, und eine Partie endet dort, wo die Two-Sided-Bearoff-Datenbank sie abdeckt. Jede Zeile nennt das Equity, sein 95-%-Intervall, die Zahl der gespielten Partien und die JSD, den Abstand zum Besten in Standardabweichungen der Differenz. Der Doppler wird während der Partien gespielt: Die Rangfolge ist verlässlicher als das absolute Equity. Strg-C zeigt, was die beendeten Partien ergeben haben.

Beispiele:

./blunderdb rollout 'XGID=-b----E-C---eE---c-e----B-:0:0:1:31:0:0:0:0:10'
./blunderdb rollout --move '8/5 6/5' --move '24/23 13/10' '<XGID>'
./blunderdb rollout --db base.db --id 42 --preset standard --store
./blunderdb rollout --db base.db --id 42 --list

epc — EPC-Rechner

Berechnet den Effective Pip Count, die Gewinnwahrscheinlichkeit und das Money-Doppler-Urteil einer per XGID oder OGID (OpenGammon) angegebenen Auswürfelstellung. Reine Berechnung: Es ist keine Datenbankdatei beteiligt.

./blunderdb epc [options] '<XGID|OGID>'

Optionen:

  • --format — Ausgabeformat: text oder json (Standard: text).

  • --bearoff-ts — Optionale zweiseitige Bearoff-Datenbank (.bd), die die eingebaute TS-06-06 erweitert (wird auch aus der Umgebungsvariablen BLUNDERDB_TS_PATH gelesen). Die breiteste gültige Datenbank gewinnt; eine ungültige Datei wird mit einer Warnung ignoriert.

Regime. In dem Bereich, den die zweiseitige Datenbank abdeckt, sind die Gewinnwahrscheinlichkeit und die Money-Doppler-Analyse (cubeless, ND, D/T, D/P, Urteil) exakt. Außerhalb wird die Gewinnwahrscheinlichkeit geschätzt (Faltung der einseitigen Wurfverteilungen plus einer kalibrierten Korrektur) und mit ihrer gemessenen Fehlergrenze angezeigt; das Doppler-Urteil wird bewusst nie geschätzt (siehe ADR-0009).

Beispiele:

# Régime exact : six pions ou moins de chaque côté
./blunderdb epc 'XGID=-BBB------------------bbb-:0:0:1:00:0:0:0:0:10'

# Avec la table TS-06-11 calculée : exact jusqu'à onze pions par joueur
./blunderdb epc --bearoff-ts ~/.local/share/blunderdb/gnubg_ts6x11.bd 'XGID=…'

bearoff — Bearoff-Datenbanken

Erzeugt und verwaltet die Bearoff-Datenbanken. Nichts wird heruntergeladen und nichts ist eingebettet: eine Tabelle wird hier berechnet und gegen den Fingerabdruck geprüft, den gnubg für ihren Bereich erzeugt. Kein Unterbefehl spricht mit einer Datenbank — eine Bearoff-Tabelle ist Arithmetik über das Spiel, nicht über jemandes Stellungen — also nimmt keiner --db.

./blunderdb bearoff generate --ts <domain> [options]
./blunderdb bearoff list [options]
./blunderdb bearoff verify <file.bd> [options]
./blunderdb bearoff delete --ts <domain> [options]

Der Bereich wird wie unter makebearoff geschrieben: 6x9 für die zweiseitige Tabelle mit neun Steinen je Spieler, os8 für die einseitige Tabelle über acht Punkte (os allein bedeutet os6).

Die beiden Familien beantworten nicht dieselbe Frage. Eine zweiseitige Tabelle erweitert den Bereich, in dem Gewinnwahrscheinlichkeit und Doppler-Urteil exakt sind; eine einseitige erweitert, wie weit von zu Hause ein Stein stehen darf, ohne dass der EPC verstummt (bis zu zehn Punkte).

generate. Nennt Größe, Speicherbedarf und geschätzte Dauer vor dem Start und zeigt dann den Prozentsatz und die gemessene Restzeit.

  • --ts — Zu berechnender zweiseitiger Bereich, zum Beispiel 6x9.

  • --os — Zu berechnender einseitiger Bereich, als Punktzahl: 6 bis 12. Genau eines von beiden ist erforderlich.

  • --cores — Zu nutzende Kerne (Standard: alle bis auf einen).

  • --data-dir — Wohin geschrieben wird (Standard: das Datenverzeichnis der Anwendung).

  • --quiet — Keine Fortschrittszeile.

STRG-C pausiert. Das Signal wird abgefangen: der Zustand wird neben der Tabelle abgelegt, und derselbe Befehl erneut ausgeführt setzt dort fort, statt alles neu zu berechnen. Eine halbe Stunde Arithmetik ist es wert, aufgeschrieben zu werden. bearoff delete wirft eine wartende Fortsetzung weg. Nur der zweiseitige Durchlauf pausiert; der einseitige ist sequentiell, und --cores bringt ihm nichts.

list. Beziffert jeden Bereich — Größe, Speicher, Dauer auf dieser Maschine — und sagt, welche schon vorhanden sind, mit ihrem Urteil, und welche einen pausierten Lauf haben. --format json für ein Skript, --cores um die Annahme der Schätzung zu ändern.

verify. Antwortet verified (dieselben Bytes wie die Referenz), unverified (wohlgeformt, aber für diesen Bereich ist kein Fingerabdruck hinterlegt) oder corrupt (die Datei widerspricht sich selbst). Endet im letzten Fall mit einem Fehler: dieser Befehl ist dafür gemacht, in einem Skript zu stehen.

delete. Entfernt die Tabelle, die wartende Fortsetzung und die Überreste eines abgestorbenen Laufs. Ein Standardbereich wird beim nächsten Start der Anwendung neu berechnet, ein breiterer nicht.

Beispiele:

# Ce que cette machine a, et ce que chaque domaine coûterait
./blunderdb bearoff list

./blunderdb bearoff generate --ts 6x9 --cores 4

# OS-08 : l'EPC répond alors jusqu'à un pion sur la 8
./blunderdb bearoff generate --os 8

# Sur un serveur, dans le volume que lit le démon
./blunderdb bearoff generate --ts 6x11 --data-dir /srv/bearoff

./blunderdb bearoff verify /srv/bearoff/gnubg_ts6x11.bd

analyze — gammonNet-Nachholanalyse

Schreibt eine gammonNet-Analyse für jede Stellung, die noch keine hat — das Nachholen für eine Bibliothek, die angelegt wurde, bevor es diese Funktion gab (ADR-0013, ADR-0015). Es ist dieselbe Operation wie das automatische Auslösen nach einem Import und die Schaltfläche „Jetzt analysieren“ der grafischen Oberfläche sowie der Endpunkt /v1/gammonnet.analyzeMissing des serve-Daemons für einen Tenant — drei verschiedene Formen derselben Operation, nicht drei getrennte Logiken (siehe Headless-Modus (Server)).

./blunderdb analyze --db <path> [options]

Optionen:

  • --db — Datenbank (erforderlich).

  • --ply — Suchtiefe (Standard: 2, der kanonische Parameter).

  • --prune-k — Beschneidungsbreite (Standard: 12, der kanonische Parameter).

  • --candidates — Anzahl der je Zugentscheidung behaltenen Kandidatenzüge (Standard: 10).

  • --jobs — Anzahl der parallel analysierten Stellungen (Standard: die Anzahl der Prozessorkerne des Rechners).

  • --match — Beschränkt den Durchlauf auf die Stellungen eines einzigen Matches (0, die Vorgabe, bedeutet die gesamte Bibliothek).

  • --compare — Schreibt nichts: vergleicht gammonNet mit den importierten Analysen, statt Lücken zu füllen (siehe unten).

  • --limit — Mit --compare: hält nach so vielen Stellungen an (0 = alle).

  • --format — Ausgabeformat: text (Standard, mit Fortschrittsanzeige) oder json (ein einziges Zusammenfassungsdokument, am Ende ausgegeben).

  • --rollout — Spielt die von --query gewählten Stellungen per Rollout aus, anstatt Lücken zu füllen (siehe unten).

  • --query — Mit --rollout die zu spielenden Stellungen, in der Abfragesprache der Suche (search --query-help); leer: alle.

Ein ohne Analyse importiertes Match erhält damit ein Performance Rating. Das betrifft ein online gespieltes Match oder eine Jellyfish-.mat-Datei, die niemand durch XG geschickt hat. blunderDB kannte die Stellungen und die gespielten Züge, aber nichts sagte, was sie wert waren; nach dem Lauf wird der tatsächlich gespielte Zug mit gammonNets Rangfolge verglichen, und die Differenz fließt in das PR und alle übrigen Kennzahlen ein. Der gespielte Zug stammt aus der Zugtabelle des Matches, beim Import geschrieben, ob die Datei nun eine Analyse trug oder nicht — er wird nie geraten.

Eine mit einer älteren Version analysierte Datenbank muss nicht neu bewertet werden: repair berechnet die Spalten aus dem bereits Gespeicherten neu und gibt diesen Matches ihr PR zurück.

Nur ein Match (--match). Mit der Kennung, die list --type matches anzeigt, durchläuft der Stapel nur die Stellungen dieses Matches: dieselbe Lückenregel, dieselben Garantien, engerer Umfang. Ein soeben importiertes Match erhält seine Analysen, ohne dass der Rest der Bibliothek durchlaufen wird, und ein korrigiertes und ein zweites Mal analysiertes Match kostet nur die durch die Korrektur entstandenen Stellungen, da alle übrigen bereits eine Analyse tragen. Die Option lässt sich weder mit --stale noch mit --compare kombinieren, die beide Stellungen betrachten, die bereits eine Analyse haben: beides zugleich zu verlangen ist ein Fehler und kein stillschweigend ignorierter Umfang.

Die Parallelität (--jobs). Die Stellungen eines Durchlaufs sind voneinander unabhängig — keine Suche speist die nächste — also werden sie auf --jobs Threads verteilt, jeder mit seinem eigenen Evaluator. Die geschriebenen Analysen sind identisch, unabhängig vom Wert von --jobs; nur die Rechenzeit ändert sich. --jobs 1 lässt den Rechner für anderes frei. Der Abbruch ist davon nicht betroffen: Ctrl-C hält den Durchlauf vor jeder neuen Stellung an, und alles bereits Berechnete wird geschrieben.

Die Lückenregel (ADR-0013). Eine Stellung, die bereits eine Analyse trägt — XG, GNUbg, BGBlitz oder ein früherer gammonNet-Durchlauf —, wird nie angetastet, welche Engine auch immer fehlt. Nur eine Stellung ohne jede Analyse wird geschrieben. Der Befehl kann daher jederzeit gefahrlos erneut gestartet und sauber unterbrochen werden: Ctrl-C bricht ab, ohne etwas bereits Geschriebenes zu verlieren, und der nächste Lauf setzt genau dort fort, wo der vorige aufgehört hat — kein Journal ist nötig, da „die Stellungen ohne Analyse“ bei jedem Start neu berechnet werden.

Beispiel:

./blunderdb analyze --db base.db

# Analyzing 1204 position(s) with gammonNet (2-ply, k=12, 16 job(s))...
#   1/1204 (0%)
#   61/1204 (5%)
#   ...
#   1204/1204 (100%)
# Done.

./blunderdb analyze --db base.db --jobs 1

# Un seul match, celui qui vient d'être importé
./blunderdb analyze --db base.db --match 12

Rollouts im Stapel (--rollout). Jede von --query gewählte Stellung wird durch einen Rollout gespielt, eine nach der anderen auf allen Kernen, und der Rollout wird neben ihrer Analyse gespeichert, nie an deren Stelle. Der Wert ist eine Voreinstellung — fast (216 Partien, bei 7 abgebrochen) oder standard (1296 Partien, bei 11 abgebrochen) — oder freie Einstellungen: eine optionale Voreinstellung, dann games=, min-games=, truncation=, jsd=, ply=, candidates=, seed=, durch Kommas getrennt. Eine Stellung, die bereits einen Rollout mit denselben Einstellungen trägt, wird übersprungen: Ein mit Strg-C unterbrochener Lauf setzt dort fort, wo er stehen geblieben ist, wobei die laufende Stellung ganz verworfen wird. Eine Stellung, die nur ein Rollout analysiert, wird von der Suche über diesen gefunden; eine bereits analysierte Stellung behält die Spalten ihrer Analyse.

./blunderdb analyze --db base.db --rollout fast --query 'E>80'
./blunderdb analyze --db base.db --rollout 'standard,ply=1' --query 'c'

--compare: was ist gammonNet auf Ihrer Datenbank wert?

Die Genauigkeit des Programms wird anderswo an Referenzkorpora und an der exakten Auswürfeltabelle gemessen. Keine dieser Messungen beantwortet die Frage, die ein Benutzer wirklich hat und die seine Stellungen betrifft: wo widerspricht das eingebaute Programm bei den aus XG importierten Partien der Analyse, die mit der Datei kam, und was würde dieser Widerspruch kosten?

--compare antwortet und schreibt nichts. Das ist keine Vorsichtsmaßnahme, sondern der Sinn des Befehls: ADR-0013 schützt eine importierte Analyse bedingungslos, und der Vergleich lässt sich daher auf einer Datenbank ausführen, die man gerade nicht überschrieben sehen will.

Der Bericht gibt:

  • die Übereinstimmungsrate bei der besten Antwort, getrennt nach Steinzügen und Dopplerentscheidungen — beide haben nichts miteinander zu tun, und eine einzige Rate würde verbergen, welche von beiden nachlässt;

  • die Kosten des Widerspruchs, bewertet auf der Skala der importierten Analyse: was der von gammonNet bevorzugte Zug nach dem importierten Programm wert ist, abzüglich dessen, was dessen eigener bester Zug wert ist. Diese Richtung ist die einzige, die beide Programme gemeinsam beziffern können; einen Widerspruch zweimal zu bewerten lüde dazu ein, die kleinere der beiden Zahlen zu lesen;

  • die Aufschlüsselung nach Spielphase, die sagt, wo die Widersprüche sitzen;

  • die zehn teuersten Widersprüche, Stellung für Stellung.

Zwei Programme schreiben denselben Zug verschieden — XG schreibt „13/7“, wo gammonNet „13/8 8/7“ schreibt, Schläge werden auf der einen Seite markiert und auf der anderen nicht, Wiederholung wird manchmal zu „(2)“ zusammengezogen. Diese Unterschiede sind Dialekt, nicht Widerspruch: der Vergleich führt beide Schreibweisen auf eine kanonische Form zurück, bevor er sie vergleicht. Ohne das zeigte ein Testkorpus 78,8 % Übereinstimmung statt 93,2 % — fünfzehn Punkte falscher Widersprüche.

Ein Zug, den das importierte Programm nicht aufgeführt hat, lässt sich auf dessen Skala nicht bewerten: er zählt als Widerspruch mit Kosten null statt mit erfundenen Kosten.

# Comparer sur un échantillon de 500 positions
./blunderdb analyze --db base.db --compare --limit 500

# compared: 118 decision(s)  (refused 2, failed 0)
# same best answer: 93.2% (110/118)
#   checker play:   93.7% (59/63)
#   cube decision:  92.7% (51/55)
# ...

transcribe — Eine Transkription erneut abspielen

Spielt eine Transkription erneut ab und berichtet, was die Wiedergabe darin findet. Die Quelle ist eine .mat-Datei, ein Match der Bibliothek oder ein Transkriptionsentwurf — genau eine der drei. Ein Match wird über die .mat gelesen, die es beim Export erzeugen würde: abgespielt wird also das, was ein Export enthielte.

./blunderdb transcribe --mat <fichier> [--check] [--render <sortie>]
./blunderdb transcribe --db <path> --match <id> --check
./blunderdb transcribe --db <path> --draft <id> --check
./blunderdb transcribe --db <path> --match <id> --edit [--accept-losses]
./blunderdb transcribe --db <path> --draft <id> --finish|--abandon

Optionen:

  • --mat — Abzuspielende .mat-Datei.

  • --db — Datenbank, für --match und --draft.

  • --match — Kennung des abzuspielenden Matches der Bibliothek.

  • --draft — Kennung des abzuspielenden Transkriptionsentwurfs.

  • --check — Listet die gefundenen Inkonsistenzen auf (Standardverhalten).

  • --render — Schreibt die Transkription als .mat an diesen Pfad zurück.

  • --format — Ausgabeformat: text (Standard) oder json.

  • --edit — Öffnet einen Entwurf für das --match (oder gibt den dort bereits geöffneten zurück).

  • --accept-losses — Mit --edit bei einem importierten Match: akzeptiert, dass dessen Analysen und Kommentare verloren gehen können.

  • --finish — Schließt den --draft ab: schreibt sein Match oder ersetzt dasjenige, aus dem er geöffnet wurde, und gibt den Entwurf frei.

  • --abandon — Verwirft den --draft: löscht ihn ohne Match; ein Match, aus dem er geöffnet wurde, bleibt unverändert.

  • --yes — Mit --abandon für einen Entwurf, der nie ein Match hervorgebracht hat: bestätigt, dass alles darin Geschriebene verloren geht.

--check benennt jede Inkonsistenz mit der Nummer der Aktion und der Partie, in der sie steht: ein illegaler Zug, zweimal hintereinander derselbe Spieler am Zug, eine unmögliche Dopplerwürfel-Aktion, eine Aktion nach dem Ende des Matches, ein Zug, dessen Schritte nicht die eigenen Würfel verwenden, ein erster Zug einer Partie mit einem Pasch, der kein Eröffnungswurf sein kann, ein nicht aufgezeichneter Zug — die Zelle ???, die gnubg schreibt, wenn es den gespielten Zug nicht behalten hat, und die nicht bedeutet, dass der Spieler nicht ziehen konnte, ein widersprüchlicher angesagter Spielstand — eine Partie, deren Spielstandzeile nicht die ist, die die vorherigen Partien ergeben, und die zum geschriebenen Spielstand nachgespielt wird.

Eine Inkonsistenz wird berichtet, nie entgegengehalten: nichts wird ihretwegen abgelehnt, und der Rückgabewert bleibt 0, was die Wiedergabe auch findet. Ein Wert ungleich 0 meldet einen echten Fehlschlag — eine unlesbare Datei, eine Datenbank, die sich nicht öffnen lässt, eine Ausgabe, die sich nicht schreiben lässt. Ein Skript, das auf die Befunde reagieren will, liest sie aus --format json, wo eine kaputte Datei und eine Partie mit einem illegalen Zug nicht verwechselt werden.

--render schreibt die Transkription wieder als .mat, womit sich der Hin- und Rückweg an einer echten Datei außerhalb der Tests prüfen lässt.

Nur drei Optionen schreiben, über dieselben Methoden wie das Transkriptionspanel: --edit öffnet einen Entwurf für ein bestehendes Match, --finish schließt ihn ab — das Match wird unter derselben Kennung ersetzt — und --abandon löscht einen Entwurf ohne Match und verlangt --yes für einen nie abgeschlossenen Entwurf, der alles darin Geschriebene mitnimmt. Ein importiertes Match trägt Analysen und Kommentare, die eine .mat-Datei nicht trägt: --edit gibt höchstens deren Anzahl an und lehnt ohne --accept-losses ab.

Beispiel:

./blunderdb transcribe --mat match.mat --check

# match.mat: 7 point match, 4 game(s), 203 action(s)
#   Final score: 9-2
# Inconsistencies: none

tournament — Ein geleitetes Turnier lesen

Liest ein geleitetes Turnier ohne grafische Oberfläche. Ein Turnier interaktiv zu leiten ist Aufgabe der Konsole der Nicomaque-Engine; diese Unterbefehle lesen, keiner wartet auf eine Eingabe, und nur move schreibt.

./blunderdb tournament <sous-commande> --db <chemin> [options]

Unterbefehle:

  • list [--format text|json] — Die geleiteten Turniere der Datenbank, mit ihrem Zustand, der Engine-Version, der Veranstaltung, zu der jedes gehört (leer, wenn keine), und dem Datum der letzten Entscheidung.

  • verify --id N [--format text|json] — Spielt die Leitung erneut ab und meldet jede verbleibende Warnung. Endet mit Fehler, wenn eine bleibt: Das ist die Prüfung im Nachhinein, und ein Skript, das sie über die Datenbanken einer Saison laufen lässt, will einen Rückgabewert und keine Zeile zum Filtern.

  • standings --id N — Die Wertung als CSV, Preisgelder inbegriffen, in der Sprache der Oberfläche.

  • ranking --season [--rencontre N] [--from AAAA-MM-JJ] [--to AAAA-MM-JJ] [--points 25,18,15] [--participation P] [--elo] [--format csv|json] — Die Saisonwertung: die abgeschlossenen Turniere einer Veranstaltung oder eines Zeitraums (Grenzen eingeschlossen, nach dem Turnierdatum; ohne Filter alle geleiteten Turniere), wobei jeder Platz durch die Skala in Punkte umgerechnet wird (der Sieger zuerst; standardmäßig 25, 18, 15, 12, 10, 8, 6, 4, 2, 1), plus --participation pro gespieltem Turnier. Punktgleiche teilen sich den Durchschnitt der Plätze, die sie belegen. Eine Person wird von einem Turnier zum nächsten am Namen erkannt. --elo fügt ein Club-Elo hinzu, das über die Matches der Saison neu berechnet wird (FIBS-Formel, Start bei 1500). Die CSV enthält eine Zeile pro Person und eine Punktespalte pro Turnier; ein nicht abgeschlossenes Turnier wird aufgeführt, bringt aber nichts ein.

  • page --id N|--rencontre N [--out <Ordner>] — Die HTML-Anzeigeseite eines Wettbewerbs (--id), oder die Wandseite einer Veranstaltung (--rencontre: eine Zeile pro Tisch, gleich welcher Wettbewerb ihn belegt). Genau eine der beiden Optionen ist erforderlich. Ohne --out geht sie auf die Standardausgabe; mit --out wird sie in den Ordner geschrieben, der damit zum Ordner der Leitung oder der Veranstaltung wird.

  • export --id N — Das rohe Ereignisjournal, von den Werkzeugen der Engine abspielbar. Das Journal ist die ganze Wahrheit einer Leitung: Wertung, Tableaus und Warnungen werden daraus abgespielt. Ein Werkzeug, das diese Ausgabe liest, braucht überhaupt kein blunderDB.

  • move --id N --match M --table T [--format text|json] — Ändert den Tisch eines laufenden Matches, wie das Ziehen eines Feldes auf ein anderes im Raster. Ist der Zieltisch belegt, tauschen die beiden Matches ihre Tische; ein Tisch außer Betrieb wird abgelehnt. Ist der Tisch in einer Veranstaltung von einem anderen Wettbewerb belegt, erfolgt der Tausch zwischen den beiden Wettbewerben: Ein Tischwechsel wird in jedes Protokoll geschrieben. Gibt den Tisch jedes laufenden Matches aus.

  • hall --rencontre N [--format text|json] — Alle Tische einer Veranstaltung: eine Zeile pro Tisch, gleich welcher Wettbewerb ihn belegt (Wettbewerb, Match, Spieler), dann die Vorschläge jedes Wettbewerbs. Das ist das Raster, das die Ansicht Alle Tische der Direction anzeigt. Die Tische sind nach Saal gruppiert, wenn die Veranstaltung Säle hat, und benannt, wenn sie einen Namen tragen.

  • tables --rencontre N|--tournament N [--format text|json] — Die Tischeigenschaften (Name, Saal, reserviert, zugewiesen an) und die Säle, in denen jeder Wettbewerb einer Veranstaltung gespielt wird (--rencontre), oder die Eigenschaften eines Wettbewerbs, der allein gespielt wird (--tournament). Nur lesend: Schreiben läuft über call (rencontres.setTables, rencontres.setEventRooms, directions.setTables).

Gemeinsame Optionen: --db (erforderlich), --id (erforderlich außer bei list, page --rencontre hall und tables), --format.

Beispiele:

./blunderdb tournament list --db base.db
./blunderdb tournament verify --db base.db --id 3
./blunderdb tournament standings --db base.db --id 3 > classement.csv
./blunderdb tournament ranking --db base.db --season --from 2026-01-01 --to 2026-12-31 --elo > saison.csv
./blunderdb tournament page --db base.db --id 3 --out /tmp/affichage
./blunderdb tournament page --db base.db --rencontre 1 --out /tmp/evenement
./blunderdb tournament export --db base.db --id 3 > journal.json
./blunderdb tournament move --db base.db --id 3 --match m4 --table 7
./blunderdb tournament hall --db base.db --rencontre 1
./blunderdb tournament tables --db base.db --rencontre 1

trash — Der Papierkorb

Was gelöscht wurde und womit es sich zurückholen lässt. Ein Löschvorgang bleibt ein Löschvorgang: ein JSON-Schnappschuss dessen, was verschwindet, wird zuvor geschrieben, und nichts sonst in der Datenbank weiß, dass diese Tabelle existiert — kein Suchfilter, keine Statistik, keine Aufbewahrungsregel.

./blunderdb trash <sous-commande> --db <chemin> [options]

Unterbefehle:

  • list — Was im Papierkorb liegt, das zuletzt Gelöschte zuerst.

  • restore --id N — Stellt Eintrag N wieder her und entfernt ihn aus dem Papierkorb.

  • discard --id N — Verwirft Eintrag N sofort, ohne ihn wiederherzustellen.

  • empty [--older-than T] — Leert den Papierkorb, oder nur, was älter als T Tage ist.

  • delete --kind K --id N — Löscht ein Objekt über den Papierkorb, damit der Vorgang rückgängig gemacht werden kann. K ist position, collection oder comment.

Gemeinsame Optionen: --db (erforderlich), --kind, --limit (Standard 50), --format (text oder json).

Bemerkung

blunderdb delete löscht weiterhin ohne Netz: ein Skript, das eine Stellung löscht, erwartet, dass sie weg ist, und stillschweigend einen Schnappschuss zurückzulassen würde eine Datei wachsen lassen, deren Wachstum niemand verlangt hat. trash delete ist das, was die Rücknahme behält.

Das Wiederherstellen einer Stellung geht erneut durch die Zobrist-Deduplizierung: es entsteht nie ein Duplikat, aber die alte Kennung kommt nicht zurück — die ursprüngliche Zeile existiert nicht mehr. Eine wiederhergestellte Stellung ist dieselbe Stellung unter einer neuen Nummer.

Was älter als dreißig Tage ist, entfernt blunderdb vacuum — nie beim Öffnen einer Datenbank.

Beispiele:

# Supprimer une position en gardant l'annulation
./blunderdb trash delete --db base.db --kind position --id 412

# Voir la corbeille, puis remettre une entrée
./blunderdb trash list --db base.db
./blunderdb trash restore --db base.db --id 3

# Ne garder que ce qui a moins de trente jours
./blunderdb trash empty --db base.db --older-than 30

info — Datenbank-Metadaten

Zeigt die Metadaten und Statistiken einer Datenbank an.

./blunderdb info --db <path> [--format <format>]

Optionen:

  • --db — Datenbank (erforderlich).

  • --format — Ausgabeformat: text oder json (Standard: text).

Beispiele:

./blunderdb info --db base.db

# Database Information
# ==================================================
# Path: /home/jean/bg/base.db
#
# Metadata:
#   Version: 2.20.0
#   User: Jean
#   Description: Matchs de tournoi 2025
#   Date of Creation: 2026-09-06 02:43:51
#
# Statistics:
#   Positions: 3859
#   Analyses: 3855
#   Matches: 11
#   Games: 61
#   Moves: 3766

--format json fügt die Herkunft der Datei hinzu — issuance trägt das Wasserzeichen, falls vorhanden, sowie die Aussteller-Identität dieser Maschine:

./blunderdb info --db base.db --format json
{
  "issuance": {
    "watermarked": false,
    "issuerFingerprint": "1186-57FA-060C-9378",
    "issuerName": "unger"
  },
  "metadata": {
    "database_version": "2.20.0",
    "dateOfCreation": "2026-09-06 02:43:51",
    "description": "Matchs de tournoi 2025",
    "user": "Jean"
  },
  "path": "/home/jean/bg/base.db",
  "stats": {
    "analysis_count": 3855,
    "game_count": 61,
    "match_count": 11,
    "move_count": 3766,
    "position_count": 3859
  }
}

edit — Metadaten ändern

Bearbeitet den Benutzernamen, die Beschreibung oder die Schwellenwerte einer Datenbank.

./blunderdb edit --db <path> [options]

Optionen:

  • --db — Datenbank (erforderlich).

  • --user — Neuer Benutzername.

  • --description — Neue Beschreibung.

  • --clear-user — Benutzernamen löschen.

  • --clear-description — Beschreibung löschen.

  • --error-threshold — Fehlerschwelle, in Millipunkten: Eine Entscheidung, die mindestens so viel kostet, ist ein Fehler.

  • --blunder-threshold — Blunder-Schwelle, in Millipunkten: Ein Fehler, der mindestens so viel kostet, ist ein Blunder.

  • --format — Ausgabeformat: text (Standard) oder json ({"changes": [...]}).

Mindestens eine Änderungsoption ist erforderlich.

Beispiele:

./blunderdb edit --db base.db --user "Marie" --description "Ma collection"
./blunderdb edit --db base.db --clear-description
./blunderdb edit --db base.db --error-threshold 20 --blunder-threshold 80

verify — Integrität prüfen

Prüft die Integrität der Datenbank und vergleicht optional ein Match mit seiner Quelldatei.

./blunderdb verify --db <path> [--match <id>] [--mat <file.mat>]

Optionen:

  • --db — Datenbank (erforderlich).

  • --match — ID des zu prüfenden Matches.

  • --mat — Zum Vergleich heranzuziehende MAT-Datei (zusammen mit --match verwendet).

  • --format — Ausgabeformat: text (Standard) oder json (Statistiken, verwaiste Zeilen, Schemaabweichung und ggf. die Matchprüfung).

Ohne die Option --match zeigt der Befehl die allgemeinen Statistiken der Datenbank an. Mit --match prüft er die Match-Daten und kann sie mit der ursprünglichen Quelldatei vergleichen.

Jeder Durchlauf prüft außerdem die referenzielle Integrität: Er zählt verwaiste Zeilen — Partien ohne Match, Züge ohne Partie, Zuganalysen ohne Zug, Analysen ohne Stellung, Einträge des Wiederholungsjournals ohne Stapel oder ohne Stellung — und gibt eine WARNING-Zeile mit der Gesamtzahl aus, wenn es welche gibt. Eine gesunde Datenbank meldet Orphaned rows: none. Verwaiste Zeilen können in einer Datenbank zurückbleiben, die von einer Version geschrieben wurde, die Fremdschlüssel nicht auf jeder Verbindung durchsetzte, oder bevor das Wiederholungsjournal eigene hatte; sie gehören zu keinem Match und zu keinem Stapel und belegen nur Platz. Der Befehl endet dennoch mit dem Exit-Code 0.

Jeder Lauf vergleicht außerdem das Schema mit der Referenz-DDL und listet die Tabellen, Spalten und Indizes auf, die der Datenbank fehlen. Beim Öffnen einer Datenbank wird ergänzt, was fehlt, sofern das möglich ist; was nicht ergänzt werden kann (typischerweise ein UNIQUE-Index, dessen Neuaufbau doppelte Zeilen verhindern), wird nur protokolliert: hier wird diese Lücke sichtbar, und eine Abfrage, die eines dieser Elemente nennt, schlägt fehl, bis die Ursache behoben ist. Eine gesunde Datenbank antwortet Schema: matches the reference DDL. Wie bei den verwaisten Zeilen ist eine Schemaabweichung ein Befund, kein Fehlschlag: der Exit-Code bleibt 0.

Jeder Durchlauf prüft schließlich die Regeln, die die aktuelle DDL aufstellt, die SQLite einer bereits bestehenden Tabelle aber nicht hinzufügen kann: die CHECK-Bereichsbedingungen (Würfel zwischen 0 und 6, Dopplerwürfel und Pips nicht negativ, 0 bis 15 abgetragene Steine, Bewertungen zwischen 1 und 4), den Zobrist-Hash, der einer Zeile nie fehlen dürfte, und eine Analyse je Position. Eine seit Schemaversion 2.18.0 angelegte Datenbank erzwingt sie; eine ältere kann noch Zeilen enthalten, die eine neue Datenbank ablehnen würde — genau diese werden hier Regel für Regel gezählt. Eine gesunde Datenbank meldet Constraints: every row satisfies the current DDL. Ein weiterer Befund: Es wird nichts repariert, und der Exit-Code bleibt 0.

Jeder Durchlauf berechnet schließlich die beiden denormalisierten Zähler match.game_count und game.move_count aus den Zeilen neu, die sie zu zählen vorgeben, und meldet, wie viele abweichen und um wie viel im schlimmsten Fall. Beide werden einmal beim Import aus dem geschrieben, was die Quelldatei enthielt, und sind das, was die Matchliste und die Partieansicht anzeigen: eine kleine Abweichung ist meist ein Import, der übersprungen hat, was er nicht umwandeln konnte. Es wird nichts überschrieben — den Zähler durch das Gespeicherte zu ersetzen würde genau die Abweichung tilgen, die man sehen will. Eine gesunde Datenbank meldet Counters: game_count and move_count agree with the rows.

Beispiele:

./blunderdb verify --db base.db
./blunderdb verify --db base.db --match 1
./blunderdb verify --db base.db --match 1 --mat original.mat

Als Wächter einsetzen. Der Exit-Code ist immer 0, unabhängig davon, was der Befehl findet: Das Urteil steckt in --format json, und ein Skript muss die Zähler selbst auswerten.

{
  "stats": {
    "analysis_count": 3855,
    "game_count": 61,
    "match_count": 11,
    "move_count": 3766,
    "position_count": 3859
  },
  "orphans": {
    "games_without_match": 0,
    "moves_without_game": 0,
    "move_analyses_without_move": 0,
    "analyses_without_position": 0,
    "reviews_without_deck": 0,
    "reviews_without_position": 0
  },
  "orphan_total": 0,
  "schema_drift": {
    "missing_tables": null,
    "missing_columns": null,
    "missing_indexes": null
  },
  "schema_drift_count": 0,
  "constraint_violations": [
    {"name": "position.zobrist_hash NOT NULL", "count": 0},
    {"name": "position.dice_1 BETWEEN 0 AND 6", "count": 0}
  ],
  "constraint_violation_total": 0,
  "counter_drift": {
    "matches_with_wrong_game_count": 0,
    "games_with_wrong_move_count": 53,
    "worst_game_count_gap": 0,
    "worst_move_count_gap": 2
  },
  "counter_drift_total": 53
}

Drei Felder sind ein Alarmsignal: orphan_total, schema_drift_count und constraint_violation_total. Sind sie von null verschieden, beschreiben sie eine Datenbank, die repariert werden muss.

./blunderdb verify --db base.db --format json \
  | jq -e '.orphan_total == 0 and .schema_drift_count == 0 and .constraint_violation_total == 0'

counter_drift_total gehört nicht dazu, und das obige Beispiel zeigt es: Die Datenbank, die es erzeugt hat, war gerade erst importiert worden und zeigt bereits 53 Partien, deren Zugzähler von dem abweicht, was die Zeilen enthalten. Diese Zähler stammen aus der Quelldatei, nicht aus der Datenbank; eine Abweichung erzählt etwas über den Import, sie zeigt keine Beschädigung an. Beobachten Sie sie, aber verwenden Sie sie nicht als Schwellenwert.

vacuum — Die Datenbank komprimieren

Gewinnt den durch Löschungen (Matches, Turniere, Bereinigungen) freigewordenen Speicherplatz zurück: SQLite verkleinert die Datei beim Löschen von Daten nie von selbst, man muss es ausdrücklich anfordern. Das ist die einzige Möglichkeit, eine Komprimierung auszulösen — beim Öffnen einer Datenbank geschieht sie nie automatisch, da ihre Kosten bei einer großen Datenbank unvorhersehbar sind.

./blunderdb vacuum --db <path>

Optionen:

  • --db — Datenbank (erforderlich).

  • --format — Ausgabeformat: text (Standard) oder json ({"size_before", "size_after", "reclaimed"}, in Byte).

Der Befehl beginnt mit einem wal_checkpoint(TRUNCATE), damit die vor der Komprimierung angezeigte Größe ehrlich ist, prüft, dass auf der Platte etwa die doppelte aktuelle Dateigröße frei ist (SQLite baut die Datenbank vollständig neu auf, bevor es auf sie umschaltet), führt das VACUUM aus und danach ein ANALYZE, um die vom Abfrageplaner genutzten Statistiken aufzufrischen. Fehlt Speicherplatz, verweigert der Befehl den Start mit einer eindeutigen Meldung, statt eine abgebrochene Komprimierung zu riskieren.

Beispiel:

./blunderdb vacuum --db base.db

# Compacting database...
#   Before: 128.4 MiB
#   After:  41.2 MiB
#   Reclaimed: 87.2 MiB

repair — Neu berechnen, was abgeleitet ist

Berechnet neu, was die Datenbank aus dem Gespeicherten ableitet: die skalaren Spalten jeder Analyse aus der Analyse selbst, von der sie nur eine Projektion sind; die Phase und den Spieltyp jeder Stellung aus ihrem Brett; und die Crawford-Markierung jedes Spielstands aus der Partie, aus der die Stellung stammt, oder aus der XGID, mit der sie hereingekommen ist. Die Analysen bleiben unangetastet: neu gemacht werden die daraus abgeleiteten Werte.

./blunderdb repair --db <path>

Optionen:

  • --db — Datenbank (erforderlich).

  • --format — Ausgabeformat: text (Standard) oder json — ein Zähler pro Durchlauf: repaired (Analysespalten), phases (neu eingestufte Stellungen) und crawford (neu gehashte Stellungen). Jeder nennt die Zahl der tatsächlich geänderten Zeilen.

Nützlich nach einer Korrektur daran, wie eine importierte Analyse gelesen wird. Das ist bereits zweimal vorgekommen. Der XG-Importeur schreibt ein „kein Doppel“ auf zwei Arten, und die zweite wurde als echtes Doppel verstanden — die Spalte trug dann den Fehler eines Doppels, das nie stattgefunden hat. Und eine von blunderDB selbst berechnete Analyse wusste nicht, welcher Zug gespielt worden war, sodass ein ohne Analyse importiertes Match überall einen Fehler von null und ein PR von 0,00 behielt; die Spalte wird nun aus den Zügen des Matches neu berechnet. Die Lesart zu korrigieren ändert nichts an den bereits geschriebenen Zeilen; dieser Befehl erneuert sie.

Der Crawford-Durchgang rührt dagegen die Stellungen selbst an. Ein Spielstand von 1 bedeutet „noch ein Punkt, und dieses Spiel IST das Crawford-Spiel“; 0 bedeutet „noch ein Punkt, das Crawford-Spiel liegt hinter uns“. Solange die Importeure diesen Unterschied nicht geschrieben haben, wurde jede Stellung nach Crawford als Crawford-Stellung gespeichert und damit mit totem Dopplerwürfel gelesen — dort, wo der Zurückliegende in Wahrheit bei der ersten Gelegenheit verdoppelt. Die Korrektur des Spielstands ändert den Hash der Stellung: die Zeile wird also neu gehasht und mit ihrem korrekten Zwilling verschmolzen, falls die Datenbank bereits einen hält — die Analyse, die Kommentare, die Sammlungen, die Anki-Karten und ihr Wiederholungsprotokoll, die Züge der Partie und die Einträge des Papierkorbs, die sie nennen, folgen der überlebenden Zeile. Eine Stellung, auf die keine Partie zeigt, wird nur auf das Wort der XGID hin korrigiert, die sie aus einem anderen Programm mitgebracht hat (XG, BGBlitz…): wenn das Crawford-Feld dieser XGID sagt, dass das Spiel nicht das Crawford-Spiel ist, und die XGID wirklich diese Stellung beschreibt. In der anderen Richtung wird eine Stellung ohne Partie, die auf beiden Seiten mit 0 gespeichert ist, zu 1, wenn die mitgebrachte XGID die einer Partie auf 1 Punkt ist und sie beschreibt: Das einzige Spiel einer Partie auf 1 Punkt beginnt einen Punkt vor dem Ziel, es ist also das Crawford-Spiel, so wie die Importeure es schreiben. Das DMP nach dem Crawford-Spiel einer längeren Partie bleibt bei 0: seine XGID nennt die Länge dieser Partie. Eine XGID, die blunderDB selbst neu geschrieben hat, wiederholt nur den gespeicherten Spielstand und beweist nichts. Jede andere Stellung ohne Partie bleibt unverändert: nichts widerspricht dem, was ihr Spielstand angibt.

Nichts löst ihn automatisch aus, und das ist Absicht: die Analysespalten aller Nutzer neu zu schreiben oder Stellungen neu zu hashen, nur weil eine Datenbank geöffnet wird, ist nichts, was ein Werkzeug hinter dem Rücken seines Nutzers tun sollte.

Beispiel:

./blunderdb repair --db base.db

# 42 analyses repaired.
# 7 positions reclassified.
# 3 positions rehashed onto the right Crawford sentinel.

delete — Daten löschen

Löscht ein Match und alle zugehörigen Daten (Spiele, Züge, Analysen).

./blunderdb delete --db <path> --type match --id <id> [--confirm]

Optionen:

  • --db — Datenbank (erforderlich).

  • --type — Löschtyp: match (erforderlich).

  • --id — ID des zu löschenden Elements (erforderlich).

  • --confirm — Ohne Bestätigungsabfrage löschen.

  • --format — Ausgabeformat: text (Standard) oder json ({"match_id": N, "deleted": true}).

Beispiele:

# Confirmation interactive, puis sans confirmation (scripts)
./blunderdb delete --db base.db --type match --id 1
./blunderdb delete --db base.db --type match --id 1 --confirm

healthcheck — Einen Daemon abfragen

Fragt einen laufenden serve-Daemon (siehe Headless-Modus (Server)), ob er bereit ist: eine GET /readyz-Anfrage, Exit-Code 0, wenn der Daemon mit 200 antwortet (Speicher erreichbar, Schema in der erwarteten Version), sonst 1 — Speicher nicht erreichbar, veraltetes Schema oder nichts lauscht an der Adresse. Es wird keine Datenbankdatei geöffnet.

./blunderdb healthcheck [--addr host:port] [--timeout 2s]

Optionen:

  • --addr — Adresse, an der der Daemon lauscht (Standard BLUNDERDB_ADDR, sonst :8080). Eine Adresse ohne Host (:8080) oder mit einem Platzhalter-Host (0.0.0.0, [::]) wird über die Loopback-Schnittstelle abgefragt.

  • --timeout — Zeit, nach der die Sonde aufgibt (standardmäßig 2s).

Das ist der Befehl, den der HEALTHCHECK des Container-Images ausführt (ein distroless-Image, ohne curl); die aus cmd/serve gebaute serve-Binary versteht ihn ebenfalls. Er eignet sich genauso für ein Skript oder eine systemd-Unit.

Beispiel:

./blunderdb serve --db base.db --addr 127.0.0.1:8080 &
./blunderdb healthcheck --addr 127.0.0.1:8080 && echo "démon disponible"

# ready

Im Fehlerfall wird der Grund ausgegeben, den docker inspect für einen unhealthy-Container wiedergibt:

Error: healthcheck: http://127.0.0.1:8080/readyz answered 503 Service Unavailable (version_mismatch)

mcp — Die Datenbank einem KI-Assistenten anbieten

Stellt einem KI-Assistenten die Werkzeuge der Datenbank über das Model Context Protocol über Standardein- und -ausgabe bereit: Der Assistent startet den Befehl. Die Werkzeuge suchen Positionen in der Grammatik der Befehlsleiste, lesen eine Position und ihre Analyse, erklären einen Fehler, berechnen die Statistiken eines Spielers, listen Matches, Turniere und Sammlungen auf und stellen eine Quizfrage. Sie lesen nur, außer mit --write. Die vollständige Liste und das HTTP-Äquivalent des Daemons: Werkzeuge für einen KI-Assistenten (MCP).

./blunderdb mcp --db base.db [--write]

Optionen:

  • --db — Datenbankdatei (erforderlich).

  • --write — Bietet auch die schreibenden Werkzeuge an: eine Position speichern, kommentieren, eine Sammlung anlegen und füllen. Nichts wird gelöscht.

Wie call migriert der Befehl das Schema einer älteren Datenbank beim Öffnen, auch ohne --write.

Beispiel: die Datenbank bei Claude Code anmelden.

claude mcp add blunderdb -- blunderdb mcp --db /chemin/vers/base.db

completion — Shell-Vervollständigung

Gibt auf der Standardausgabe ein Shell-Vervollständigungsskript für die Namen der Unterbefehle aus. Die in jedes Skript eingebettete Befehlsliste wird aus derselben Tabelle erzeugt, die auch blunderdb help und die Weiterleitung in main.go (handlers()) lesen: ein neuer Unterbefehl wird der Vervollständigung also angeboten, sobald er eingebunden ist, ohne dass etwas von Hand gepflegt werden müsste.

./blunderdb completion <bash|zsh|fish>

Beispiele:

# bash
source <(blunderdb completion bash)
blunderdb completion bash | sudo tee /etc/bash_completion.d/blunderdb > /dev/null

# zsh : un répertoire déjà sur $fpath
blunderdb completion zsh > "${fpath[1]}/_blunderdb"

# fish
blunderdb completion fish | source

Pakete installieren dies automatisch: Das .deb/.rpm (nfpm) und das AUR-Paket erzeugen die drei Skripte zur Baukompilierzeit aus der gepackten Binärdatei, und das Homebrew-Cask führt blunderdb completion <shell> einmal bei der Installation über generate_completions_from_executable aus. Nichts davon wird ins Repository eingecheckt, sodass die Vervollständigung nie von der Unterbefehlstabelle abweichen kann.

version — Version anzeigen

Zeigt die Version von blunderDB und die Version des Datenbankschemas, das diese Binärdatei schreibt; das ist das Erste, was einem Fehlerbericht beizulegen ist.

./blunderdb version
# blunderDB version 0.36.0 (database schema 2.20.0)

Workflow-Beispiele

Ein Turnierverzeichnis importieren

./blunderdb create --db tournoi_paris.db --user "Jean" --description "Open de Paris 2025"
./blunderdb import --db tournoi_paris.db --type batch --dir ./matchs_open_paris/
./blunderdb list --db tournoi_paris.db --type stats

Regelmäßige Sicherung

./blunderdb export --db production.db --type database --file sauvegarde-$(date +%Y%m%d).db

Fehleranalyse

# Les positions délicates, puis celles de videau
./blunderdb search --db production.db --error-min 0.1 --export blunders.db
./blunderdb search --db production.db --decision cube --error-min 0.05 --export cube_errors.db

# Les coups réellement fautifs : au moins 100 millièmes d'équité perdus
./blunderdb search --db production.db --move-error-min 100 --format json

Rückgabecodes

  • 0 — Erfolg.

  • 1 — Fehler.

Dadurch lässt sich die CLI in Skripten mit Fehlerbehandlung verwenden:

if ./blunderdb import --db base.db --type match --file match.xg; then
    echo "OK"
else
    echo "KO"
    exit 1
fi