An open-source, high-performance, cross-platform game engine and AI search for Dice Chess, built with Scala 3 targeting JVM, JavaScript (Scala.js), and WebAssembly (WasmGC).
Dice Chess is a stochastic chess variant where players roll three six-sided dice before making their moves.
-
The Turn Structure:
- A player's turn consists of one roll of 3 dice and up to 3 micro-moves.
- The active color in the FEN does not change within the turn (during micro-moves). It only changes when the turn ends β after the playable dice have been consumed, or immediately when no legal moves exist (a forced pass; there is no voluntary pass).
-
The Dice Roll:
- Each die determines which piece type may move:
1= Pawn (β)2= Knight (β)3= Bishop (β)4= Rook (β)5= Queen (β)6= King (β)
- Each die determines which piece type may move:
-
Micro-moves:
- Each micro-move consumes one die matching the moved piece's type. Castling consumes two dice β King (
6) and Rook (4) β in a single move. - You can move different pieces or the same piece multiple times during your turn, as long as each move matches one of the remaining dice.
- Victory Condition: The game is won by capturing the opponent's king directly (no check/checkmate).
- Maximum Micro-moves Rule: Players must choose move sequences that maximize the number of dice consumed over the whole turn; any sequence that captures the opponent's king is always legal regardless of length.
- Each micro-move consumes one die matching the moved piece's type. Castling consumes two dice β King (
This project compiles from a single Scala 3 codebase into four published artifacts, all at one version per release:
- Maven rules artifact (
com.fortemate:dicechess-rules_3, from 0.11.0): the rules of the game only β board and DFEN model, move generation, legal turn enumeration, dice probabilities. Depends on the Scala standard library and nothing else. - Maven engine artifact (
com.fortemate:dicechess-engine_3): bots, evaluators, feature extractors and the Java/Kotlin facadeJvmApi. Depends ondicechess-rules_3of the same version;onnxruntimeis an optional dependency that ONNX consumers declare themselves. The JMH benchmarks, the bot arena and the CLI live in this repository but are not part of the jar. - NPM JavaScript Package (
@fortemate/dicechess-engine): ES Module for browsers and Node.js. - NPM WebAssembly Package (
@fortemate/dicechess-engine-wasm): WasmGC build running on modern WebAssembly runtimes.
What each artifact contains, what is deliberately left out and how to pick or switch a coordinate: Published Artifacts & Rules-Only Migration.
- mise (manages Java Temurin 25, Node.js 26, sbt, scalafmt, and tooling)
# Clone the repository
git clone https://github.com/fortemate/dicechess-engine.git
cd dicechess-engine
# Install toolchain and register git hooks
mise install
mise run setup
# Run full test suite and quality gates
mise run check
# Performance benchmarks
mise run bench # JVM JMH benchmarks
mise run bench:js # JavaScript (Scala.js / ES2022) on Node.js
mise run bench:wasm # WebAssembly (Scala.js / WasmGC) on Node.js
mise run bench:all # Cross-platform JS vs Wasm vs JVM comparisonInstall from npmjs.org without a token or custom registry configuration:
npm install @fortemate/dicechess-engineimport { DiceChess } from '@fortemate/dicechess-engine';
// A Dice Chess FEN (DFEN) carries the rolled dice as a 7th field: "PN" = a Pawn and a Knight die.
const dfen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 PN';
// Every legal micro-move for this position and roll, as UCI strings
const legalMoves = DiceChess.getLegalUciMoves(dfen); // e.g. ["e2e3", "e2e4", "b1c3", ...]
// Play one micro-move, then close the turn once the dice are spent
const afterMove = DiceChess.applyMove(dfen, 'e2', 'e4');
const nextTurn = DiceChess.endTurn(afterMove);
// Ask a built-in bot for its turn (ids from DiceChess.getAvailableBots())
const bot = DiceChess.getBestMove(nextTurn, { algorithm: 'greedy' });
console.log('Bot plays:', bot.moves, 'score', bot.score);The full surface (getAvailableBots, clock-aware getBestMove, doubling and draw decisions, estimateEquity) is documented in the JavaScript API Reference.
JvmApi ships in com.fortemate:dicechess-engine_3 (Maven Central); rules-only JVM projects use dicechess-rules_3 and call the Scala API directly.
import dicechess.engine.domain.GameState;
import dicechess.engine.jvmapi.JvmApi;
import java.util.List;
public class BotExample {
public static void main(String[] args) {
GameState state = JvmApi.parseDfen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
GameState rolled = JvmApi.withDice(state, List.of(1, 2, 4)); // Pawn, Knight, Rook
JvmApi.bestTurn(rolled, "greedy").ifPresentOrElse(
turn -> System.out.println("Best turn: " + turn.uci() + " score " + turn.score()),
() -> System.out.println("No legal turn for this roll: forced pass"));
}
}The facade's contract β legalTurns, evaluate, thinking-time budgets, game-over queries β is documented in the JVM API Reference.
- Licensed under AGPL-3.0-only (SPDX
AGPL-3.0-only; the GNU Affero General Public License version 3, without the "or any later version" option). - Contributions require signing the Contributor License Agreement (see CONTRIBUTING.md).
- Security vulnerability reports should follow SECURITY.md.