Διεπαφή γραμμής εντολών (CLI)
Εισαγωγή
Το blunderDB περιλαμβάνει μια πλήρη διεπαφή γραμμής εντολών (CLI) στο ίδιο εκτελέσιμο με τη γραφική διεπαφή. Η CLI είναι ιδιαίτερα χρήσιμη για:
τη μαζική εισαγωγή αγώνων: εισαγωγή ενός ολόκληρου καταλόγου αρχείων αγώνων (XG, SGF, MAT, BGF…) με μία μόνο εντολή,
την αυτοματοποίηση: ενσωμάτωση του blunderDB σε σενάρια κελύφους για τακτικά αντίγραφα ασφαλείας, προγραμματισμένες εξαγωγές ή αλυσίδες επεξεργασίας,
τη χρήση σε διακομιστή: διαχείριση βάσεων δεδομένων σε μηχανήματα χωρίς γραφικό περιβάλλον,
τη γρήγορη επιθεώρηση: έλεγχος του περιεχομένου ή της ακεραιότητας μιας βάσης δεδομένων χωρίς εκκίνηση της γραφικής διεπαφής.
Η CLI χρησιμοποιεί ακριβώς την ίδια μορφή βάσης δεδομένων με τη γραφική διεπαφή: και οι δύο γράφουν το ίδιο αρχείο, δεν υπάρχει τίποτα να συγχρονιστεί.
Σημείωση
Αν η εφαρμογή είναι ανοιχτή ενώ ένα σενάριο γράφει. Το αρχείο βρίσκεται σε λειτουργία WAL: μια ανάγνωση δεν μπλοκάρει ποτέ μια εγγραφή, και τα δύο προγράμματα δουλεύουν στην ίδια βάση χωρίς να ενοχλεί το ένα το άλλο. Δύο εγγραφές, αντιθέτως, γίνονται διαδοχικά — η δεύτερη περιμένει το κλείδωμα εγγραφής (δέκα δευτερόλεπτα ανά εντολή, συν μερικές νέες προσπάθειες) και αποτυγχάνει μόνο αν εξαντληθεί η αναμονή, με ένα μήνυμα που κατονομάζει το SQLite:
Error: failed to import match: sqlite: save match: database is locked (5) (SQLITE_BUSY)
Η γραφική διεπαφή δεν παρακολουθεί το αρχείο: συνεχίζει να εμφανίζει ό,τι είχε φορτώσει μέχρι το CTRL-R να επαναφορτώσει τις θέσεις. Τίποτα δεν χάνεται, αλλά η οθόνη είναι πίσω από τη βάση.
Γενική σύνταξη
Η λειτουργία ανιχνεύεται αυτόματα: αν το πρώτο όρισμα είναι μια εντολή CLI, το blunderDB εκκινεί σε λειτουργία χωρίς γραφικό περιβάλλον (headless), διαφορετικά εκκινεί τη γραφική διεπαφή.
# GUI
./blunderdb
# CLI
./blunderdb <command> [options]
Τα παραδείγματα αυτής της σελίδας γράφουν ./blunderdb: το εκτελέσιμο όπως λαμβάνεται, καλούμενο από τον φάκελο όπου βρίσκεται. Εγκατεστημένο από πακέτο, ή συνδεδεμένο από φάκελο του PATH (δείτε Λήψη και εγκατάσταση), καλείται απλώς blunderdb.
Οι δυαδικές επιλογές που δηλώνονται ως «προεπιλογή: ναι» απενεργοποιούνται με τη μορφή --option=false — --recursive=false, --analysis=false. Η μορφή με κενό διάστημα δεν υπάρχει: το --recursive false αφήνει την επιλογή στην προεπιλεγμένη τιμή της και θεωρεί το false ένα όρισμα παραπάνω.
Διαθέσιμες εντολές
Εντολή |
Περιγραφή |
|---|---|
create |
Δημιουργεί μια νέα βάση δεδομένων. |
import |
Εισάγει δεδομένα (αγώνας, θέση, παρτίδα). |
export |
Εξάγει δεδομένα. |
identity |
Εμφανίζει ή μετακινεί την ταυτότητα εκδότη (κλειδί υπογραφής των υδατογραφημάτων). |
open |
Μετατρέπει ένα αρχείο προστατευμένο με κωδικό (.dbx) σε συνηθισμένη βάση. |
search |
Αναζητά θέσεις με φίλτρα. |
list |
Εμφανίζει το περιεχόμενο της βάσης. |
match |
Εμφανίζει τις θέσεις και τις αναλύσεις ενός αγώνα. |
collection |
Διαχειρίζεται τις συλλογές (λίστα, περιεχόμενο, δημιουργία, μετονομασία, διαγραφή, εξαγωγή). |
anki |
Πακέτα επανάληψης με διαστήματα (λίστα, στατιστικά, πρόβλεψη, συγχρονισμός). |
rollout |
Παίζει μια θέση ως το τέλος για να ξεχωρίσει τις κινήσεις της ή την απόφαση κύβου (XGID ή OGID). |
epc |
Υπολογίζει το Effective Pip Count και την ετυμηγορία κύβου μιας θέσης εξόδου (XGID ή OGID). |
bearoff |
Δημιουργεί, παραθέτει, ελέγχει και διαγράφει τις βάσεις bearoff. |
analyze |
Γράφει μια ανάλυση gammonNet για κάθε θέση που δεν έχει καμία. |
info |
Εμφανίζει τα μεταδεδομένα της βάσης. |
edit |
Τροποποιεί τα μεταδεδομένα και τα κατώφλια της βάσης. |
verify |
Ελέγχει την ακεραιότητα της βάσης. |
vacuum |
Συμπυκνώνει το αρχείο της βάσης, ανακτώντας τον ελεύθερο χώρο. |
repair |
Επανυπολογίζει ό,τι η βάση παράγει από όσα αποθηκεύει. |
delete |
Διαγράφει δεδομένα. |
healthcheck |
Ρωτά έναν δαίμονα |
mcp |
Προσφέρει τα εργαλεία της βάσης σε έναν βοηθό ΤΝ (Model Context Protocol). |
completion |
Εμφανίζει ένα σενάριο συμπλήρωσης κελύφους (bash, zsh, fish). |
help |
Εμφανίζει τη βοήθεια. |
version |
Εμφανίζει την έκδοση. |
serve, migrate, call |
Λειτουργία διακομιστή και μετάβαση σε PostgreSQL: δείτε Λειτουργία χωρίς γραφικό περιβάλλον (διακομιστής). |
Κάθε εντολή δέχεται την επιλογή --help για την εμφάνιση της λεπτομερούς βοήθειάς της.
create — Δημιουργία βάσης δεδομένων
Δημιουργεί ένα νέο αρχείο βάσης δεδομένων με προαιρετικά μεταδεδομένα.
./blunderdb create --db <path> [--user <name>] [--description <text>] [--force]
Επιλογές:
--db— Διαδρομή του αρχείου βάσης δεδομένων προς δημιουργία (υποχρεωτικό).--user— Όνομα του κατόχου της βάσης.--description— Περιγραφή της βάσης.--force— Αντικατάσταση του αρχείου αν υπάρχει ήδη.--format— Μορφή εξόδου:text(προεπιλογή) ήjson(διαδρομή, έκδοση, χρήστης, περιγραφή, ημερομηνία δημιουργίας).
Η επέκταση .db προστίθεται αυτόματα αν λείπει. Οι γονικοί κατάλογοι δημιουργούνται όταν χρειάζεται.
Παράδειγμα:
./blunderdb create --db mes_matchs.db --user "Jean" --description "Matchs de tournoi 2025"
import — Εισαγωγή δεδομένων
Εισάγει αρχεία αγώνων ή θέσεων στη βάση δεδομένων.
./blunderdb import --db <path> --type <type> [options]
Επιλογές:
--db— Διαδρομή της βάσης δεδομένων (υποχρεωτικό).--type— Τύπος εισαγωγής:match,positionήbatch(υποχρεωτικό).--file— Αρχείο προς εισαγωγή (γιαmatchκαιposition).--dir— Κατάλογος προς εισαγωγή (γιαbatch).--recursive— Αναδρομική σάρωση των υποκαταλόγων (προεπιλογή: ναι).--watch— Με--type batch: δεν σταματά, και εισάγει κάθε αρχείο αγώνα μόλις εμφανιστεί στο--dir(Ctrl-C για διακοπή).--watch-every— Πόσο συχνά κοιτάζει το--watch(προεπιλογή: 10s, κατώτατο 2s).--format— Μορφή εξόδου:text(προεπιλογή) ήjson.--fail-on-error— Αποτυγχάνει αν έστω ένα στοιχείο (positionήbatch) δεν εισήχθη, ακόμη κι αν άλλα πέτυχαν.
Ο κωδικός επιστροφής υπακούει σε τέσσερις κανόνες:
τίποτα δεν αναγνωρίστηκε — κάθε αρχείο απέτυχε —: σφάλμα, είτε δοθεί το
--fail-on-errorείτε όχι·μόνο διπλότυπα — κάθε αρχείο υπήρχε ήδη στη βάση —: επιτυχία. Ένας κατάλογος που ξανατρέχει χωρίς νέο αρχείο, η συνηθισμένη νύχτα ενός σεναρίου, βγαίνει με 0 και μόνο το
duplicatesμη μηδενικό·μερική αποτυχία (ορισμένα στοιχεία εισήχθησαν, άλλα απορρίφθηκαν): σφάλμα μόνο αν δοθεί το
--fail-on-error·τουλάχιστον ένα νέο στοιχείο εισήχθη, χωρίς
--fail-on-error: επιτυχία, με τα απορριφθέντα αρχεία να παρατίθενται στον πίνακα.
Παρακολούθηση φακέλου
Το --watch μετατρέπει την εισαγωγή καταλόγου σε παρακολούθηση: η εντολή δεν επιστρέφει και εισάγει κάθε αρχείο αγώνα που εμφανίζεται στον φάκελο. Είναι η μορφή χωρίς διεπαφή του παρακολουθούμενου φακέλου της εφαρμογής.
# 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
Εισάγονται μόνο τα αρχεία που εμφανίζονται: ό,τι περιέχει ο φάκελος κατά την εκκίνηση καταγράφεται ως γνωστό και αφήνεται ήσυχο — το να στρέψεις μια παρακολούθηση σε τέσσερα χρόνια αγώνων δεν πρέπει να τους εισαγάγει όλους. Οι δύο παραπάνω εντολές συνδυάζονται λοιπόν ακριβώς όπως θα ήλπιζε κανείς.
Ένα αρχείο εισάγεται μόνο αφού σταθεροποιηθεί το μέγεθός του, δηλαδή αφού το δούμε δύο φορές αμετάβλητο: ένας αγώνας που γράφει ένα άλλο πρόγραμμα μεγαλώνει από τη μια ματιά στην άλλη, και το να τον εισαγάγεις μισογραμμένο θα έδινε ένα συντακτικό σφάλμα με το οποίο κανείς δεν μπορεί να κάνει τίποτα. Ο φάκελος δεν διατρέχεται αναδρομικά. Ένα δικτυακό κοινόχρηστο που έγινε μη αναγνώσιμο δεν σταματά την παρακολούθηση, και το περιεχόμενό του δεν περνά για νέο όταν επιστρέψει.
Το Ctrl-C σταματά ανάμεσα σε δύο αρχεία, ποτέ στη μέση ενός: το αρχείο που εισάγεται ολοκληρώνεται και η αναφορά του εμφανίζεται πριν επιστρέψει η εντολή.
Εισαγωγή αγώνα
Υποστηριζόμενες μορφές: eXtreme Gammon (.xg, .xgp), GNUbg (.sgf), Jellyfish (.mat, .txt), BGBlitz (.bgf) και 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 δίνει τα ίδια πεδία σε ένα μόνο έγγραφο:
{
"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
}
Εισαγωγή θέσεων
Εισάγει θέσεις από αρχείο κειμένου, μία θέση JSON ανά γραμμή. Είναι ακριβώς αυτό που γράφει η export --type positions: οι δύο εντολές αντιστοιχούν η μία στην άλλη, μια εξαγωγή επανεισάγεται ως έχει, χωρίς καμία τροποποίηση.
./blunderdb import --db base.db --type position --file positions.txt
# Successfully imported 4 positions
Μια γραμμή, όπως την παράγει η export — το ταμπλό καταλαμβάνει το μεγαλύτερο μέρος της, είκοσι έξι σημεία ακολουθούμενα από τα βγαλμένα πούλια:
{"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}
Η ανάλυση και τα σχόλια δεν ταξιδεύουν με αυτή τη μορφή: μεταφέρει τη θέση, τίποτα άλλο. Για να μετακινήσετε ολόκληρη βιβλιοθήκη, χρειάζεται η export --type database.
Μαζική εισαγωγή
Εισάγει όλα τα αρχεία αγώνων ενός καταλόγου σε μία μόνο ενέργεια. Είναι η πιο αποδοτική μέθοδος για την εισαγωγή μεγάλου αριθμού αγώνων.
./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
Ένας συνοπτικός πίνακας δείχνει για κάθε αρχείο αν η εισαγωγή πέτυχε (✓), απέτυχε (✗) ή ήταν διπλότυπο (⊘). Ένα διπλότυπο δεν μετράει ως αποτυχία, και μια δέσμη που δεν περιέχει παρά διπλότυπα είναι επιτυχία (βλ. τους κανόνες παραπάνω).
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 δίνει το ίδιο πράγμα, αξιοποιήσιμο από σενάριο: ένα αντικείμενο ανά αρχείο στο files, και έπειτα τα σύνολα. Μια ήσυχη νύχτα αφήνει μόνο το duplicates μη μηδενικό και το failed στο μηδέν, και τον κωδικό επιστροφής στο 0· μόνο μια δέσμη όπου τίποτα δεν αναγνωρίστηκε βγαίνει με σφάλμα.
{
"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 — Εξαγωγή δεδομένων
Εξάγει το περιεχόμενο της βάσης σε αρχεία.
./blunderdb export --db <path> --type <type> --file <output> [options]
Επιλογές:
--db— Βάση προέλευσης (υποχρεωτικό).--type— Τύπος εξαγωγής:database,positions,matchesήmat(εξαγωγή ενός ή περισσότερων αγώνων σε μεταγραφή Jellyfish.mat) (υποχρεωτικό).--file— Αρχείο εξόδου (υποχρεωτικό, εκτός από το--type matπου χρησιμοποιείται με το--dir).--dir— Κατάλογος εξόδου για την ομαδική εξαγωγή.mat(πολλοί αγώνες, ένα αρχείο ανά αγώνα· χωρίς--match-ids, εξάγονται όλοι οι αγώνες).--analysis— Συμπερίληψη των αναλύσεων (προεπιλογή: ναι).--comments— Συμπερίληψη των σχολίων (προεπιλογή: ναι).--filters— Συμπερίληψη της βιβλιοθήκης φίλτρων (προεπιλογή: ναι).--played-moves— Συμπερίληψη των παιγμένων κινήσεων (προεπιλογή: ναι).--matches— Συμπερίληψη των αγώνων (προεπιλογή: ναι).--collections— Συμπερίληψη των συλλογών (προεπιλογή: όχι).--collection-ids— IDs συλλογών προς εξαγωγή (χωρισμένα με κόμματα).--match-ids— IDs αγώνων προς εξαγωγή (χωρισμένα με κόμματα, κενό = όλα).--tournament-ids— IDs τουρνουά προς εξαγωγή (χωρισμένα με κόμματα).--password— Τυλίγει το αποτέλεσμα σε κρυπτογραφημένο κοντέινερ (.dbx).--watermark— Γράφει μια υπογεγραμμένη δήλωση προέλευσης στο εξαγόμενο αρχείο (βλ. Διανομή μιας βάσης: προέλευση και κωδικός πρόσβασης).--watermark-note— Ελεύθερο κείμενο συνδεδεμένο με το υδατογράφημα (όροι χρήσης, επικοινωνία)· χρησιμοποιείται μαζί με το--watermark.--format— Μορφή εξόδου:text(προεπιλογή) ήjson(ένα έγγραφο που συνοψίζει την εξαγωγή: διαδρομή, μέγεθος σε bytes, πλήθη).
Παραδείγματα:
./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
Ένα υδατογράφημα υπογράφεται με την τοπική ταυτότητα εκδότη (βλ. την εντολή identity παρακάτω): είναι απαραχάρακτο, αλλά όχι ανεξάλειπτο — το αρχείο παραμένει μια συνηθισμένη βάση SQLite. Δεν προστατεύει τίποτα, δηλώνει μόνο από πού προέρχεται το αρχείο. Ένας κωδικός προστατεύει τη μεταφορά του αρχείου (το ξεχασμένο αντίγραφο, το συνημμένο που στάλθηκε κατά λάθος), όχι την ίδια τη βάση: όποιος έλαβε τον κωδικό μπορεί να την ανοίξει. Το blunderDB δεν καταγράφει ποτέ τίποτα στην πλευρά του παραλήπτη (κανένα μητρώο, κανένα ημερολόγιο) — βλ. ADR-0007.
identity — Ταυτότητα εκδότη
Εμφανίζει ή μετακινεί την ταυτότητα εκδότη σας: το κλειδί Ed25519 που υπογράφει κάθε υδατογράφημα. Δημιουργείται από μόνη της με το πρώτο υδατογράφημα που τίθεται· δεν υπάρχει τίποτα να ρυθμίσετε. Ανήκει σε ένα πρόσωπο, όχι σε μια βάση δεδομένων: ό,τι σημαίνετε φέρει ένα και μόνο δημόσιο αποτύπωμα.
./blunderdb identity
./blunderdb identity --name "Jean Dupont"
./blunderdb identity --export jean.bdbid --passphrase pw
./blunderdb identity --import jean.bdbid --passphrase pw
Επιλογές:
--name— Αλλάζει το εμφανιζόμενο όνομα της ταυτότητας.--export— Εξάγει την ταυτότητα σε αρχείο.bdbid.--import— Εισάγει μια ταυτότητα από αρχείο.bdbid.--passphrase— Προαιρετική φράση πρόσβασης που προστατεύει το εξαγόμενο/εισαγόμενο αρχείο (η τοπική ταυτότητα παραμένει σκόπιμα απροστάτευτη).--format— Μορφή εξόδου:text(προεπιλογή) ήjson(όνομα, αποτύπωμα, διαδρομή αποθήκευσης).
Το εξαγόμενο αρχείο επιτρέπει σε όποιον το κατέχει να υπογράφει στο όνομά σας — μην το μοιράζεστε. Η μετονομασία αλλάζει μόνο μια ετικέτα: τα ήδη σημασμένα αρχεία διατηρούν το όνομα με το οποίο σφραγίστηκαν και εξακολουθούν να επαληθεύονται.
open — Άνοιγμα προστατευμένου αρχείου
Μετατρέπει ένα αρχείο προστατευμένο με κωδικό (.dbx) σε συνηθισμένη βάση. Ο κωδικός ζητείται μία μόνο φορά· έπειτα πρόκειται για κανονικό αρχείο.
./blunderdb open --db cours.dbx --password secret
./blunderdb open --db cours.dbx --password secret --file ./mon-cours.db
Επιλογές:
--db— Το αρχείο.dbxπρος άνοιγμα (υποχρεωτικό).--password— Ο κωδικός του κοντέινερ (υποχρεωτικό).--file— Διαδρομή εξόδου για τη συνηθισμένη βάση (προεπιλογή: ίδιο όνομα, κατάληξη.db).
Τι προστατεύει ο κωδικός: τη μεταφορά του αρχείου — το αντίγραφο που ξεχάστηκε σε έναν φάκελο λήψεων, το συνημμένο που στάλθηκε κατά λάθος. Όχι τη βάση: όποιος έλαβε τον κωδικό μπορεί να την ανοίξει. Η κεφαλίδα του κοντέινερ είναι σε καθαρό κείμενο, ώστε το blunderdb info να διαβάζει την προέλευση ενός προστατευμένου αρχείου χωρίς τον κωδικό του.
search — Αναζήτηση θέσεων
Αναζητά θέσεις στη βάση σύμφωνα με συνδυάσιμα κριτήρια.
./blunderdb search --db <path> [options]
Κύριες επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--format— Μορφή εξόδου:table,jsonήxgid(προεπιλογή:table).--limit— Μέγιστος αριθμός αποτελεσμάτων (0 = απεριόριστα).--offset— Παράβλεψη των n πρώτων αποτελεσμάτων πριν αρχίσει η μέτρηση· μαζί με το--limit, αυτό είναι η σελιδοποίηση.--export— Εξαγωγή των αποτελεσμάτων σε μια νέα βάση.--query-help— Εμφανίζει τη λίστα των διακριτικών που κατανοεί η--query, και σταματά εκεί. Καμία βάση δεν ανοίγει: η--dbείναι περιττή.
Διαθέσιμα φίλτρα:
--decision— Τύπος απόφασης:checkerήcube.--dice— Ζαριά. Το5,3αναζητά τις θέσεις όπου ταιριάζουν και τα δύο ζάρια (ανεξαρτήτως σειράς). Το5αναζητά τις θέσεις όπου ένα 5 εμφανίζεται σε ένα από τα δύο ζάρια (η τιμή του δεύτερου ζαριού αγνοείται). Συνεπάγεται--decision checkerαν δεν δοθεί καμία τιμή για το--decision.--pip-min/--pip-max— Εύρος διαφοράς του μετρητή πόντων (pip count).--winrate-min/--winrate-max— Εύρος ποσοστού νίκης (%).--cube— Τιμή του κύβου.--score1/--score2— Σκορ των παικτών.--match-length— Μήκος του αγώνα.--error-min— Κατώφλι πάνω σε αυτό που κοστίζει ένα σφάλμα στη θέση: η διαφορά ανάμεσα στην καλύτερη και τη δεύτερη κίνηση, ή το μεγαλύτερο από τα τρία σφάλματα κύβου. Σε πόντους ισοδυναμίας — το--error-min 0.1κρατά τις θέσεις όπου ένα λάθος κοστίζει τουλάχιστον ένα δέκατο του πόντου. Δεν λέει τίποτα για το τι παίχτηκε εκεί.--move-error-min/--move-error-max— Κατώφλι πάνω στο σφάλμα της κίνησης που πράγματι παίχτηκε από τον παίκτη 1. Σε χιλιοστά ισοδυναμίας (millipoints):--move-error-min 50, δηλαδή ένα εικοστό του πόντου. Είναι το διακριτικόEτης γραμματικής αναζήτησης, γραμμένο ως έχει.--has-analysis— Μόνο οι θέσεις με ανάλυση.--off1-min/--off2-min— Ελάχιστος αριθμός πουλιών εκτός (παίκτης 1/2).--match-ids— Φιλτράρισμα κατά IDs αγώνων (χωρισμένα με κόμματα).--tournament-ids— Φιλτράρισμα κατά IDs τουρνουά (χωρισμένα με κόμματα).--position-ids— Φιλτράρισμα κατά IDs θέσεων: εύρος2,7(θέσεις 2 έως 7) ή ρητή λίστα χωρισμένη με ερωτηματικά5;10;15.--individual— Μόνο οι θέσεις που εισήχθησαν μεμονωμένα, δηλαδή αυτές που προσθέσατε εσείς και όχι όσες έφερε μια εισαγωγή αγώνα.--flagged— Μόνο οι θέσεις που έχουν σημανθεί (flag) για μελέτη στο λογισμικό προέλευσης (σημάνσεις eXtreme Gammon). Δεν ισχύει αναδρομικά: οι αγώνες που έχουν ήδη εισαχθεί πρέπει να εισαχθούν ξανά για να δώσουν τις σημάνσεις τους.--has-comment— Μόνο οι θέσεις που φέρουν σχόλιο. Η προέλευση δεν διακρίνεται: μια σημείωση γραμμένη με το χέρι και ένα σχόλιο που ήρθε με την εισαγωγή αγώνα μετρούν και τα δύο. Τα σχόλια αγώνα ή τουρνουά δεν λαμβάνονται υπόψη.--no-comment— Μόνο οι θέσεις χωρίς σχόλιο. Αμοιβαία αποκλειόμενο με το--has-comment.
Προειδοποίηση
Τα --error-min και --move-error-min δεν μετρούν το ίδιο πράγμα και δεν παίρνουν την ίδια μονάδα: ο συντελεστής είναι χίλια. Το πρώτο δίνεται σε πόντους ισοδυναμίας (0.1), τα δύο άλλα σε χιλιοστά (100) — ένας πόντος αξίζει 1000 χιλιοστά. Το --move-error-min είναι που απαντά στο «πού έσφαλα»· το --error-min απαντά στο «ποιες θέσεις ήταν λεπτές».
Τι τυπώνει η search:
Η --format table (η προεπιλογή) δίνει μία γραμμή ανά θέση: το αναγνωριστικό, το σκορ, την τιμή του κύβου, τον τύπο της απόφασης, τη ζαριά, την καλύτερη απόφαση και την ισοδυναμία της. Οι δύο τελευταίες στήλες μένουν κενές για θέση χωρίς ανάλυση.
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 δίνει έναν πίνακα των ίδιων θέσεων. Τα πεδία id, score, cube, decision_type (checker ή cube) και dice υπάρχουν πάντα· τα best_move, equity και xgid εμφανίζονται μόνο αν η θέση φέρει ανάλυση που τα συμπληρώνει. Η γραμμή Found n position(s) εξακολουθεί να τυπώνεται πριν από τον πίνακα: ένα σενάριο που περιμένει μόνο JSON πρέπει να παραλείψει την πρώτη γραμμή, ή να περάσει από την --export.
[
{
"id": 5266,
"score": [
5,
4
],
"cube": 1,
"decision_type": "checker",
"dice": [
4,
3
],
"best_move": "10/3",
"equity": 0.565
}
]
Η --format xgid τυπώνει ένα XGID ανά γραμμή, και τίποτα άλλο. Τυπώνει μόνο τις θέσεις των οποίων η αποθηκευμένη ανάλυση φέρει XGID: μια θέση επικολλημένη στην εφαρμογή από μια εξαγωγή κειμένου, ή ένα αρχείο BGF που μεταφέρει ένα. Οι θέσεις που έρχονται με την εισαγωγή αγώνα XG, GNUbg ή Jellyfish δεν φέρουν, και τότε η έξοδος είναι κενή. Η υποεντολή collection show, αντιθέτως, αναπαράγει το XGID από το ταμπλό.
Η γλώσσα ερωτημάτων:
Οι παραπάνω επιλογές καλύπτουν μόνο ένα μέρος των φίλτρων. Η --query δίνει πρόσβαση στη γλώσσα ερωτημάτων της εφαρμογής — αυτή της γραμμής εντολών — και επομένως σε όλα τα φίλτρα που δεν σχεδιάζονται στο ταμπλό: μοτίβο κίνησης, κείμενο σχολίου, παίκτης, ημερομηνία, ισοδυναμία, εξαιρούμενα ζάρια, ζώνες και blots.
Η γραμματική είναι γραμμένη σε ένα μόνο σημείο, Φίλτρα αναζήτησης. Ο πίνακάς της δίνει κάθε διακριτικό, τη μορφή του, και την επιλογή της search που του αντιστοιχεί όταν υπάρχει. Η σελίδα αυτή δεν την επαναλαμβάνει.
./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'
Η κατάταξη των γειτονικών θέσεων μιας θέσης περνά από την ίδια γραμματική: --query 's like42', μόνη της ή ακολουθούμενη από άλλα διακριτικά για να περιοριστεί το σύνολο που κατατάσσεται.
Η --query-help υπενθυμίζει τη λίστα χωρίς να ανοίξει βάση:
$ ./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 αντικαθιστά τις επιλογές φιλτραρίσματος αντί να προστίθεται σε αυτές: ο συνδυασμός τους απορρίπτεται, με αναφορά της επίμαχης επιλογής. Οι επιλογές που λένε πού θα γίνει η αναζήτηση και πώς θα εμφανιστεί — --db, --format, --limit, --offset, --export — παραμένουν έγκυρες.
Ένα διακριτικό που δεν αναγνωρίζεται κάνει την εντολή να αποτύχει, αντί να περιορίσει σιωπηλά την αναζήτηση. Δύο περιορισμοί προκύπτουν από την απουσία ταμπλό στη γραμμή εντολών: το μοτίβο των πουλιών δεν πληκτρολογείται, και τα πέντε διακριτικά που διαβάζουν το ταμπλό — cube, score, d, D/D1 και x — συγκρίνονται εδώ με ένα κενό ταμπλό. Μια αναζήτηση που χρειάζεται κάποιο από αυτά γράφεται εξ ολοκλήρου με επιλογές, αφού η --query δεν συνδυάζεται μαζί τους — για παράδειγμα, οι αποφάσεις κύβου με καθυστέρηση 30 pips και σφάλμα τουλάχιστον 50 χιλιοστών:
./blunderdb search --db base.db --decision cube --pip-min 30 --move-error-min 50
Παραδείγματα:
./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 — Εμφάνιση περιεχομένου
Εμφανίζει το περιεχόμενο της βάσης δεδομένων.
./blunderdb list --db <path> --type <type> [--limit <n>] [--offset <n>]
Τύποι:
matches— Λίστα των εισαγμένων αγώνων.tournaments— Λίστα των τουρνουά.positions— Λίστα των θέσεων (10 από προεπιλογή· το--offset <n>παραλείπει τις πρώτες n). Διαβάζεται μόνο το παράθυρο που εμφανίζεται, όποιο κι αν είναι το μέγεθος της βάσης. Με--format csvγίνεται εξαγωγή σε πίνακα: μία γραμμή ανά θέση, με το XGID, τη φάση, το σκορ, τον κύβο, τα pips και τις παράγωγες στήλες ανάλυσης.imports— Οι καταγεγραμμένες εισαγωγές, από την πιο πρόσφατη στην παλαιότερη: αναγνωριστικό, ημερομηνία, μορφή, πηγή, αγώνες που εισήχθησαν / παραλείφθηκαν / εμπλουτίστηκαν, μη αναγνώσιμα αρχεία και νέες θέσεις. Με--batch <id>εμφανίζεται η πλήρης αναφορά μιας εισαγωγής: επισημασμένες θέσεις, θέσεις χωρίς ανάλυση, PR αυτής της παρτίδας και οι πέντε χειρότερες αποφάσεις της (βλ. Η αναφορά εισαγωγής).stats— Αναφορά στατιστικών επιδόσεων: PR / Snowie ER / MWC (συνολικό, πούλια, κύβος), κυλιόμενο PR στις τελευταίες N αποφάσεις, top blunders, κατανομή ανά ενέργεια κύβου και ιστόγραμμα των μεγεθών σφάλματος.players— Συγκριτικός πίνακας, μία γραμμή ανά παίκτη της βάσης: αγώνες, νίκες/ήττες, μετρημένες αποφάσεις, PR συνολικό / πούλια / κύβος, Snowie ER, λάθη, σοβαρά λάθη και τύχη. Είναι το αντίστοιχο από τη γραμμή εντολών της καρτέλας Παίκτες του πίνακα Στατιστικών.moves— Πινακοποιημένη εξαγωγή των καταγεγραμμένων κινήσεων, μία ανά γραμμή, με τον αγώνα στον οποίο ανήκουν επαναλαμβανόμενο σε κάθε γραμμή: αναγνωριστικά, ημερομηνία, παίκτες, μήκος, αριθμός και τύπος κίνησης, θέση, ζάρια, κίνηση που παίχτηκε, ενέργεια κύβου, τύχη. Απαιτείται--format csv.analyses— Πινακοποιημένη εξαγωγή των αποθηκευμένων αναλύσεων, μία ανά γραμμή: μηχανή, βάθος, καλύτερη κίνηση και η ισοδυναμία της, σφάλμα της κίνησης που παίχτηκε, καλύτερη ενέργεια κύβου και το σφάλμα της, τα έξι ποσοστά νίκης. Απαιτείται--format csv.tags— Το λεξιλόγιο ετικετών της βάσης: κάθε#λέξηγραμμένη σε σχόλιο, με το πλήθος των θέσεων που τη φέρουν, με πρώτη τη συχνότερη. Σε μια βάση χωρίς καμία ετικέτα, εμφανίζει το προτεινόμενο λεξιλόγιο αντί για κενή λίστα (δείτε Οι ετικέτες). Δέχεται--format jsonκαι--format csv.
Πινακοποιημένες εξαγωγές
Τρεις τύποι — positions, moves και analyses — εξάγονται σε CSV για ένα notebook, ένα υπολογιστικό φύλλο ή ένα σενάριο:
./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 ισχύει μόνο αν το δώσετε. Η προεπιλογή του (10) υπάρχει ώστε ένα list στο τερματικό να μην κυλήσει όλη τη βάση· μια εξαγωγή όμως πάει σε αρχείο που διαβάζει ένα πρόγραμμα, και το να κοπεί σιωπηλά στις δέκα γραμμές θα ήταν παγίδα που κανείς δεν προσέχει μέχρι να βγουν λάθος οι αριθμοί.
Οι στήλες είναι συμβόλαιο. Ένα notebook ή ένα σενάριο γραμμένο πάνω σε αυτά τα ονόματα πρέπει να συνεχίσει να λειτουργεί: οι στήλες προστίθενται στο τέλος, δεν μετονομάζονται ποτέ και δεν αναδιατάσσονται. Κάθε ισοδυναμία είναι σε ακέραια millipoints, γιατί έτσι αποθηκεύεται και γιατί ένας δεκαδικός σε CSV προσκαλεί μια locale να τον ξαναμορφοποιήσει.
Το Parquet δεν προσφέρεται, και αυτό είναι μετρημένο και όχι δογματικό: μια στηλοκεντρική βιβλιοθήκη ζυγίζει αρκετά megabyte σε ένα εκτελέσιμο του οποίου το μέγεθος παρακολουθείται, ενώ όλα όσα εξυπηρετεί αυτή η εξαγωγή διαβάζουν CSV σε μία γραμμή (pd.read_csv, polars.read_csv, read.csv, ένα υπολογιστικό φύλλο). Το Parquet αξίζει σε δεκάδες εκατομμύρια γραμμές· μια δεκαετής βιβλιοθήκη τάβλι έχει εκατό χιλιάδες. Αν κάποια μέρα η διαφορά μετρηθεί σε πραγματική βάση, αυτή η μέτρηση θα ξανανοίξει το ζήτημα.
Ένα παράδειγμα notebook Jupyter συνοδεύει αυτές τις εξαγωγές (notebooks/blunderdb-analyse.ipynb στο αποθετήριο): PR στον χρόνο, κατανομή των μεγεθών σφάλματος, οι δέκα χειρότερες αποφάσεις με το XGID τους. Δεν χρησιμοποιεί τίποτα άλλο από αυτά τα τρία αρχεία CSV, και εκτελείται κάθε νύχτα στη συνεχή ενσωμάτωση — ένα notebook που κανείς δεν τρέχει είναι ένα notebook που έπαψε να λειτουργεί χωρίς να το ξέρει κανείς.
Επιλογές (μόνο τύπος stats):
--metric— Εμφανιζόμενη μετρική:prήmwc(προεπιλογή:pr).--player— Περιορισμός στον υποδεικνυόμενο παίκτη.--tournament— Περιορισμός σε ένα ή περισσότερα IDs τουρνουά (χωρισμένα με κόμματα).--from— Ημερομηνία έναρξης (ΕΕΕΕ-ΜΜ-ΗΗ).--to— Ημερομηνία λήξης (ΕΕΕΕ-ΜΜ-ΗΗ).--decision-type— Τύπος απόφασης:all,checkerήcube(προεπιλογή:all).--top-blunders— Αριθμός των χειρότερων λαθών που εμφανίζονται (προεπιλογή: 10).--format— Μορφή εξόδου:textήjson(προεπιλογή:text).
Επιλογές (μόνο τύπος imports):
--batch— Αναγνωριστικό μιας παρτίδας: εμφανίζει την πλήρη αναφορά της αντί για τη λίστα.--queue— Με--batch: η ουρά μελέτης της παρτίδας εισαγωγής αντί για την αναφορά της — οι θέσεις που αξίζουν δεύτερη ματιά, με τη σειρά που πρέπει να τις δεις (δείτε Η ουρά μελέτης). Πρώτα οι αποφάσεις που κόστισαν κάτι, μετά οι θέσεις που ήταν σημειωμένες στο αρχικό πρόγραμμα, μετά οι οριακές αποφάσεις κύβου· μια θέση εμφανίζεται μόνο μία φορά.--format— Μορφή εξόδου:textήjson(προεπιλογή:text).
Το μετρημένο μισό της αναφοράς υπολογίζεται ξανά σε κάθε κλήση: μια παρτίδα της οποίας οι θέσεις έχουν έκτοτε αναλυθεί επιστρέφει τα σημερινά νούμερα, όχι εκείνα της ημέρας της εισαγωγής.
Επιλογές (μόνο τύπος players):
--from/--to— Όρια ημερομηνιών (ΕΕΕΕ-ΜΜ-ΗΗ), για παράδειγμα οι ημέρες μιας διοργάνωσης.--tournament— Περιορισμός σε ένα ή περισσότερα IDs τουρνουά.--format— Μορφή εξόδου:text,jsonήcsv(προεπιλογή:text).
Τα --player και --decision-type δεν ισχύουν για αυτόν τον τύπο: ο πίνακας αφορά όλους τους παίκτες και ήδη διαχωρίζει πούλια και κύβο σε ξεχωριστές στήλες.
Σημείωση
Μια παύλα «—» (κενό πεδίο σε CSV) σημαίνει τιμή που δεν μετρήθηκε ποτέ, να μη συγχέεται με το μηδέν. Αυτό ισχύει για την τύχη σε κάθε αγώνα που εισήχθη πριν από την έκδοση 2.15.0 του σχήματος, καθώς και για τις μορφές που δεν τη μεταφέρουν (BGF, Jellyfish .mat): εισαγάγετε ξανά τα αρχεία προέλευσης για να την αποκτήσετε. Η στήλη luck_rolls δείχνει σε πόσες ζαριές αναφέρεται ο μέσος όρος.
Κάθε τύπος τυπώνει ένα μπλοκ ανά στοιχείο, με το σύνολο που βρέθηκε στην αρχή. Η τελευταία γραμμή λέει ποιο παράθυρο εμφανίζεται, περιορισμένο από το --limit (προεπιλογή 10 για τις θέσεις) και μετατοπισμένο από το --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)
Παραδείγματα:
# 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 — Εμφάνιση αγώνα
Εμφανίζει τις θέσεις και τις αναλύσεις ενός εισαγμένου αγώνα.
./blunderdb match --db <path> --id <id> [--format <format>] [--output <file>]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--id— ID του αγώνα προς εμφάνιση (υποχρεωτικό).--format— Μορφή εξόδου:json,textήsummary(προεπιλογή:json).--output— Αρχείο εξόδου (προεπιλογή: τυπική έξοδος).
Παραδείγματα:
./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 — Διαχείριση συλλογών
Διαχειρίζεται τις συλλογές, αυτά τα σύνολα θέσεων επιλεγμένων με το χέρι στον πίνακα Συλλογές της γραφικής διεπαφής. Κάθε υποεντολή δέχεται --db· οι list και show δέχονται --format text (προεπιλογή), json ή csv, όπως η list.
./blunderdb collection <subcommand> [options]
Υποεντολές:
list— Λίστα των συλλογών: id, όνομα, αριθμός θέσεων, περιγραφή.show --id <id>— Θέσεις μιας συλλογής: id, index (ο αριθμός με αρίθμηση από το 1 που εμφανίζεται στη γραμμή κατάστασης της γραφικής διεπαφής), σκορ, τύπος απόφασης και XGID.create --name <nom> [--description <texte>]— Δημιουργεί μια κενή συλλογή.filter --id <id> --query <ερώτημα>— Κάνει μια συλλογή ζωντανή: το περιεχόμενό της γίνεται το αποτέλεσμα μιας αναζήτησης, που επαναϋπολογίζεται κάθε φορά που ανοίγει. Το ερώτημα γράφεται στη γραμματική αναζήτησης της εφαρμογής (βλέπε Φίλτρα αναζήτησης). Το--clearτην επαναφέρει σε χειροποίητη λίστα, διατηρώντας τις θέσεις που περιείχε.rename --id <id> --name <nom> [--description <texte>]— Μετονομάζει μια συλλογή (η περιγραφή διατηρείται αν δεν δοθεί).delete --id <id> [--confirm]— Διαγράφει μια συλλογή· οι θέσεις της παραμένουν στη βάση.export --id <id[,id…]> --out <fichier.db> [--analysis=false] [--comments=false] [--watermark <texte>] [--watermark-note <texte>]— Εξάγει μία ή περισσότερες συλλογές σε νέο αρχείο βάσης, μέσω της ίδιας κλήσης όπως το παράθυρο εξαγωγής της γραφικής διεπαφής (βλ. την εντολήexportγια το υδατογράφημα).
Το XGID που εμφανίζεται από την show είναι αυτό που καταγράφηκε με την ανάλυση της θέσης όταν υπάρχει (εισαγωγές BGF και XGP)· διαφορετικά παράγεται από το ταμπλό ακριβώς όπως κάνει η Αντιγραφή της θέσης στη γραφική διεπαφή — το μήκος του αγώνα είναι τότε το μεγαλύτερο από τα δύο εναπομείναντα σκορ, καθώς μια αποθηκευμένη θέση δεν διατηρεί το πραγματικό.
Παραδείγματα:
./blunderdb collection list --db base.db
# Found 2 collection(s):
#
# ID Name Positions Description
# -- ---- --------- -----------
# 1 Ouvertures blitz 0 À revoir
# 2 Videaux ratés 0
Μια βάση χωρίς συλλογή απαντά No collections found in database και τερματίζει παρ” όλα αυτά με κωδικό 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 — Πακέτα επανάληψης με διαστήματα
Εξετάζει και συντηρεί τα πακέτα επανάληψης με διαστήματα (FSRS) του πίνακα Anki της γραφικής διεπαφής. Η επανάληψη μιας κάρτας απαιτεί το ταμπλό και παραμένει στη γραφική διεπαφή· η CLI παραθέτει, μετρά και επανασυγχρονίζει.
./blunderdb anki <subcommand> [options]
Υποεντολές:
decks [--format text|json|csv]— Λίστα των πακέτων: πηγή, αριθμός καρτών, οφειλόμενες κάρτες, νέες κάρτες.stats --deck <id> [--format text|json]— Στατιστικά επανάληψης ενός πακέτου: σύνολο, νέες, σε εκμάθηση, προς επανάληψη, οφειλόμενες τώρα, και οι παράμετροί του FSRS.forecast [--deck <id>] [--days <n>] [--format text|json|csv]— Κάρτες που λήγουν ανά ημερολογιακή ημέρα (UTC) για τις επόμενεςnημέρες (προεπιλογή 30, μέγιστο 365)· η ημέρα 0 απορροφά όλες τις καθυστερημένες κάρτες·--deck 0(προεπιλογή) καλύπτει όλα τα πακέτα.sync --deck <id>— Προσθέτει μια κάρτα για κάθε θέση της πηγής του πακέτου που δεν έχει ακόμη μία· οι υπάρχουσες κάρτες διατηρούν τον προγραμματισμό τους.retention --deck <id> [--format text|json]— η μετρημένη διατήρηση μιας τράπουλας, σε σύγκριση με τον στόχο που επέλεξε ο κάτοχός της.card --id <id> --action suspend|unsuspend|bury|remove [--format text|json]— ενεργεί σε μία κάρτα. Η αναστολή τη βάζει στην άκρη χωρίς να χαθεί το ιστορικό της (δεν εμφανίζεται πια σε συνεδρία)· η ταφή την κρύβει ως την επόμενη μέρα, χωρίς να λέει τίποτα για την αξία της· η αφαίρεση τη διαγράφει από την τράπουλα — η ίδια η θέση μένει στη βιβλιοθήκη, αφού μια τράπουλα δεν είναι παρά μια λίστα μελέτης πάνω της.log [--deck <id>] [--limit <n>] [--format text|json]— το ημερολόγιο επαναλήψεων, το πιο πρόσφατο πρώτο (--deck 0, η προεπιλογή, καλύπτει όλες τις τράπουλες· το--limitείναι 20 από προεπιλογή). Το ημερολόγιο είναι ό,τι πραγματικά δόθηκε στον προγραμματιστή, σε αντίθεση με ό,τι σχεδιάζει σήμερα: το μόνο σημείο όπου φαίνεται μια βαθμολογία που δόθηκε κατά λάθος.
Ένα πακέτο βασισμένο σε συλλογή διαβάζει ξανά τη συλλογή του. Ένα πακέτο βασισμένο σε αναζήτηση διατηρεί την αναζήτηση όπως την κατέγραψε η γραφική διεπαφή (εντολή, ταμπλό και αναγνωριστικά των θέσεων που βρέθηκαν εκείνη τη στιγμή): η γραμματική αναζήτησης ζει στη γραφική διεπαφή, οπότε η CLI επανασυγχρονίζει από τα καταγεγραμμένα αναγνωριστικά και το αναφέρει στην έξοδο σφαλμάτων — ανοίξτε το πακέτο στη γραφική διεπαφή για να επαναλάβετε την ίδια την αναζήτηση.
Παραδείγματα:
./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 — Επαναλαμβανόμενα λάθη
Ομαδοποιεί τα λάθη ενός φίλτρου ανά σχέδιο παιχνιδιού και ανά θέμα, με πρώτο το πιο δαπανηρό: ο πίνακας Επαναλαμβανόμενα λάθη της καρτέλας Errors του πίνακα Stats (βλ. Πίνακας Stats). Τα καθολικά στατιστικά παραμένουν στο list --type stats.
./blunderdb stats recurring --db <fichier> [options]
Επιλογές:
--player <nom>— Μόνο οι αποφάσεις αυτού του παίκτη.--tournament <ids>,--from <AAAA-MM-JJ>,--to <AAAA-MM-JJ>,--decision-type all|checker|cube— Το ίδιο φίλτρο με τοlist --type stats.--limit <n>— Αριθμός ομάδων που εμφανίζονται σε κείμενο (προεπιλογή 20,0για όλες).--format text|json— Το JSON περιέχει κάθε ομάδα με την πλήρη λίστα των θέσεών της.--quiz— Κληρώνει τυχαία θέσεις από εκείνες των τριών πιο δαπανηρών ομάδων (--quiz-size <n>, προεπιλογή 20) και τις εμφανίζει: είναι τα αναγνωριστικά που κρίνουν το κουίζ και τοquiz_grade. Σε JSON, το πεδίοQuiz.--deck <όνομα>— Δημιουργεί μια τράπουλα Anki με αυτό το όνομα, γεμάτη με όλες τις θέσεις των τριών πιο δαπανηρών ομάδων.--group <κατάταξη>— Με το--quizή το--deck: η ομάδα αυτής της κατάταξης (1 για την πιο δαπανηρή) αντί για τις τρεις πρώτες.
Ένα θέμα κίνησης πούλιων είναι gammon, blots, point ή passive· ένα θέμα κύβου είναι offer_missed, offer_premature, answer_wrong_pass ή answer_wrong_take. Τα λάθη που κανένας κανόνας δεν ονομάζει βγαίνουν από την κατάταξη: παρατίθενται χωριστά, μία γραμμή ανά σχέδιο παιχνιδιού (πεδίο Unthemed στο JSON), επειδή η εξήγηση εκφέρεται μόνο από 60 mp και πάνω, πάνω από το όριο Λάθος. Η στήλη COST (PR) είναι το μερίδιο του PR του φίλτρου που αντιπροσωπεύει η ομάδα.
Παραδείγματα:
./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 — Το PR του κουίζ Απόφασης, το PR των αγώνων και η διατήρηση του Anki, ομαδοποιημένα ανά ημερολογιακό παράθυρο, όπως η καρτέλα Εκπαίδευση του πίνακα Stats (βλ. Πίνακας Stats).
./blunderdb stats training --db <fichier> [options]
Επιλογές:
--window week|month— Το ημερολογιακό παράθυρο (προεπιλογήweek).--player <όνομα>,--tournament <ids>,--from <ΕΕΕΕ-ΜΜ-ΗΗ>,--to <ΕΕΕΕ-ΜΜ-ΗΗ>,--decision-type all|checker|cube— Το φίλτρο των αγώνων· τα ημερολόγια του κουίζ και του Anki δεν φέρουν παίκτη.--format text|json— Το JSON περιλαμβάνει και τη λίστα των συνεδριών κουίζ.
Κάθε σειρά διατηρεί το πλήθος των δειγμάτων της: ένα παράθυρο χωρίς αποφάσεις είναι παύλα στο κείμενο και μηδενικό πλήθος στο JSON, ποτέ μηδενική τιμή.
Παραδείγματα:
./blunderdb stats training --db base.db --player "Alice"
./blunderdb stats training --db base.db --window month --format json
cubematrix — Μήτρα του κύβου
Δίνει την ετυμηγορία του κύβου μιας θέσης σε κάθε σκορ ενός αγώνα: για κάθε κελί away × away, αν η θέση διπλασιάζεται και αν γίνεται αποδεκτή. Καθαρός υπολογισμός: καμία βάση δεδομένων δεν ανοίγει, η θέση δίνεται ως XGID ή ως OGID (OpenGammon).
./blunderdb cubematrix [options] '<XGID|OGID>'
Επιλογές:
--format— Μορφή εξόδου:textήjson(προεπιλογή:text).--match-length— Μήκος αγώνα που καλύπτει το πλέγμα, από 1 έως 25 (προεπιλογή: 7).--ply— Βάθος αναζήτησης κάθε κελιού,0ή2(προεπιλογή: 2).--prune-k— Πλήθος υποψήφιων κινήσεων που κρατά το δίκτυο κλαδέματος (προεπιλογή: 12).--jobs— Αναζητήσεις που τρέχουν παράλληλα (προεπιλογή: μία ανά πυρήνα). Το πλέγμα είναι το ίδιο όποια κι αν είναι η τιμή· αλλάζει μόνο ο χρόνος.
Το ίδιο το σκορ της θέσης αγνοείται — το πλέγμα το αντικαθιστά — αλλά ο κύβος της διατηρείται: το ερώτημα είναι σε ποιο σκορ θα γύριζα αυτόν τον κύβο. Το πλέγμα είναι μετά το Crawford από άκρη σε άκρη.
Κάθε κελί είναι δική του αναζήτηση, γιατί η μηχανή λαμβάνει υπόψη το σκορ: μία μόνο αναζήτηση διαβασμένη μέσα από διαφορετικές ισοδυναμίες αγώνα θα ήταν λάθος ακριβώς εκεί που μετράει το σκορ.
Παραδείγματα:
# 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>'
Έξοδος text: ένα πλέγμα του οποίου οι γραμμές είναι οι πόντοι που χρειάζεται ακόμη ο παίκτης στη σειρά και οι στήλες εκείνοι του αντιπάλου, έπειτα το υπόμνημα των συντομογραφιών ND / DT / DP / TG και ο λόγος κάθε κελιού που απορρίφθηκε.
rollout — Rollout μιας θέσης
Παίζει μια θέση πολλές φορές με το gammonNet, για να κρίνει όσα μια αναζήτηση δεν κρίνει: δύο κινήσεις με διαφορά λίγων χιλιοστών ή μια απόφαση κύβου όπου το μοντέλο διστάζει. Με ζάρια παίζονται οι κινήσεις της (οι καλύτερες στο βάθος του rollout, τουλάχιστον 2 ply, ή αυτές που ορίζονται με --move)· χωρίς ζάρια, η απόφαση κύβου (Όχι διπλασιασμός και Διπλασιασμός/Αποδοχή· το Διπλασιασμός/Άρνηση αξίζει ακριβώς +1). Η θέση προέρχεται από ένα XGID ή ένα OGID ή από μια βάση (--db και --id)· χωρίς --store, τίποτα δεν καταγράφεται.
./blunderdb rollout [options] '<XGID|OGID>'
./blunderdb rollout --db <path> --id <position> [--store] [options]
Επιλογές:
--preset— Αρχική ρύθμιση:fast(προεπιλογή: 216 παρτίδες κομμένες στις 7 κινήσεις, διακοπή στο JSD 3 μετά τις 108) ήstandard(1296 παρτίδες κομμένες στις 11, διακοπή στο JSD 3 μετά τις 324). Και οι δύο παίζουν στα 0 ply — το δίκτυο μόνο του, για τις κινήσεις, τον κύβο και τα φύλλα· το--ply 1ή περισσότερο παίζει βαθύτερα, με χρόνο αρκετές φορές μεγαλύτερο. Οι επόμενες επιλογές την αντικαθιστούν μία προς μία.--games,--min-games,--truncation,--jsd,--ply,--candidates— Οι παράμετροι του rollout (το--truncation 0παίζει κάθε παρτίδα ως το τέλος, το--jsd 0δεν σταματά ποτέ πριν το τέλος).--move— Μια κίνηση προς παιχνίδι, με τον συμβολισμό του blunderDB (επαναλαμβανόμενη).--seed— Σπόρος των ζαριών, σταθερός από προεπιλογή: η ίδια εντολή δίνει τους ίδιους αριθμούς.--jobs— Παρτίδες που παίζονται παράλληλα (προεπιλογή: μία ανά πυρήνα)· αλλάζει μόνο ο χρόνος.--format— Μορφή εξόδου:textήjson(προεπιλογή:text).--db,--id— Η βάση και ο αναγνωριστικός αριθμός της θέσης που θα παιχτεί, αντί για ένα XGID.--store— Καταγράφει το ολοκληρωμένο rollout στη θέση, ως δεύτερη ανάλυση με τις δικές της ρυθμίσεις, δίπλα στην εισηγμένη ή υπολογισμένη ανάλυση, την οποία δεν αντικαθιστά ποτέ. Ένα διακοπτόμενο rollout δεν καταγράφεται· από δύο rollouts με τις ίδιες ρυθμίσεις διατηρείται η μεγαλύτερη σειρά, ενώ ένα rollout με άλλες ρυθμίσεις προστίθεται δίπλα.--list— Εμφανίζει τα rollouts που είναι αποθηκευμένα στη θέση, από το πιο πρόσφατο στο παλαιότερο, αντί να εκτελέσει ένα.
Όλοι οι υποψήφιοι παίζουν τα ίδια ζάρια, η τύχη κάθε ρίψης αφαιρείται από το αποτέλεσμα κάθε παρτίδας (μείωση διακύμανσης), οι δύο πρώτες ρίψεις στρωματοποιούνται και μια παρτίδα σταματά εκεί που τη καλύπτει η βάση εξόδου two-sided. Κάθε γραμμή δίνει το equity, το διάστημα 95 % του, τον αριθμό των παρτίδων που παίχτηκαν και το JSD, τη διαφορά από τον καλύτερο σε τυπικές αποκλίσεις της διαφοράς. Ο κύβος παίζεται κατά τη διάρκεια των παρτίδων: η κατάταξη είναι πιο αξιόπιστη από το απόλυτο equity. Το Ctrl-C εμφανίζει όσα έχουν καθιερώσει οι ολοκληρωμένες παρτίδες.
Παραδείγματα:
./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
Υπολογίζει το Effective Pip Count, την πιθανότητα νίκης και την ετυμηγορία κύβου money μιας θέσης εξόδου δοσμένης με XGID ή με OGID (OpenGammon). Καθαρός υπολογισμός: δεν εμπλέκεται κανένα αρχείο βάσης δεδομένων.
./blunderdb epc [options] '<XGID|OGID>'
Επιλογές:
--format— Μορφή εξόδου:textήjson(προεπιλογή:text).--bearoff-ts— Προαιρετική αμφίπλευρη βάση bearoff (.bd) που διευρύνει την ενσωματωμένη TS-06-06 (διαβάζεται και από τη μεταβλητή περιβάλλοντοςBLUNDERDB_TS_PATH). Υπερισχύει η ευρύτερη έγκυρη βάση· ένα άκυρο αρχείο αγνοείται με προειδοποίηση.
Καθεστώτα. Στο εύρος που καλύπτει η αμφίπλευρη βάση, η πιθανότητα νίκης και η ανάλυση κύβου money (cubeless, ND, D/T, D/P, ετυμηγορία) είναι ακριβείς. Εκτός αυτού, η πιθανότητα νίκης εκτιμάται (συνέλιξη των μονόπλευρων κατανομών ζαριών συν μια βαθμονομημένη διόρθωση) και εμφανίζεται με το μετρημένο περιθώριο σφάλματός της· η ετυμηγορία κύβου δεν εκτιμάται ποτέ, σκοπίμως (βλ. ADR-0009).
Παραδείγματα:
# 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
Φτιάχνει και διαχειρίζεται τις βάσεις bearoff. Τίποτα δεν κατεβαίνει και τίποτα δεν είναι ενσωματωμένο: ένας πίνακας υπολογίζεται εδώ και ελέγχεται με το αποτύπωμα που παράγει το gnubg για τον τομέα του. Καμία υποεντολή δεν μιλά σε βάση δεδομένων — ένας πίνακας bearoff είναι αριθμητική για το παιχνίδι, όχι για τις θέσεις κάποιου — οπότε καμία δεν παίρνει --db.
./blunderdb bearoff generate --ts <domain> [options]
./blunderdb bearoff list [options]
./blunderdb bearoff verify <file.bd> [options]
./blunderdb bearoff delete --ts <domain> [options]
Ο τομέας γράφεται όπως στο makebearoff: 6x9 για τον αμφίπλευρο πίνακα με εννέα πούλια ανά παίκτη, os8 για τον μονόπλευρο πίνακα οκτώ σημείων (το σκέτο os ισοδυναμεί με os6).
Οι δύο οικογένειες δεν απαντούν στο ίδιο ερώτημα. Ένας αμφίπλευρος πίνακας διευρύνει τον τομέα όπου η πιθανότητα νίκης και η ετυμηγορία κύβου είναι ακριβείς· ένας μονόπλευρος διευρύνει την απόσταση στην οποία μπορεί να βρίσκεται ένα πούλι χωρίς να σωπάσει το EPC (έως δέκα σημεία).
generate. Δηλώνει το μέγεθος, τη μνήμη και τον εκτιμώμενο χρόνο πριν ξεκινήσει, και μετά δείχνει το ποσοστό και τον μετρημένο υπολειπόμενο χρόνο.
--ts— Αμφίπλευρος τομέας προς υπολογισμό, για παράδειγμα6x9.--os— Μονόπλευρος τομέας προς υπολογισμό, σε αριθμό σημείων: 6 έως 12. Απαιτείται ακριβώς ένα από τα δύο.--cores— Πυρήνες προς χρήση (προεπιλογή: όλοι εκτός από έναν).--data-dir— Πού γράφεται (προεπιλογή: ο φάκελος δεδομένων της εφαρμογής).--quiet— Χωρίς γραμμή προόδου.
Το CTRL-C κάνει παύση. Το σήμα συλλαμβάνεται: η κατάσταση γράφεται δίπλα στον πίνακα και η ίδια εντολή ξανατρέχοντας συνεχίζει από εκεί που σταμάτησε αντί να ξαναϋπολογίσει τα πάντα. Μισή ώρα αριθμητικής αξίζει να καταγραφεί. Το bearoff delete πετάει μια εκκρεμή συνέχιση. Μόνο η αμφίπλευρη σάρωση κάνει παύση· η μονόπλευρη είναι σειριακή και το --cores δεν της χρησιμεύει.
list. Κοστολογεί κάθε τομέα — μέγεθος, μνήμη, χρόνος σε αυτό το μηχάνημα — και λέει ποιοι υπάρχουν ήδη, με την ετυμηγορία τους, και ποιοι έχουν υπολογισμό σε παύση. --format json για σενάριο, --cores για αλλαγή της υπόθεσης της εκτίμησης.
verify. Απαντά verified (τα ίδια byte με την αναφορά), unverified (καλοσχηματισμένος, αλλά δεν υπάρχει καταγεγραμμένο αποτύπωμα για αυτόν τον τομέα) ή corrupt (το αρχείο αντιφάσκει με τον εαυτό του). Τερματίζει με σφάλμα στην τελευταία περίπτωση: αυτή η εντολή φτιάχτηκε για να μπει σε σενάριο.
delete. Αφαιρεί τον πίνακα, την εκκρεμή συνέχιση και τα υπολείμματα ενός νεκρού υπολογισμού. Ένας προεπιλεγμένος τομέας ξαναϋπολογίζεται στην επόμενη εκκίνηση της εφαρμογής· ένας ευρύτερος όχι.
Παραδείγματα:
# 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
Γράφει μια ανάλυση gammonNet για κάθε θέση που δεν έχει καμία — η συμπλήρωση μιας βιβλιοθήκης που δημιουργήθηκε πριν υπάρξει αυτή η λειτουργία (ADR-0013, ADR-0015). Είναι η ίδια λειτουργία με την αυτόματη ενεργοποίηση μετά την εισαγωγή και το κουμπί «Ανάλυση τώρα» της γραφικής διεπαφής, καθώς και με το σημείο πρόσβασης /v1/gammonnet.analyzeMissing του δαίμονα serve για έναν tenant — τρεις διαφορετικές μορφές της ίδιας λειτουργίας, όχι τρεις ξεχωριστές λογικές (βλ. Λειτουργία χωρίς γραφικό περιβάλλον (διακομιστής)).
./blunderdb analyze --db <path> [options]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--ply— Βάθος αναζήτησης (προεπιλογή: 2, η κανονική παράμετρος).--prune-k— Πλάτος κλαδέματος (προεπιλογή: 12, η κανονική παράμετρος).--candidates— Αριθμός υποψήφιων κινήσεων που διατηρούνται ανά απόφαση κίνησης (προεπιλογή: 10).--jobs— Αριθμός θέσεων που αναλύονται παράλληλα (προεπιλογή: ο αριθμός των πυρήνων του μηχανήματος).--match— Περιορίζει τη δέσμη στις θέσεις ενός μόνο αγώνα (0, η προεπιλογή, σημαίνει ολόκληρη τη βιβλιοθήκη).--compare— Δεν γράφει τίποτα: συγκρίνει το gammonNet με τις εισηγμένες αναλύσεις αντί να καλύπτει κενά (βλ. παρακάτω).--limit— Με το--compare, σταματά μετά από αυτόν τον αριθμό θέσεων (0 = όλες).--format— Μορφή εξόδου:text(προεπιλογή, με πρόοδο) ήjson(ένα και μόνο συνοπτικό έγγραφο, τυπωμένο στο τέλος).--rollout— Κάνει rollout στις θέσεις που επιλέγει το--queryαντί να συμπληρώνει κενά (βλ. παρακάτω).--query— Με το--rollout, οι θέσεις που θα παιχτούν, στη γλώσσα ερωτημάτων της αναζήτησης (search --query-help)· κενό, όλες.
Ένας αγώνας που εισήχθη χωρίς ανάλυση αποκτά έτσι PR. Είναι η περίπτωση ενός αγώνα που παίχτηκε διαδικτυακά, ή ενός αρχείου Jellyfish .mat που κανείς δεν πέρασε από το XG. Το blunderDB γνώριζε τις θέσεις και τις κινήσεις που παίχτηκαν, αλλά τίποτα δεν έλεγε τι άξιζαν· μόλις τρέξει η παρτίδα, η κίνηση που όντως παίχτηκε συγκρίνεται με την κατάταξη του gammonNet και η διαφορά τροφοδοτεί το PR και όλους τους άλλους δείκτες. Η κίνηση που παίχτηκε προέρχεται από τον πίνακα κινήσεων του αγώνα, γραμμένο κατά την εισαγωγή, είτε το αρχείο έφερε ανάλυση είτε όχι — ποτέ δεν μαντεύεται.
Μια βάση που αναλύθηκε με παλαιότερη έκδοση δεν χρειάζεται επανεκτίμηση: το repair ξαναϋπολογίζει τις στήλες από ό,τι υπάρχει ήδη και επιστρέφει το PR σε αυτούς τους αγώνες.
Ένας μόνο αγώνας (--match). Με το αναγνωριστικό που εμφανίζει η list --type matches, η δέσμη διατρέχει μόνο τις θέσεις αυτού του αγώνα: ίδιος κανόνας του κενού, ίδιες εγγυήσεις, στενότερη εμβέλεια. Ένας αγώνας που μόλις εισήχθη λαμβάνει τις αναλύσεις του χωρίς να διατρέχεται η υπόλοιπη βιβλιοθήκη, και ένας αγώνας που διορθώθηκε και αναλύθηκε δεύτερη φορά κοστίζει μόνο τις θέσεις που δημιούργησε η διόρθωση, αφού όλες οι άλλες φέρουν ήδη ανάλυση. Η επιλογή δεν συνδυάζεται ούτε με --stale ούτε με --compare, που και οι δύο κοιτούν θέσεις οι οποίες έχουν ήδη ανάλυση: το να ζητηθούν και τα δύο είναι σφάλμα, όχι μια σιωπηλά αγνοημένη εμβέλεια.
Ο παραλληλισμός (--jobs). Οι θέσεις μιας δέσμης είναι ανεξάρτητες — καμία αναζήτηση δεν τροφοδοτεί την επόμενη — οπότε κατανέμονται σε --jobs νήματα εκτέλεσης, καθένα με τον δικό του αξιολογητή. Οι αναλύσεις που γράφονται είναι πανομοιότυπες όποια κι αν είναι η τιμή του --jobs· αλλάζει μόνο ο χρόνος υπολογισμού. Το --jobs 1 αφήνει το μηχάνημα ελεύθερο για άλλες εργασίες. Η ακύρωση δεν επηρεάζεται: το Ctrl-C σταματά τη δέσμη πριν από κάθε νέα θέση, και ό,τι είχε ήδη υπολογιστεί γράφεται.
Ο κανόνας του κενού (ADR-0013). Μια θέση που φέρει ήδη μια ανάλυση — XG, GNUbg, BGBlitz, ή ένα προηγούμενο πέρασμα του gammonNet — δεν αγγίζεται ποτέ, όποια μηχανή κι αν λείπει. Γράφεται μόνο μια θέση χωρίς καμία ανάλυση. Η εντολή μπορεί επομένως να επανεκτελεστεί ανά πάσα στιγμή χωρίς κίνδυνο, και να διακοπεί καθαρά: το Ctrl-C ακυρώνει χωρίς να χαθεί τίποτα από όσα έχουν ήδη γραφτεί, και η επόμενη εκτέλεση συνεχίζει ακριβώς από εκεί που σταμάτησε η προηγούμενη — δεν χρειάζεται κανένα ημερολόγιο, αφού «οι θέσεις χωρίς ανάλυση» επανυπολογίζονται σε κάθε εκκίνηση.
Παράδειγμα:
./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
Rollout σε παρτίδες (--rollout). Κάθε θέση που επιλέγει το --query παίζεται με ένα rollout, η μία μετά την άλλη σε όλους τους πυρήνες, και το rollout καταγράφεται δίπλα στην ανάλυσή της, ποτέ στη θέση της. Η τιμή είναι μια προεπιλογή — fast (216 παιχνίδια κομμένα στο 7) ή standard (1296 παιχνίδια κομμένα στο 11) — ή ελεύθερες ρυθμίσεις: μια προαιρετική προεπιλογή, έπειτα games=, min-games=, truncation=, jsd=, ply=, candidates=, seed=, χωρισμένα με κόμματα. Μια θέση που φέρει ήδη rollout με τις ίδιες ρυθμίσεις παραλείπεται: μια εκτέλεση που διακόπηκε με Ctrl-C συνεχίζει από εκεί που σταμάτησε, με την τρέχουσα θέση να απορρίπτεται εξ ολοκλήρου. Μια θέση που αναλύεται μόνο από rollout βρίσκεται από την αναζήτηση μέσω αυτού· μια ήδη αναλυμένη θέση διατηρεί τις στήλες της ανάλυσής της.
./blunderdb analyze --db base.db --rollout fast --query 'E>80'
./blunderdb analyze --db base.db --rollout 'standard,ply=1' --query 'c'
--compare: τι αξίζει το gammonNet στη δική σας βάση;
Η ακρίβεια της μηχανής μετριέται αλλού έναντι σωμάτων αναφοράς και έναντι του ακριβούς πίνακα μαζέματος. Καμία από αυτές τις μετρήσεις δεν απαντά στο ερώτημα που πραγματικά θέτει ο χρήστης και που αφορά τις δικές του θέσεις: στους αγώνες που εισήχθησαν από το XG, πού διαφωνεί η ενσωματωμένη μηχανή με την ανάλυση που ήρθε με το αρχείο, και τι θα κόστιζε αυτή η διαφωνία;
Το --compare απαντά και δεν γράφει τίποτα. Δεν είναι προφύλαξη αλλά το νόημα της εντολής: το ADR-0013 προστατεύει ανεπιφύλακτα μια εισηγμένη ανάλυση, και η σύγκριση μπορεί έτσι να τρέξει σε μια βάση που κανείς δεν θέλει να ξαναγραφτεί.
Η αναφορά δίνει:
το ποσοστό συμφωνίας στην καλύτερη απάντηση, χωρισμένο ανάμεσα σε κινήσεις πουλιών και αποφάσεις κύβου — τα δύο δεν έχουν σχέση μεταξύ τους και ένα ενιαίο ποσοστό θα έκρυβε ποιο από τα δύο υστερεί·
το κόστος της διαφωνίας, αποτιμημένο στην κλίμακα της εισηγμένης ανάλυσης: πόσο αξίζει η κίνηση που προτιμά το gammonNet σύμφωνα με την εισηγμένη μηχανή, μείον πόσο αξίζει η δική της καλύτερη κίνηση. Αυτή η κατεύθυνση είναι η μόνη που μπορούν να αποτιμήσουν από κοινού και οι δύο μηχανές· η διπλή αποτίμηση μιας διαφωνίας θα προσκαλούσε να διαβαστεί ο μικρότερος από τους δύο αριθμούς·
την ανάλυση ανά φάση του παιχνιδιού, που είναι αυτό που λέει πού συγκεντρώνονται οι διαφωνίες·
τις δέκα πιο δαπανηρές διαφωνίες, θέση προς θέση.
Δύο μηχανές γράφουν την ίδια κίνηση διαφορετικά — το XG γράφει «13/7» εκεί που το gammonNet γράφει «13/8 8/7», τα χτυπήματα σημειώνονται από τη μία πλευρά και όχι από την άλλη, η επανάληψη συμπυκνώνεται ενίοτε σε «(2)». Αυτές οι διαφορές είναι διάλεκτος και όχι διαφωνία: η σύγκριση ανάγει και τις δύο γραφές σε κανονική μορφή πριν τις συγκρίνει. Χωρίς αυτό, ένα δοκιμαστικό σώμα έδειχνε 78,8 % συμφωνία αντί για 93,2 % — δεκαπέντε μονάδες ψευδών διαφωνιών.
Μια κίνηση που η εισηγμένη μηχανή δεν κατέγραψε δεν μπορεί να αποτιμηθεί στην κλίμακά της: μετρά ως διαφωνία μηδενικού κόστους αντί για ένα κόστος επινοημένο.
# 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 — Αναπαραγωγή μιας μεταγραφής
Αναπαράγει μια μεταγραφή και αναφέρει τι βρίσκει σε αυτήν η επανάληψη. Η πηγή είναι ένα αρχείο .mat, ένας αγώνας της βιβλιοθήκης ή ένα πρόχειρο μεταγραφής — ακριβώς ένα από τα τρία. Ένας αγώνας διαβάζεται μέσω του .mat που θα παρήγαγε κατά την εξαγωγή: αυτό που αναπαράγεται είναι επομένως αυτό που θα περιείχε μια εξαγωγή.
./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
Επιλογές:
--mat— Αρχείο.matπρος αναπαραγωγή.--db— Βάση δεδομένων, για τα--matchκαι--draft.--match— Αναγνωριστικό του αγώνα της βιβλιοθήκης προς αναπαραγωγή.--draft— Αναγνωριστικό του πρόχειρου μεταγραφής προς αναπαραγωγή.--check— Παραθέτει τις ασυνέπειες που βρέθηκαν (προεπιλεγμένη συμπεριφορά).--render— Ξαναγράφει τη μεταγραφή σε.matσε αυτή τη διαδρομή.--format— Μορφή εξόδου:text(προεπιλογή) ήjson.--edit— Ανοίγει ένα προσχέδιο στο--match(ή επιστρέφει αυτό που είναι ήδη ανοιχτό σε αυτό).--accept-losses— Με το--editσε εισαγμένο αγώνα: δέχεται ότι οι αναλύσεις και τα σχόλιά του μπορεί να χαθούν.--finish— Ολοκληρώνει το--draft: γράφει τον αγώνα του ή αντικαθιστά αυτόν από τον οποίο ανοίχτηκε, και ελευθερώνει το προσχέδιο.--abandon— Εγκαταλείπει το--draft: το διαγράφει χωρίς αγώνα· ένας αγώνας από τον οποίο ανοίχτηκε μένει όπως είναι.--yes— Με το--abandonσε προσχέδιο που δεν παρήγαγε ποτέ αγώνα: επιβεβαιώνει ότι ό,τι έχει γραφτεί σε αυτό χάνεται.
--check ονομάζει κάθε ασυνέπεια με τον αριθμό της ενέργειας και την παρτίδα στην οποία βρίσκεται: παράνομη κίνηση, δύο σειρές στη σειρά για τον ίδιο παίκτη, αδύνατη ενέργεια κύβου, ενέργεια πέρα από το τέλος του αγώνα, κίνηση της οποίας τα βήματα δεν χρησιμοποιούν τα δικά της ζάρια, πρώτη κίνηση παρτίδας με διπλή ζαριά, που καμία ζαριά έναρξης δεν μπορεί να είναι, μη καταγεγραμμένη κίνηση — το κελί ??? που γράφει το gnubg όταν δεν κράτησε την κίνηση που παίχτηκε, και που δεν είναι χορός, ασυνεπές δηλωμένο σκορ — μια παρτίδα της οποίας η γραμμή σκορ δεν είναι αυτή που δίνουν οι προηγούμενες παρτίδες, και που ξαναπαίζεται με το γραμμένο σκορ.
Μια ασυνέπεια αναφέρεται, ποτέ δεν αντιτάσσεται: τίποτα δεν απορρίπτεται εξαιτίας της και ο κωδικός εξόδου παραμένει 0 ό,τι κι αν βρει η επανάληψη. Ένας μη μηδενικός κωδικός σημαίνει πραγματική αποτυχία — αρχείο που δεν διαβάζεται, βάση που δεν ανοίγει, έξοδος που δεν μπορεί να γραφτεί. Ένα σενάριο που θέλει να ενεργήσει βάσει των ευρημάτων τα διαβάζει με --format json, όπου ένα χαλασμένο αρχείο και μια παρτίδα που περιέχει παράνομη κίνηση δεν συγχέονται.
--render ξαναγράφει τη μεταγραφή σε .mat, πράγμα που επιτρέπει τον έλεγχο της μετάβασης και επιστροφής σε πραγματικό αρχείο, εκτός των δοκιμών.
Μόνο τρεις επιλογές γράφουν, με τις ίδιες μεθόδους όπως ο πίνακας Μεταγραφή: το --edit ανοίγει ένα προσχέδιο σε υπάρχοντα αγώνα, το --finish το ολοκληρώνει — ο αγώνας αντικαθίσταται με το ίδιο αναγνωριστικό — και το --abandon διαγράφει ένα προσχέδιο χωρίς αγώνα, και απαιτεί --yes για προσχέδιο που δεν ολοκληρώθηκε ποτέ, το οποίο παίρνει μαζί του ό,τι έχει γραφτεί σε αυτό. Ένας εισαγμένος αγώνας φέρει αναλύσεις και σχόλια που ένα .mat δεν φέρει: το --edit δίνει το πολύ τον αριθμό τους και αρνείται χωρίς --accept-losses.
Παράδειγμα:
./blunderdb transcribe --mat match.mat --check
# match.mat: 7 point match, 4 game(s), 203 action(s)
# Final score: 9-2
# Inconsistencies: none
tournament — Ανάγνωση διευθυνόμενου τουρνουά
Διαβάζει ένα διευθυνόμενο τουρνουά χωρίς γραφική διεπαφή. Η διεξαγωγή ενός τουρνουά με διαδραστικό τρόπο είναι δουλειά της κονσόλας της μηχανής Nicomaque· αυτές οι υποεντολές διαβάζουν, καμία δεν περιμένει είσοδο, και μόνο η move γράφει.
./blunderdb tournament <sous-commande> --db <chemin> [options]
Υποεντολές:
list [--format text|json]— Τα διευθυνόμενα τουρνουά της βάσης, με την κατάστασή τους, την έκδοση της μηχανής, τη διοργάνωση στην οποία ανήκει καθένα (κενό αν καμία) και την ημερομηνία της τελευταίας απόφασης.verify --id N [--format text|json]— Ξαναπαίζει τη διεύθυνση και αναφέρει κάθε εναπομείνασα προειδοποίηση. Τερματίζει με σφάλμα αν μείνει έστω μία: είναι ο έλεγχος μετά το τουρνουά, και ένα σενάριο που τον τρέχει στις βάσεις μιας σεζόν θέλει κωδικό εξόδου, όχι μια γραμμή προς φιλτράρισμα.standings --id N— Η κατάταξη σε CSV, με τα έπαθλα, στη γλώσσα της διεπαφής.ranking --season [--rencontre N] [--from AAAA-MM-JJ] [--to AAAA-MM-JJ] [--points 25,18,15] [--participation P] [--elo] [--format csv|json]— Η κατάταξη σεζόν: τα ολοκληρωμένα τουρνουά μιας διοργάνωσης ή μιας περιόδου (τα όρια συμπεριλαμβάνονται, με βάση την ημερομηνία του τουρνουά· χωρίς φίλτρο, όλα τα διευθυνόμενα τουρνουά), με κάθε θέση να μετατρέπεται σε βαθμούς από την κλίμακα (πρώτος ο νικητής· από προεπιλογή 25, 18, 15, 12, 10, 8, 6, 4, 2, 1), συν--participationανά τουρνουά που παίχτηκε. Οι ισοβαθμούντες μοιράζονται τον μέσο όρο των θέσεων που καταλαμβάνουν. Ένα πρόσωπο αναγνωρίζεται από τουρνουά σε τουρνουά από το όνομά του. Το--eloπροσθέτει ένα Elo συλλόγου που αναπαίζεται στους αγώνες της σεζόν (τύπος FIBS, εκκίνηση στο 1500). Το CSV δίνει μία γραμμή ανά πρόσωπο και μία στήλη βαθμών ανά τουρνουά· ένα μη ολοκληρωμένο τουρνουά εμφανίζεται στη λίστα αλλά δεν αποφέρει τίποτα.page --id N|--rencontre N [--out <φάκελος>]— Η σελίδα HTML προβολής ενός αγωνίσματος (--id), ή η σελίδα τοίχου μιας διοργάνωσης (--rencontre: μία γραμμή ανά τραπέζι, όποιο αγώνισμα κι αν το κατέχει). Ακριβώς ένα από τα δύο απαιτείται. Χωρίς--outπηγαίνει στην τυπική έξοδο· με αυτό, γράφεται στον φάκελο, ο οποίος γίνεται ο φάκελος της διεύθυνσης ή της διοργάνωσης.export --id N— Το ακατέργαστο ημερολόγιο γεγονότων, αναπαράξιμο από τα εργαλεία της μηχανής. Το ημερολόγιο είναι όλη η αλήθεια μιας διεύθυνσης: η κατάταξη, οι πίνακες και οι προειδοποιήσεις αναπαράγονται από αυτό. Ένα εργαλείο που διαβάζει αυτή την έξοδο δεν χρειάζεται καθόλου το blunderDB.move --id N --match M --table T [--format text|json]— Αλλάζει το τραπέζι ενός αγώνα σε εξέλιξη, όπως η μεταφορά ενός κελιού πάνω σε άλλο στο πλέγμα. Αν το τραπέζι προορισμού είναι κατειλημμένο, οι δύο αγώνες ανταλλάσσουν τραπέζια· ένα τραπέζι εκτός λειτουργίας απορρίπτεται. Σε μια διοργάνωση, αν το τραπέζι είναι κατειλημμένο από άλλο αγώνισμα, η ανταλλαγή γίνεται μεταξύ των δύο αγωνισμάτων: μια αλλαγή τραπεζιού γράφεται στο ημερολόγιο καθενός. Εμφανίζει το τραπέζι κάθε αγώνα σε εξέλιξη.hall --rencontre N [--format text|json]— Όλα τα τραπέζια μιας διοργάνωσης: μία γραμμή ανά τραπέζι, όποιο αγώνισμα κι αν το καταλαμβάνει (αγώνισμα, αγώνας, παίκτες), και έπειτα οι προτάσεις κάθε αγωνίσματος. Είναι το πλέγμα που εμφανίζει η προβολή Όλα τα τραπέζια της Direction. Τα τραπέζια ομαδοποιούνται ανά αίθουσα όταν η διοργάνωση έχει αίθουσες, και φέρουν όνομα όταν έχουν.tables --rencontre N|--tournament N [--format text|json]— Οι ιδιότητες των τραπεζιών (όνομα, αίθουσα, δεσμευμένο, ορισμένο για) και οι αίθουσες όπου παίζεται κάθε αγώνισμα μιας διοργάνωσης (--rencontre), ή οι ιδιότητες ενός αγωνίσματος που παίζεται μόνο του (--tournament). Μόνο ανάγνωση: η εγγραφή γίνεται μέσω τουcall(rencontres.setTables,rencontres.setEventRooms,directions.setTables).
Κοινές επιλογές: --db (υποχρεωτικό), --id (υποχρεωτικό εκτός από τα list, page --rencontre hall και tables), --format.
Παραδείγματα:
./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 — Ο κάδος
Τι έχει διαγραφεί και με τι επιστρέφει. Μια διαγραφή παραμένει διαγραφή: ένα στιγμιότυπο JSON αυτού που εξαφανίζεται γράφεται πρώτα, και τίποτε άλλο στη βάση δεν γνωρίζει ότι αυτός ο πίνακας υπάρχει — κανένα φίλτρο αναζήτησης, καμία στατιστική, κανένας κανόνας διατήρησης.
./blunderdb trash <sous-commande> --db <chemin> [options]
Υποεντολές:
list— Τι υπάρχει στον κάδο, από το πιο πρόσφατα διαγραμμένο στο παλαιότερο.restore --id N— Επαναφέρει την καταχώριση N και την αφαιρεί από τον κάδο.discard --id N— Διαγράφει την καταχώριση N αμέσως, χωρίς να την επαναφέρει.empty [--older-than Η]— Αδειάζει τον κάδο, ή μόνο ό,τι είναι παλαιότερο από Η ημέρες.delete --kind K --id N— Διαγράφει ένα αντικείμενο μέσω του κάδου, ώστε η ενέργεια να είναι αναιρέσιμη. ΤοKείναιposition,collectionήcomment.
Κοινές επιλογές: --db (υποχρεωτική), --kind, --limit (προεπιλογή 50), --format (text ή json).
Σημείωση
Η blunderdb delete διαγράφει πάντα χωρίς δίχτυ: ένα σενάριο που διαγράφει μια θέση περιμένει να εξαφανιστεί, και το να αφήνει σιωπηλά ένα στιγμιότυπο θα μεγάλωνε ένα αρχείο που κανείς δεν ζήτησε να μεγαλώσει. Η trash delete είναι αυτή που κρατά την αναίρεση.
Η επαναφορά μιας θέσης περνά ξανά από την αφαίρεση διπλότυπων Zobrist: δεν δημιουργεί ποτέ διπλότυπο, αλλά δεν επιστρέφει το παλιό της αναγνωριστικό — η αρχική γραμμή δεν υπάρχει πια. Μια επαναφερμένη θέση είναι η ίδια θέση, με νέο αριθμό.
Ό,τι είναι παλαιότερο από τριάντα ημέρες το διαγράφει η blunderdb vacuum — ποτέ το άνοιγμα μιας βάσης.
Παραδείγματα:
# 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 — Μεταδεδομένα της βάσης
Εμφανίζει τα μεταδεδομένα και τα στατιστικά μιας βάσης δεδομένων.
./blunderdb info --db <path> [--format <format>]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--format— Μορφή εξόδου:textήjson(προεπιλογή:text).
Παραδείγματα:
./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 προσθέτει την προέλευση του αρχείου — το issuance φέρει το υδατογράφημα, αν υπάρχει, και την ταυτότητα εκδότη αυτού του υπολογιστή:
./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 — Τροποποίηση μεταδεδομένων
Τροποποιεί το όνομα χρήστη, την περιγραφή ή τα κατώφλια μιας βάσης δεδομένων.
./blunderdb edit --db <path> [options]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--user— Νέο όνομα χρήστη.--description— Νέα περιγραφή.--clear-user— Διαγραφή του ονόματος χρήστη.--clear-description— Διαγραφή της περιγραφής.--error-threshold— Κατώφλι σφάλματος, σε χιλιοστά του πόντου: μια απόφαση που κοστίζει τουλάχιστον τόσο είναι σφάλμα.--blunder-threshold— Κατώφλι blunder, σε χιλιοστά του πόντου: ένα σφάλμα που κοστίζει τουλάχιστον τόσο είναι blunder.--format— Μορφή εξόδου:text(προεπιλογή) ήjson({"changes": [...]}).
Απαιτείται τουλάχιστον μία επιλογή τροποποίησης.
Παραδείγματα:
./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 — Έλεγχος ακεραιότητας
Ελέγχει την ακεραιότητα της βάσης δεδομένων και, προαιρετικά, συγκρίνει έναν αγώνα με το αρχείο προέλευσής του.
./blunderdb verify --db <path> [--match <id>] [--mat <file.mat>]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--match— ID του αγώνα προς έλεγχο.--mat— Αρχείο MAT προς σύγκριση (χρησιμοποιείται με--match).--format— Μορφή εξόδου:text(προεπιλογή) ήjson(στατιστικά, ορφανές γραμμές, απόκλιση σχήματος, και ο έλεγχος του ματς αν υπάρχει).
Χωρίς την επιλογή --match, η εντολή εμφανίζει τα γενικά στατιστικά της βάσης. Με το --match, ελέγχει τα δεδομένα του αγώνα και μπορεί να τα συγκρίνει με το αρχικό αρχείο προέλευσης.
Κάθε εκτέλεση ελέγχει επίσης την ακεραιότητα αναφορών: μετρά τις ορφανές γραμμές — παρτίδες χωρίς αγώνα, κινήσεις χωρίς παρτίδα, αναλύσεις κίνησης χωρίς κίνηση, αναλύσεις χωρίς θέση, εγγραφές του ημερολογίου επανάληψης χωρίς τράπουλα ή χωρίς θέση — και εμφανίζει μια γραμμή WARNING με το σύνολο, αν υπάρχουν. Μια υγιής βάση απαντά Orphaned rows: none. Ορφανές γραμμές μπορεί να παραμένουν σε μια βάση που γράφτηκε από έκδοση η οποία δεν επέβαλλε τα ξένα κλειδιά σε κάθε σύνδεση, ή πριν το ημερολόγιο επανάληψης αποκτήσει τα δικά του· δεν ανήκουν σε κανέναν αγώνα ούτε σε καμία τράπουλα και απλώς πιάνουν χώρο. Η εντολή τερματίζει και πάλι με κωδικό 0.
Κάθε εκτέλεση συγκρίνει επίσης το σχήμα με το DDL αναφοράς και απαριθμεί τους πίνακες, τις στήλες και τα ευρετήρια που λείπουν από τη βάση. Το άνοιγμα μιας βάσης προσθέτει ό,τι λείπει όταν μπορεί και απλώς καταγράφει ό,τι δεν μπορεί να προσθέσει (συνήθως ένα ευρετήριο UNIQUE που διπλές γραμμές το εμποδίζουν να ξαναχτιστεί): εδώ γίνεται ορατό αυτό το κενό, και ένα ερώτημα που κατονομάζει ένα από αυτά τα στοιχεία αποτυγχάνει μέχρι να διορθωθεί η αιτία. Μια υγιής βάση απαντά Schema: matches the reference DDL. Όπως και οι ορφανές γραμμές, μια απόκλιση σχήματος είναι διαπίστωση, όχι αποτυχία: ο κωδικός εξόδου παραμένει 0.
Κάθε εκτέλεση ελέγχει τέλος τους κανόνες που ορίζει η τρέχουσα DDL αλλά που η SQLite δεν μπορεί να προσθέσει σε έναν ήδη υπάρχοντα πίνακα: τους περιορισμούς εύρους CHECK (ζάρια από 0 έως 6, κύβος και pips μη αρνητικά, 0 έως 15 πούλια εκτός, βαθμολογία επανάληψης από 1 έως 4), το hash Zobrist που δεν θα έπρεπε ποτέ να λείπει από μια γραμμή και τη μοναδικότητα μιας ανάλυσης ανά θέση. Μια βάση που δημιουργήθηκε από την έκδοση σχήματος 2.18.0 και μετά τους επιβάλλει· μια παλαιότερη μπορεί να περιέχει ακόμη γραμμές που μια νέα βάση θα απέρριπτε, και αυτές μετρώνται εδώ, κανόνα προς κανόνα. Μια υγιής βάση απαντά Constraints: every row satisfies the current DDL. Άλλη μια διαπίστωση: τίποτα δεν επιδιορθώνεται και ο κωδικός εξόδου παραμένει 0.
Κάθε εκτέλεση υπολογίζει τέλος εκ νέου τους δύο αποκανονικοποιημένους μετρητές, match.game_count και game.move_count, από τις γραμμές που ισχυρίζονται ότι μετρούν, και αναφέρει πόσοι διαφωνούν και κατά πόσο στη χειρότερη περίπτωση. Και οι δύο γράφονται μία φορά, κατά την εισαγωγή, από ό,τι περιείχε το αρχείο πηγής, και είναι αυτοί που εμφανίζουν η λίστα αγώνων και η προβολή παρτίδας: μια μικρή απόκλιση είναι συνήθως μια εισαγωγή που παρέλειψε ό,τι δεν μπορούσε να μετατρέψει. Τίποτα δεν ξαναγράφεται — η αντικατάσταση του μετρητή με ό,τι αποθηκεύτηκε θα έσβηνε ακριβώς την απόκλιση που αξίζει να δει κανείς. Μια υγιής βάση απαντά Counters: game_count and move_count agree with the rows.
Παραδείγματα:
./blunderdb verify --db base.db
./blunderdb verify --db base.db --match 1
./blunderdb verify --db base.db --match 1 --mat original.mat
Να χρησιμοποιηθεί ως δικλείδα. Ο κωδικός εξόδου είναι 0 ό,τι κι αν βρει η εντολή: η --format json είναι αυτή που φέρει την ετυμηγορία, και ένα σενάριο πρέπει να διαβάσει το ίδιο τους μετρητές.
{
"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
}
Τρία πεδία αξίζουν συναγερμό: τα orphan_total, schema_drift_count και constraint_violation_total. Όταν δεν είναι μηδενικά, περιγράφουν βάση που χρειάζεται επισκευή.
./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 δεν ανήκει σε αυτά, και το παραπάνω παράδειγμα το δείχνει: η βάση που το παρήγαγε μόλις είχε εισαχθεί και εμφανίζει ήδη 53 παρτίδες των οποίων ο μετρητής κινήσεων διαφέρει από αυτό που περιέχουν οι γραμμές. Οι μετρητές αυτοί προέρχονται από το αρχείο πηγής, όχι από τη βάση· μια απόκλιση αφηγείται την εισαγωγή, δεν σημαίνει αλλοίωση. Κοιτάξτε τον, μη τον χρησιμοποιείτε ως κατώφλι.
vacuum — Συμπύκνωση της βάσης δεδομένων
Ανακτά τον χώρο στον δίσκο που άφησαν οι διαγραφές (αγώνες, τουρνουά, εκκαθαρίσεις): η SQLite δεν μικραίνει ποτέ μόνη της το αρχείο όταν διαγράφονται δεδομένα, πρέπει να της ζητηθεί ρητά. Είναι ο μόνος τρόπος να ξεκινήσει μια συμπύκνωση — δεν συμβαίνει ποτέ αυτόματα στο άνοιγμα μιας βάσης, γιατί το κόστος της είναι απρόβλεπτο σε μεγάλη βάση.
./blunderdb vacuum --db <path>
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--format— Μορφή εξόδου:text(προεπιλογή) ήjson({"size_before", "size_after", "reclaimed"}, σε bytes).
Η εντολή ξεκινά με ένα wal_checkpoint(TRUNCATE) ώστε το μέγεθος που εμφανίζεται πριν από τη συμπύκνωση να είναι ειλικρινές, ελέγχει ότι απομένει στον δίσκο περίπου το διπλάσιο του τρέχοντος μεγέθους του αρχείου (η SQLite ξαναχτίζει ολόκληρη τη βάση πριν μεταβεί σε αυτήν), εκτελεί το VACUUM και έπειτα ένα ANALYZE για να ανανεώσει τα στατιστικά που χρησιμοποιεί ο σχεδιαστής ερωτημάτων. Αν λείπει χώρος στον δίσκο, η εντολή αρνείται να ξεκινήσει με ρητό μήνυμα αντί να διακινδυνεύσει μια διακοπείσα συμπύκνωση.
Παράδειγμα:
./blunderdb vacuum --db base.db
# Compacting database...
# Before: 128.4 MiB
# After: 41.2 MiB
# Reclaimed: 87.2 MiB
repair — Επανυπολογισμός όσων είναι παράγωγα
Επανυπολογίζει ό,τι η βάση αντλεί από όσα αποθηκεύει: τις βαθμωτές στήλες κάθε ανάλυσης από την ίδια την ανάλυση, της οποίας δεν είναι παρά μια προβολή· τη φάση και τον τύπο παιχνιδιού κάθε θέσης από το ταμπλό της· και τον δείκτη Crawford κάθε σκορ από τον αγώνα από τον οποίο προέρχεται η θέση, ή από το XGID με το οποίο μπήκε. Οι αναλύσεις δεν θίγονται: αυτό που ξαναγίνεται είναι οι τιμές που είχαν εξαχθεί από αυτές.
./blunderdb repair --db <path>
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--format— Μορφή εξόδου:text(προεπιλογή) ήjson— ένας μετρητής ανά πέρασμα:repaired(στήλες ανάλυσης),phases(θέσεις που αναταξινομήθηκαν) καιcrawford(θέσεις με νέο hash). Ο καθένας δίνει τον αριθμό των γραμμών που άλλαξαν πραγματικά.
Χρήσιμη μετά από διόρθωση του τρόπου με τον οποίο διαβάζεται μια εισηγμένη ανάλυση. Έχει ήδη συμβεί δύο φορές. Ο εισαγωγέας XG γράφει ένα «χωρίς διπλασιασμό» με δύο τρόπους, και ο δεύτερος εκλαμβανόταν ως πραγματικός διπλασιασμός — η στήλη έφερε τότε το σφάλμα ενός διπλασιασμού που ποτέ δεν έγινε. Και μια ανάλυση που το ίδιο το blunderDB είχε υπολογίσει δεν ήξερε ποια κίνηση είχε παιχτεί, οπότε ένας αγώνας που εισήχθη χωρίς ανάλυση κρατούσε μηδενικό σφάλμα παντού και PR 0,00· η στήλη ξαναϋπολογίζεται τώρα από τις κινήσεις του αγώνα. Η διόρθωση της ανάγνωσης δεν αλλάζει τίποτα στις ήδη γραμμένες γραμμές· αυτή η εντολή τις ξαναφτιάχνει.
Το πέρασμα του Crawford, αντιθέτως, αγγίζει τις ίδιες τις θέσεις. Σκορ 1 σημαίνει «μένει ένας πόντος, και αυτή η παρτίδα ΕΙΝΑΙ η παρτίδα Crawford»· 0 σημαίνει «μένει ένας πόντος, η παρτίδα Crawford είναι πίσω μας». Όσο οι εισαγωγείς δεν έγραφαν αυτή τη διάκριση, κάθε θέση μετά το Crawford καταγραφόταν ως θέση Crawford, και άρα διαβαζόταν με νεκρό κύβο — εκεί ακριβώς όπου αυτός που χάνει διπλασιάζει στην πραγματικότητα με την πρώτη ευκαιρία. Η διόρθωση του σκορ αλλάζει τον κατακερματισμό της θέσης: η γραμμή λοιπόν ξανακατακερματίζεται και συγχωνεύεται με τη σωστή δίδυμή της αν η βάση κρατά ήδη μία — η ανάλυση, τα σχόλια, οι συλλογές, οι κάρτες Anki και το ημερολόγιο επαναλήψεών τους, οι κινήσεις του αγώνα και οι καταχωρίσεις του κάδου απορριμμάτων που την κατονομάζουν ακολουθούν τη γραμμή που επιβιώνει. Μια θέση την οποία δεν δείχνει κανένας αγώνας διορθώνεται μόνο με τον λόγο του XGID που έφερε από άλλο πρόγραμμα (XG, BGBlitz…): όταν το πεδίο Crawford αυτού του XGID λέει ότι η παρτίδα δεν είναι η παρτίδα Crawford, και το XGID περιγράφει πράγματι αυτή τη θέση. Προς την αντίθετη κατεύθυνση, μια θέση χωρίς αγώνα, αποθηκευμένη με 0 και από τις δύο πλευρές, περνά σε 1 όταν το XGID που έφερε είναι ενός αγώνα 1 πόντου και την περιγράφει: η μόνη παρτίδα ενός αγώνα 1 πόντου ξεκινά έναν πόντο πριν από τον στόχο, άρα είναι η παρτίδα Crawford, όπως τη γράφουν οι εισαγωγείς. Το DMP μετά την παρτίδα Crawford ενός μακρύτερου αγώνα μένει στο 0: το XGID του δίνει το μήκος αυτού του αγώνα. Ένα XGID που το blunderDB ξανάγραψε μόνο του απλώς επαναλαμβάνει το αποθηκευμένο σκορ και δεν αποδεικνύει τίποτα. Κάθε άλλη θέση χωρίς αγώνα μένει ως έχει: τίποτα δεν αντιφάσκει με όσα δηλώνει το σκορ της.
Τίποτα δεν την ενεργοποιεί αυτόματα, και αυτό είναι σκόπιμο: το να ξαναγράφονται οι στήλες ανάλυσης όλων, ή να ξανακατακερματίζονται θέσεις, με το απλό άνοιγμα μιας βάσης δεν είναι κάτι που ένα εργαλείο πρέπει να κάνει πίσω από την πλάτη του χρήστη του.
Παράδειγμα:
./blunderdb repair --db base.db
# 42 analyses repaired.
# 7 positions reclassified.
# 3 positions rehashed onto the right Crawford sentinel.
delete — Διαγραφή δεδομένων
Διαγράφει έναν αγώνα και όλα τα σχετικά δεδομένα (παρτίδες, κινήσεις, αναλύσεις).
./blunderdb delete --db <path> --type match --id <id> [--confirm]
Επιλογές:
--db— Βάση δεδομένων (υποχρεωτικό).--type— Τύπος διαγραφής:match(υποχρεωτικό).--id— ID του στοιχείου προς διαγραφή (υποχρεωτικό).--confirm— Διαγραφή χωρίς αίτημα επιβεβαίωσης.--format— Μορφή εξόδου:text(προεπιλογή) ήjson({"match_id": N, "deleted": true}).
Παραδείγματα:
# 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 — Έλεγχος ενός δαίμονα
Ρωτά έναν δαίμονα serve σε λειτουργία (βλ. Λειτουργία χωρίς γραφικό περιβάλλον (διακομιστής)) αν είναι διαθέσιμος: ένα αίτημα GET /readyz, κωδικός επιστροφής 0 αν ο δαίμονας απαντά 200 (αποθήκευση προσβάσιμη, σχήμα στην αναμενόμενη έκδοση), 1 αλλιώς — αποθήκευση μη προσβάσιμη, ξεπερασμένο σχήμα ή τίποτα δεν ακούει στη διεύθυνση. Δεν ανοίγει κανένα αρχείο βάσης.
./blunderdb healthcheck [--addr host:port] [--timeout 2s]
Επιλογές:
--addr— Διεύθυνση στην οποία ακούει ο δαίμονας (προεπιλογήBLUNDERDB_ADDR, αλλιώς:8080). Μια διεύθυνση χωρίς host (:8080) ή με γενικό host (0.0.0.0,[::]) ελέγχεται μέσω της διεπαφής loopback.--timeout— Χρόνος μετά τον οποίο ο έλεγχος εγκαταλείπει (2sαπό προεπιλογή).
Είναι η εντολή που εκτελεί το HEALTHCHECK της εικόνας container (εικόνα distroless, χωρίς curl)· το δυαδικό serve που χτίζεται από το cmd/serve την καταλαβαίνει επίσης. Είναι εξίσου χρήσιμη σε ένα script ή σε μια μονάδα systemd.
Παράδειγμα:
./blunderdb serve --db base.db --addr 127.0.0.1:8080 &
./blunderdb healthcheck --addr 127.0.0.1:8080 && echo "démon disponible"
# ready
Σε περίπτωση αποτυχίας εμφανίζεται η αιτία, την οποία το docker inspect αναπαράγει για ένα container unhealthy:
Error: healthcheck: http://127.0.0.1:8080/readyz answered 503 Service Unavailable (version_mismatch)
mcp — Προσφορά της βάσης σε έναν βοηθό ΤΝ
Εξυπηρετεί τα εργαλεία της βάσης σε έναν βοηθό ΤΝ μέσω του Model Context Protocol, στην τυπική είσοδο και έξοδο: ο βοηθός εκκινεί την εντολή. Τα εργαλεία αναζητούν θέσεις στη γραμματική της γραμμής εντολών, διαβάζουν μια θέση και την ανάλυσή της, εξηγούν ένα λάθος, υπολογίζουν τα στατιστικά ενός παίκτη, απαριθμούν αγώνες, τουρνουά και συλλογές και θέτουν ένα κουίζ. Μόνο διαβάζουν, εκτός αν δοθεί --write. Ο πλήρης κατάλογος και το ισοδύναμο HTTP του δαίμονα: Εργαλεία για έναν βοηθό ΤΝ (MCP).
./blunderdb mcp --db base.db [--write]
Επιλογές:
--db— Αρχείο βάσης δεδομένων (υποχρεωτικό).--write— Προσφέρει επίσης τα εργαλεία που γράφουν: αποθήκευση θέσης, σχολιασμός της, δημιουργία και συμπλήρωση συλλογής. Τίποτα δεν διαγράφεται.
Όπως η call, η εντολή μεταφέρει το σχήμα μιας παλαιότερης βάσης κατά το άνοιγμα, ακόμη και χωρίς --write.
Παράδειγμα: δήλωση της βάσης στο Claude Code.
claude mcp add blunderdb -- blunderdb mcp --db /chemin/vers/base.db
completion — Συμπλήρωση κελύφους
Εμφανίζει στην τυπική έξοδο ένα σενάριο συμπλήρωσης για τα ονόματα των υποεντολών. Η λίστα εντολών που ενσωματώνεται σε κάθε σενάριο παράγεται από τον ίδιο πίνακα που διαβάζουν και το blunderdb help και η δρομολόγηση του main.go (handlers()): έτσι μια νέα υποεντολή προσφέρεται από τη συμπλήρωση μόλις συνδεθεί, χωρίς τίποτα να χρειάζεται χειροκίνητη συντήρηση.
./blunderdb completion <bash|zsh|fish>
Παραδείγματα:
# 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
Τα πακέτα το εγκαθιστούν αυτόματα: το .deb/.rpm (nfpm) και το πακέτο AUR παράγουν τα τρία σενάρια από το πακεταρισμένο εκτελέσιμο κατά τη στιγμή της κατασκευής, και το Homebrew cask εκτελεί blunderdb completion <shell> μία φορά κατά την εγκατάσταση μέσω generate_completions_from_executable. Τίποτα δεν αποθηκεύεται στο αποθετήριο, οπότε η συμπλήρωση δεν μπορεί ποτέ να αποκλίνει από τον πίνακα υποεντολών.
version — Εμφάνιση της έκδοσης
Εμφανίζει την έκδοση του blunderDB και την έκδοση του σχήματος βάσης δεδομένων που γράφει αυτό το εκτελέσιμο· είναι το πρώτο πράγμα που επισυνάπτεται σε μια αναφορά σφάλματος.
./blunderdb version
# blunderDB version 0.36.0 (database schema 2.20.0)
Παραδείγματα ροών εργασίας
Εισαγωγή ενός καταλόγου τουρνουά
./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
Τακτικό αντίγραφο ασφαλείας
./blunderdb export --db production.db --type database --file sauvegarde-$(date +%Y%m%d).db
Ανάλυση σφαλμάτων
# 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
Κωδικοί εξόδου
0— Επιτυχία.1— Σφάλμα.
Αυτό επιτρέπει τη χρήση της CLI σε σενάρια με διαχείριση σφαλμάτων:
if ./blunderdb import --db base.db --type match --file match.xg; then
echo "OK"
else
echo "KO"
exit 1
fi