Opening Book
The Opening Book provides pre-computed turn sequences for common opening positions, allowing bots to play strong opening moves instantly without spending search budget.
In Dice Chess, opening book coverage is particularly valuable because the branching factor is high (often hundreds of legal turn paths per dice roll), while empirical game data from master play provides rich, reliable continuations.
Format & Contract
Section titled “Format & Contract”Opening books are stored in plain TSV (tab-separated values) format. Each non-empty line maps a canonical position-and-dice key to a recommended turn continuation:
<canonical-key>\t<continuation>Canonical Key (OpeningBook.key)
Section titled “Canonical Key (OpeningBook.key)”A book key identifies a specific board position together with the rolled dice pool:
<piece-placement> <active-color> <castling> <en-passant> <dice>- First 4 Fields (Normalized FEN): The canonical 4-field FEN from
Dfen.normalizedFen(byte-compatible with the analytics databasenormalized_fencolumn):- Piece placement, active color (
worb), castling rights (KQkqor-), and canonical en-passant target square (retained only if actually capturable). - Half-move clock and full-move counter are omitted so positions that differ only by move counters share the same book entry.
- Piece placement, active color (
- 5th Field (
<dice>): The rolled piece letters (P N B R Q K), sorted alphabetically and cased by the active player — uppercase for White, lowercase for Black (matching the analyticsdice_sortedcolumn).
Continuation Value
Section titled “Continuation Value”The value mapped to a key is a comma-separated list of long-algebraic (UCI) micro-moves (e.g. e2e4,f1c4, with a promotion suffix such as e7e8q where applicable).
Realistic TSV Example
Section titled “Realistic TSV Example”rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - BPR e2e4,f1c4rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - BKP e2e4,e1e2rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - bpr e8e7,d7d5[!IMPORTANT] Cross-Repository Invariant: The
OpeningBook.keycontract is shared across the Dice Chess ecosystem (the engine,dicechess-analytics, and the play platform). Any change to the key format is a breaking cross-repository event.
Book Provenance & Exporting
Section titled “Book Provenance & Exporting”The engine itself does not generate opening books. Opening books are produced from the historical games database by the dicechess-analytics backend:
# In the dicechess-analytics repository:mise run db:export-book [minGames] [minRating] [outputPath]
# Example: Export book from games with rating >= 2000 and at least 100 observationsmise run db:export-book 100 2000 opening_book.tsvOpening book data files are kept locally and are git-ignored (opening_book.tsv, *.book.tsv) — never commit data files to the engine repository.
Book Bot Implementation
Section titled “Book Bot Implementation”Parsing & Decoration
Section titled “Parsing & Decoration”The engine provides OpeningBookParser and OpeningBookBot:
OpeningBookParser.parse(tsvString): Validates and parses TSV data into aMap[String, String], returning anEither[Exception, Map[String, String]].OpeningBookBot.decorate(underlying, book): Wraps any baseSearchAlgorithmwith opening book lookups.- If
underlyingimplementsTimeBudgetedSearch,decoratereturns aTimeBudgetedOpeningBookBotso wall-clock deadlines are forwarded to the fallback bot on a book miss. - Draw and doubling decisions delegate directly to the underlying bot if it implements
DrawOfferLogic.
- If
Lookup Algorithm
Section titled “Lookup Algorithm”flowchart TD
A["Current State (Rolled Position)"] --> B["Build Canonical Key: OpeningBook.key(state)"]
B --> C{"Key in Book Map?"}
C -->|No| D["Fallback: underlying.findBestMove(state)"]
C -->|Yes| E["Get Booked Continuation (UCI list)"]
E --> F["Find Legal Turn Path Matching Move Multiset"]
F --> G{"Matching Legal Path Found?"}
G -->|Yes| H["Play Booked Turn Immediately"]
G -->|No| D
- Key Generation:
OpeningBook.key(state)constructs the canonical key. If no dice pool is set, lookup returnsNone. - Map Lookup: The key is checked against
book: Map[String, String]. - Multiset Matching: The booked UCI micro-moves are compared against all legal turn paths from
TurnGenerator.generateAllLegalTurnPaths(state)by move multiset signature (moves.sorted.mkString(",")).- The stored move order does not matter.
- If the booked moves cannot be realised legally (e.g. from an incompatible or corrupted book), the entry is silently ignored in favour of the fallback bot rather than making an illegal move.
- Fallback: On a book miss or illegal book move,
underlying.findBestMove(state)executes normally.
Usage Examples
Section titled “Usage Examples”Scala (JVM)
Section titled “Scala (JVM)”import dicechess.engine.search.{BotInfo, BotRegistry, OpeningBookBot, OpeningBookParser}import scala.io.Source
val source = Source.fromFile("opening_book.tsv")val tsvString = try source.mkString finally source.close()
val book = OpeningBookParser.parse(tsvString).fold(error => throw error, identity)val baseBot = BotRegistry.getAlgorithm("aggressive").getval decorated = OpeningBookBot.decorate(baseBot, book)
val registration = BotRegistry.registerCustomBot( BotInfo( id = "aggressive-book", name = "Aggressive + Book", description = "Aggressive bot decorated with an opening book", difficulty = 5, isExperimental = true ), decorated)
// When the bot is no longer needed:registration.close()JavaScript / TypeScript (Scala.js)
Section titled “JavaScript / TypeScript (Scala.js)”The JavaScript API exposes registerOpeningBookBot on DiceChess:
import { DiceChess } from '@fortemate/dicechess-engine';
const tsvString = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - BPR\te2e4,f1c4\n";
const ok = DiceChess.registerOpeningBookBot( tsvString, "aggressive", // base bot ID "aggressive-book", // new custom bot ID "Aggressive + Book" // new bot display name);
if (ok) { const result = DiceChess.getBestMove(dfen, { algorithm: "aggressive-book" }); console.log("Book turn:", result.moves);}Bot Arena Runner (JVM)
Section titled “Bot Arena Runner (JVM)”Pits a base bot against the same bot decorated with an opening book to evaluate book performance:
sbt 'arena/runMain dicechess.engine.bench.OpeningBookArenaRunner \ --base-bot aggressive \ --book opening_book.tsv \ --games 50'
# Or via mise task:mise run arena:book aggressive opening_book.tsv 50Roadmap & Future Enhancements
Section titled “Roadmap & Future Enhancements”Future opening book capabilities are tracked in the Search Roadmap & Evaluation:
- In-Engine Book Distillation: Generating opening books directly via self-play without relying on external databases.
- Weighted Multi-Line Selection: Supporting probabilistic selection across multiple viable continuations for the same opening key.
- Binary Serialization: Compact binary formats for large opening books.
See Also
Section titled “See Also”- Expectimax Search Engine — Two-ply lookahead search for out-of-book positions
- Time Management — Budget allocation and deadline forwarding
- Search Roadmap & Evaluation — Staged plans for future search and book optimizations