@fortemate/dicechess-engine-wasm 0.12.3 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -15
- package/dicechess-engine.d.ts +58 -1
- package/main.js +260 -225
- package/main.wasm +0 -0
- package/main.wasm.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ so importing both in the same application loads the shared half once.
|
|
|
27
27
|
|
|
28
28
|
| Import | What it gives you | What it loads |
|
|
29
29
|
| :--- | :--- | :--- |
|
|
30
|
-
| `@fortemate/dicechess-engine` | everything: `DiceChess`, `EngineFacade`, the bots, `getBestMove`, equity, doubling and draw decisions | 1,308,539 B (191,262 B gzipped) |
|
|
30
|
+
| `@fortemate/dicechess-engine` | everything: `DiceChess`, `EngineFacade`, the legal turn tree, the bots, `getBestMove`, equity, doubling and draw decisions | 1,308,539 B (191,262 B gzipped) |
|
|
31
31
|
| `@fortemate/dicechess-engine/rules` | the rules only: `getLegalUciMoves`, `generateMoves`, `applyMove`, `endTurn`, `perft`, `getPieceFromDice`, `canonicalKey` | 891,712 B (138,394 B gzipped) |
|
|
32
32
|
|
|
33
33
|
Use `/rules` wherever the application validates, applies and renders moves but never asks the engine
|
|
@@ -68,44 +68,61 @@ const legalMoves = DiceChess.getLegalUciMoves(dfen);
|
|
|
68
68
|
console.log("Legal moves in this turn:", legalMoves);
|
|
69
69
|
// e.g. ["e2e3", "e2e4", "b1c3", "b1a3", ...]
|
|
70
70
|
|
|
71
|
-
// 2.
|
|
72
|
-
//
|
|
71
|
+
// 2. Get every legal turn as a prefix tree of UCI micro-moves. A node without children is a
|
|
72
|
+
// complete turn. getLegalUciMoves judges each position in isolation, so a client that follows
|
|
73
|
+
// a turn one action at a time walks this tree instead of calling getLegalUciMoves again.
|
|
74
|
+
const turns = DiceChess.getLegalTurnTree(dfen);
|
|
75
|
+
console.log("Continuations of e2e4:", Object.keys(turns["e2e4"]));
|
|
76
|
+
// e.g. ["b1a3", "b1c3", "g1e2", "g1f3", "g1h3"]
|
|
77
|
+
|
|
78
|
+
// The dice a legal turn can still spend: pass the rolled DFEN and the moves played since, not the
|
|
79
|
+
// DFEN after them, because the turn is judged as a whole. A client can dim every other die.
|
|
80
|
+
console.log("Playable after e2e4:", DiceChess.getPlayableDice(dfen, ["e2e4"]));
|
|
81
|
+
// "N"
|
|
82
|
+
|
|
83
|
+
// 3. Apply a micro-move. applyMove preserves the active color (White), since a Dice Chess turn
|
|
84
|
+
// may consist of multiple micro-moves, and keeps the dice the move did not spend ("N" here).
|
|
73
85
|
// Arguments: (dfen, fromSquare, toSquare, optionalPromotionPiece)
|
|
74
86
|
const nextDfen = DiceChess.applyMove(dfen, "e2", "e4");
|
|
75
87
|
console.log("DFEN after micro-move:", nextDfen);
|
|
76
88
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
// Spend the knight die too: the turn ends at a leaf of the tree, here after e2e4 then g1f3.
|
|
90
|
+
const turnDfen = DiceChess.applyMove(nextDfen, "g1", "f3");
|
|
91
|
+
|
|
92
|
+
// 4. Explicitly end the turn when the player has exhausted their dice.
|
|
93
|
+
// This toggles the active color to Black, clears the dice pool (the full-move number advances
|
|
94
|
+
// only after Black's turn), and clears any stale en-passant targets from the previous turn.
|
|
95
|
+
const finalDfen = DiceChess.endTurn(turnDfen);
|
|
81
96
|
console.log("DFEN after ending turn:", finalDfen);
|
|
82
97
|
|
|
83
|
-
//
|
|
98
|
+
// 5. Discover available bots (search algorithms)
|
|
84
99
|
const bots = DiceChess.getAvailableBots();
|
|
85
100
|
console.log("Available bots:", bots);
|
|
86
101
|
// e.g. [ { id: 'random', name: 'Random', description: '...', difficulty: 1, isExperimental: false }, ... ]
|
|
87
102
|
|
|
88
|
-
//
|
|
103
|
+
// 6. Discover the built-in time-management policies.
|
|
89
104
|
const timePolicies = DiceChess.getAvailableTimePolicies();
|
|
90
105
|
console.log("Available time policies:", timePolicies);
|
|
91
106
|
// [ "empirical-v1", "legacy-linear-v1" ]
|
|
92
107
|
|
|
93
|
-
//
|
|
108
|
+
// 7. Compute the best sequence of micro-moves using the greedy bot search.
|
|
109
|
+
// The bot needs Black's roll: append the dice (lowercase for Black), here a Pawn and a Knight.
|
|
94
110
|
// Arguments: (dfen, optionalOptions)
|
|
95
|
-
const
|
|
111
|
+
const rolledDfen = `${finalDfen} pn`;
|
|
112
|
+
const botResult = DiceChess.getBestMove(rolledDfen, { algorithm: "greedy" });
|
|
96
113
|
console.log("Bot moves:", botResult.moves);
|
|
97
|
-
// e.g. [ { from: "
|
|
114
|
+
// e.g. [ { from: "b8", to: "c6" }, { from: "a7", to: "a5" } ]
|
|
98
115
|
|
|
99
116
|
// Clock-aware searches use empirical-v1 by default. Pass legacy-linear-v1 to
|
|
100
117
|
// reproduce the original allocation for rollback or an A/B comparison.
|
|
101
|
-
const timedResult = DiceChess.getBestMove(
|
|
118
|
+
const timedResult = DiceChess.getBestMove(rolledDfen, {
|
|
102
119
|
algorithm: "monte-carlo",
|
|
103
120
|
clock: { remainingMs: 180_000, incrementMs: 2_000, moveNumber: 8 },
|
|
104
121
|
timePolicy: "empirical-v1",
|
|
105
122
|
});
|
|
106
123
|
console.log("Effective budget (ms):", timedResult.budgetMs);
|
|
107
124
|
|
|
108
|
-
//
|
|
125
|
+
// 8. Doubling Cube & Draw Offers (New)
|
|
109
126
|
// Check if the bot wants to offer a double before its turn:
|
|
110
127
|
const shouldDouble = DiceChess.shouldBotOfferDouble(finalDfen, 1);
|
|
111
128
|
|
|
@@ -133,7 +150,7 @@ const acceptDraw = DiceChess.shouldBotAcceptDraw(finalDfen);
|
|
|
133
150
|
|
|
134
151
|
## API Reference & Documentation
|
|
135
152
|
|
|
136
|
-
* **[Interactive User & Developer Guide](https://fortemate.
|
|
153
|
+
* **[Interactive User & Developer Guide](https://fortemate.github.io/dicechess-engine/)**: Complete rules, architectural documentation, and live interactive visual catalogs.
|
|
137
154
|
* **[GitHub Repository](https://github.com/fortemate/dicechess-engine)**: Source code, issue tracker, and contribution guidelines.
|
|
138
155
|
|
|
139
156
|
---
|
package/dicechess-engine.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ export interface EngineFacadeApi {
|
|
|
13
13
|
getPieceTypeAt(dfen: string, square: string): number | undefined;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Applies a move to the given DFEN and returns the resulting state
|
|
16
|
+
* Applies a move to the given DFEN and returns the resulting state, keeping the dice the move
|
|
17
|
+
* did not spend (castling spends the king and the rook die) and, when the DFEN carries dice,
|
|
18
|
+
* refusing a move no die allows.
|
|
19
|
+
* Same as `DiceChess.applyMove`.
|
|
17
20
|
*/
|
|
18
21
|
applyMove(dfen: string, from: string, to: string, promotion?: string): string | undefined;
|
|
19
22
|
|
|
@@ -27,6 +30,20 @@ export interface EngineFacadeApi {
|
|
|
27
30
|
|
|
28
31
|
export const EngineFacade: EngineFacadeApi;
|
|
29
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Every legal turn of a rolled position as a prefix tree of UCI micro-moves, in the shape of
|
|
35
|
+
* dicechess-play-api's `MoveTree`, children in UCI order:
|
|
36
|
+
*
|
|
37
|
+
* { "e2e3": { "e3e4": {} }, "e2e4": { "e4e5": {} } }
|
|
38
|
+
*
|
|
39
|
+
* A node with no children is a complete legal turn, and every complete legal turn is such a leaf:
|
|
40
|
+
* a turn that captures the king ends there, and every other turn spends the most dice the roll
|
|
41
|
+
* allows. An empty object means the roll has no legal move.
|
|
42
|
+
*/
|
|
43
|
+
export interface MoveTree {
|
|
44
|
+
[uci: string]: MoveTree;
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
export type TimePolicyId = "empirical-v1" | "legacy-linear-v1";
|
|
31
48
|
|
|
32
49
|
export interface ClockStateOptions {
|
|
@@ -63,9 +80,44 @@ export interface DiceChessApi {
|
|
|
63
80
|
|
|
64
81
|
/**
|
|
65
82
|
* Returns all legal moves as a flat array of UCI strings (e.g., ["e2e4", "e7e8q"]).
|
|
83
|
+
* They are the legal first actions of a turn from this position, judged in isolation: asked
|
|
84
|
+
* again after each micro-move, the answer can admit actions the whole turn does not allow.
|
|
85
|
+
* Use `getLegalTurnTree` to follow a turn.
|
|
66
86
|
*/
|
|
67
87
|
getLegalUciMoves(dfen: string): string[];
|
|
68
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Returns every legal turn of the rolled position as a prefix tree of UCI micro-moves.
|
|
91
|
+
* Its first level equals `getLegalUciMoves(dfen)`. Deeper levels can be narrower than
|
|
92
|
+
* `getLegalUciMoves` asked again after each micro-move, so a client that follows a turn one
|
|
93
|
+
* action at a time walks this tree. Empty for an invalid DFEN, a DFEN without dice, or a roll
|
|
94
|
+
* with no legal move.
|
|
95
|
+
*/
|
|
96
|
+
getLegalTurnTree(dfen: string): MoveTree;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns the dice that a legal turn can still spend once `moves` have been played: those that
|
|
100
|
+
* at least one legal turn beginning with `moves` spends after them. A client can dim the other
|
|
101
|
+
* dice, which no turn left can use.
|
|
102
|
+
*
|
|
103
|
+
* The turn is judged as a whole, so pass the rolled DFEN at the start of the turn, as for
|
|
104
|
+
* `getLegalTurnTree`, and the UCI micro-moves played since, not the DFEN after them. `moves`
|
|
105
|
+
* default to none. In the start position with `QRN` this returns `"NR"`: only a knight can
|
|
106
|
+
* move first, but the rook can follow it.
|
|
107
|
+
*
|
|
108
|
+
* The dice come as the DFEN dice field writes them: ascending by face, in the case of the side
|
|
109
|
+
* to move, and a face repeated as often as the most dice showing it that one legal turn spends.
|
|
110
|
+
* The result is `""` when no legal turn continues: after a complete turn, a king capture
|
|
111
|
+
* included, and for a roll with no legal move or a DFEN without dice. It is `undefined` for an
|
|
112
|
+
* invalid DFEN, when `moves` is not an array of UCI strings, and when it is not the beginning
|
|
113
|
+
* of a legal turn.
|
|
114
|
+
*
|
|
115
|
+
* A client holding the tree needs the call only when the current node has children but no path
|
|
116
|
+
* below it has as many actions as there are dice left: an empty node means no die is playable,
|
|
117
|
+
* and a path as long as the dice left means every one of them is.
|
|
118
|
+
*/
|
|
119
|
+
getPlayableDice(dfen: string, moves?: string[]): string | undefined;
|
|
120
|
+
|
|
69
121
|
/**
|
|
70
122
|
* Executes perft (performance test) counting leaf nodes at given depth.
|
|
71
123
|
* @param dfen The position in DFEN notation.
|
|
@@ -119,6 +171,11 @@ export interface DiceChessApi {
|
|
|
119
171
|
|
|
120
172
|
/**
|
|
121
173
|
* Applies a move to the given DFEN and returns the resulting state.
|
|
174
|
+
* The result keeps the dice the move did not spend; castling spends the king and the rook die.
|
|
175
|
+
* Pass it back unchanged: while dice remain, appending dice to it yields an eight-field DFEN,
|
|
176
|
+
* which is rejected. `undefined` when the move is not pseudo-legal, when no die in the pool
|
|
177
|
+
* allows it, or when an argument is invalid. A position without dice, including the one
|
|
178
|
+
* returned once the last die is spent, accepts any pseudo-legal move.
|
|
122
179
|
* @param dfen The starting board state in DiceChess FEN notation.
|
|
123
180
|
* @param from The algebraic notation of the starting square.
|
|
124
181
|
* @param to The algebraic notation of the target square.
|