@datamoc/mw_games 0.19.0 → 0.22.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/CHANGELOG.md +111 -0
- package/dist/ai/index.d.ts +2 -2
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +1 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/search.d.ts +49 -0
- package/dist/ai/search.d.ts.map +1 -1
- package/dist/ai/search.js +48 -0
- package/dist/ai/search.js.map +1 -1
- package/dist/audio/Channels.d.ts +19 -0
- package/dist/audio/Channels.d.ts.map +1 -1
- package/dist/audio/Channels.js +33 -4
- package/dist/audio/Channels.js.map +1 -1
- package/dist/audio/LoopTags.d.ts +37 -0
- package/dist/audio/LoopTags.d.ts.map +1 -0
- package/dist/audio/LoopTags.js +116 -0
- package/dist/audio/LoopTags.js.map +1 -0
- package/dist/audio/Midi.d.ts +5 -0
- package/dist/audio/Midi.d.ts.map +1 -1
- package/dist/audio/Midi.js +9 -1
- package/dist/audio/Midi.js.map +1 -1
- package/dist/audio/MidiRender.d.ts +42 -4
- package/dist/audio/MidiRender.d.ts.map +1 -1
- package/dist/audio/MidiRender.js +286 -199
- package/dist/audio/MidiRender.js.map +1 -1
- package/dist/audio/index.d.ts +5 -3
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +2 -1
- package/dist/audio/index.js.map +1 -1
- package/dist/board/Engine.d.ts +33 -0
- package/dist/board/Engine.d.ts.map +1 -1
- package/dist/board/Engine.js +448 -1
- package/dist/board/Engine.js.map +1 -1
- package/dist/board/bitboard.d.ts +132 -0
- package/dist/board/bitboard.d.ts.map +1 -0
- package/dist/board/bitboard.js +495 -0
- package/dist/board/bitboard.js.map +1 -0
- package/dist/board/chess.d.ts +16 -0
- package/dist/board/chess.d.ts.map +1 -1
- package/dist/board/chess.js +43 -0
- package/dist/board/chess.js.map +1 -1
- package/dist/board/index.d.ts +11 -3
- package/dist/board/index.d.ts.map +1 -1
- package/dist/board/index.js +6 -2
- package/dist/board/index.js.map +1 -1
- package/dist/board/openings.d.ts +58 -0
- package/dist/board/openings.d.ts.map +1 -0
- package/dist/board/openings.js +45 -0
- package/dist/board/openings.js.map +1 -0
- package/dist/board/tablebase.d.ts +118 -0
- package/dist/board/tablebase.d.ts.map +1 -0
- package/dist/board/tablebase.js +414 -0
- package/dist/board/tablebase.js.map +1 -0
- package/dist/board/tourney.d.ts +90 -0
- package/dist/board/tourney.d.ts.map +1 -0
- package/dist/board/tourney.js +1013 -0
- package/dist/board/tourney.js.map +1 -0
- package/dist/core/JavaRandom.d.ts +55 -0
- package/dist/core/JavaRandom.d.ts.map +1 -0
- package/dist/core/JavaRandom.js +81 -0
- package/dist/core/JavaRandom.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/mw_games.global.js +123 -116
- package/dist/rpg/EventRunner.d.ts +7 -0
- package/dist/rpg/EventRunner.d.ts.map +1 -1
- package/dist/rpg/EventRunner.js +6 -0
- package/dist/rpg/EventRunner.js.map +1 -1
- package/dist/threads/index.d.ts +3 -0
- package/dist/threads/index.d.ts.map +1 -0
- package/dist/threads/index.js +2 -0
- package/dist/threads/index.js.map +1 -0
- package/dist/threads/spawn.d.ts +41 -0
- package/dist/threads/spawn.d.ts.map +1 -0
- package/dist/threads/spawn.js +143 -0
- package/dist/threads/spawn.js.map +1 -0
- package/dist/threads/worker.d.ts +51 -0
- package/dist/threads/worker.d.ts.map +1 -0
- package/dist/threads/worker.js +84 -0
- package/dist/threads/worker.js.map +1 -0
- package/dist/two-d/render/FogLayer.d.ts +68 -0
- package/dist/two-d/render/FogLayer.d.ts.map +1 -0
- package/dist/two-d/render/FogLayer.js +83 -0
- package/dist/two-d/render/FogLayer.js.map +1 -0
- package/dist/two-d/render/LiquidLayer.d.ts +62 -0
- package/dist/two-d/render/LiquidLayer.d.ts.map +1 -0
- package/dist/two-d/render/LiquidLayer.js +102 -0
- package/dist/two-d/render/LiquidLayer.js.map +1 -0
- package/dist/two-d/render/RpgmAutotile.d.ts +5 -0
- package/dist/two-d/render/RpgmAutotile.d.ts.map +1 -1
- package/dist/two-d/render/RpgmAutotile.js +4 -3
- package/dist/two-d/render/RpgmAutotile.js.map +1 -1
- package/dist/two-d/render/TileMap.d.ts +14 -2
- package/dist/two-d/render/TileMap.d.ts.map +1 -1
- package/dist/two-d/render/TileMap.js +32 -2
- package/dist/two-d/render/TileMap.js.map +1 -1
- package/dist/two-d/render/index.d.ts +4 -0
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +2 -0
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/two-d/ui/Label.d.ts.map +1 -1
- package/dist/two-d/ui/Label.js +11 -2
- package/dist/two-d/ui/Label.js.map +1 -1
- package/dist/two-d/ui/ListView.d.ts +24 -0
- package/dist/two-d/ui/ListView.d.ts.map +1 -1
- package/dist/two-d/ui/ListView.js +97 -4
- package/dist/two-d/ui/ListView.js.map +1 -1
- package/dist/two-d/ui/MessageLog.d.ts +62 -0
- package/dist/two-d/ui/MessageLog.d.ts.map +1 -0
- package/dist/two-d/ui/MessageLog.js +114 -0
- package/dist/two-d/ui/MessageLog.js.map +1 -0
- package/dist/two-d/ui/RadioGroup.d.ts +68 -0
- package/dist/two-d/ui/RadioGroup.d.ts.map +1 -0
- package/dist/two-d/ui/RadioGroup.js +177 -0
- package/dist/two-d/ui/RadioGroup.js.map +1 -0
- package/dist/two-d/ui/TextModel.d.ts +26 -1
- package/dist/two-d/ui/TextModel.d.ts.map +1 -1
- package/dist/two-d/ui/TextModel.js +56 -7
- package/dist/two-d/ui/TextModel.js.map +1 -1
- package/dist/two-d/ui/TextSharpness.d.ts +33 -0
- package/dist/two-d/ui/TextSharpness.d.ts.map +1 -0
- package/dist/two-d/ui/TextSharpness.js +56 -0
- package/dist/two-d/ui/TextSharpness.js.map +1 -0
- package/dist/two-d/ui/index.d.ts +5 -0
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +3 -0
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +19 -2
- package/sbom.cdx.json +54 -28
- package/tools/build-tablebases.d.mts +22 -0
- package/tools/build-tablebases.mjs +549 -0
- package/tools/compile-openings.d.mts +20 -0
- package/tools/compile-openings.mjs +130 -0
- package/tools/compress-dist.d.mts +8 -0
- package/tools/compress-dist.mjs +76 -30
- package/tools/play-uci.d.mts +26 -0
- package/tools/play-uci.mjs +194 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
const EXTRA_LETTER = { queen: 'Q', rook: 'R', bishop: 'B', knight: 'N' };
|
|
2
|
+
const LETTER_EXTRA = { Q: 'queen', R: 'rook', B: 'bishop', N: 'knight' };
|
|
3
|
+
const KIND_INDEX = { pawn: 0, knight: 1, bishop: 2, rook: 3, queen: 4, king: 5 };
|
|
4
|
+
/**
|
|
5
|
+
* The canonical id for white extras: strongest piece first, so `['bishop',
|
|
6
|
+
* 'queen']` and `['queen', 'bishop']` name the same `KQBK` ending.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { tablebaseId } from '@datamoc/mw_games/board';
|
|
11
|
+
*
|
|
12
|
+
* console.log(tablebaseId(['bishop', 'queen'])); // 'KQBK'
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function tablebaseId(white) {
|
|
16
|
+
const order = { queen: 0, rook: 1, bishop: 2, knight: 3 };
|
|
17
|
+
return `K${white
|
|
18
|
+
.slice()
|
|
19
|
+
.sort((a, b) => order[a] - order[b])
|
|
20
|
+
.map((kind) => EXTRA_LETTER[kind])
|
|
21
|
+
.join('')}K`;
|
|
22
|
+
}
|
|
23
|
+
const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
24
|
+
function base64Encode(raw) {
|
|
25
|
+
let out = '';
|
|
26
|
+
for (let i = 0; i < raw.length; i += 3) {
|
|
27
|
+
const a = raw[i];
|
|
28
|
+
const b = i + 1 < raw.length ? raw[i + 1] : 0;
|
|
29
|
+
const c = i + 2 < raw.length ? raw[i + 2] : 0;
|
|
30
|
+
out += BASE64[a >> 2] + BASE64[((a & 3) << 4) | (b >> 4)];
|
|
31
|
+
out += i + 1 < raw.length ? BASE64[((b & 15) << 2) | (c >> 6)] : '=';
|
|
32
|
+
out += i + 2 < raw.length ? BASE64[c & 63] : '=';
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function base64Decode(code) {
|
|
37
|
+
if (code.length % 4 !== 0)
|
|
38
|
+
throw new Error('tablebase data is not base64: length is not a multiple of 4');
|
|
39
|
+
const values = new Array(code.length);
|
|
40
|
+
for (let i = 0; i < code.length; i++) {
|
|
41
|
+
if (code[i] === '=') {
|
|
42
|
+
values[i] = -1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const value = BASE64.indexOf(code[i]);
|
|
46
|
+
if (value === -1)
|
|
47
|
+
throw new Error(`tablebase data is not base64: ${code[i]}`);
|
|
48
|
+
values[i] = value;
|
|
49
|
+
}
|
|
50
|
+
const out = [];
|
|
51
|
+
for (let i = 0; i < values.length; i += 4) {
|
|
52
|
+
const [a, b, c, d] = [values[i], values[i + 1], values[i + 2], values[i + 3]];
|
|
53
|
+
if (a === -1 || b === -1)
|
|
54
|
+
throw new Error('tablebase data is not base64: padding inside a quantum');
|
|
55
|
+
out.push((a << 2) | (b >> 4));
|
|
56
|
+
if (c !== -1)
|
|
57
|
+
out.push(((b & 15) << 4) | (c >> 2));
|
|
58
|
+
if (d !== -1)
|
|
59
|
+
out.push(((c & 3) << 6) | d);
|
|
60
|
+
}
|
|
61
|
+
return new Uint8Array(out);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Canonical Huffman plus base64, the game decodes with this same
|
|
65
|
+
* dependency-free code. Two dictionary schemes were tried first and both lost
|
|
66
|
+
* to the data: run-length encoding collapsed because a solved ending is a fine
|
|
67
|
+
* win/draw/loss mosaic rather than broad regions, and LZ77 barely beat raw
|
|
68
|
+
* size on the 4-piece mosaics while tripping over its own match flags. Huffman
|
|
69
|
+
* matches the actual skew (draws dominate, distances cluster near zero) with a
|
|
70
|
+
* decoder a reader can hold in their head.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { huffDecode, huffEncode } from '@datamoc/mw_games/board';
|
|
75
|
+
*
|
|
76
|
+
* console.log(huffDecode(huffEncode(new Uint8Array([2, 2, 2, 3])))); // Uint8Array([2, 2, 2, 3])
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function huffEncode(raw) {
|
|
80
|
+
const counts = new Array(256).fill(0);
|
|
81
|
+
for (const byte of raw)
|
|
82
|
+
counts[byte]++;
|
|
83
|
+
const symbols = counts.map((count, symbol) => ({ count, symbol })).filter((entry) => entry.count > 0);
|
|
84
|
+
const header = [1, symbols.length];
|
|
85
|
+
if (symbols.length === 0)
|
|
86
|
+
return base64Encode(new Uint8Array([1, 0, 0, 0, 0, 0]));
|
|
87
|
+
if (symbols.length === 1) {
|
|
88
|
+
header.push(symbols[0].symbol, 0);
|
|
89
|
+
const packed = new Uint8Array(header.length + 4);
|
|
90
|
+
packed.set(header, 0);
|
|
91
|
+
packed[header.length] = raw.length & 255;
|
|
92
|
+
packed[header.length + 1] = (raw.length >> 8) & 255;
|
|
93
|
+
packed[header.length + 2] = (raw.length >> 16) & 255;
|
|
94
|
+
packed[header.length + 3] = (raw.length >> 24) & 255;
|
|
95
|
+
return base64Encode(packed);
|
|
96
|
+
}
|
|
97
|
+
const lengths = huffmanLengths(symbols.map((entry) => entry.count));
|
|
98
|
+
const ordered = symbols
|
|
99
|
+
.map((entry, i) => ({ symbol: entry.symbol, length: lengths[i] }))
|
|
100
|
+
.sort((a, b) => a.symbol - b.symbol);
|
|
101
|
+
for (const entry of ordered)
|
|
102
|
+
header.push(entry.symbol);
|
|
103
|
+
for (const entry of ordered)
|
|
104
|
+
header.push(entry.length);
|
|
105
|
+
const codes = canonicalCodes(ordered);
|
|
106
|
+
const table = new Map();
|
|
107
|
+
for (let i = 0; i < ordered.length; i++)
|
|
108
|
+
table.set(ordered[i].symbol, codes[i]);
|
|
109
|
+
let totalBits = 0;
|
|
110
|
+
for (const entry of symbols)
|
|
111
|
+
totalBits += entry.count * table.get(entry.symbol).length;
|
|
112
|
+
const bytes = new Uint8Array(header.length + 4 + Math.ceil(totalBits / 8));
|
|
113
|
+
bytes.set(header, 0);
|
|
114
|
+
bytes[header.length] = raw.length & 255;
|
|
115
|
+
bytes[header.length + 1] = (raw.length >> 8) & 255;
|
|
116
|
+
bytes[header.length + 2] = (raw.length >> 16) & 255;
|
|
117
|
+
bytes[header.length + 3] = (raw.length >> 24) & 255;
|
|
118
|
+
let bit = 0;
|
|
119
|
+
const firstDataByte = header.length + 4;
|
|
120
|
+
for (const byte of raw) {
|
|
121
|
+
const entry = table.get(byte);
|
|
122
|
+
for (let k = entry.length - 1; k >= 0; k--) {
|
|
123
|
+
if ((entry.code >> k) & 1)
|
|
124
|
+
bytes[firstDataByte + (bit >> 3)] |= 1 << (7 - (bit & 7));
|
|
125
|
+
bit++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return base64Encode(bytes);
|
|
129
|
+
}
|
|
130
|
+
/** code lengths from symbol counts: repeatedly merge the two smallest */
|
|
131
|
+
function huffmanLengths(counts) {
|
|
132
|
+
const n = counts.length;
|
|
133
|
+
if (n === 0)
|
|
134
|
+
return [];
|
|
135
|
+
const weights = counts.slice();
|
|
136
|
+
const lengths = new Array(n).fill(0);
|
|
137
|
+
const active = counts.map((_, i) => i);
|
|
138
|
+
const mergeOrder = [];
|
|
139
|
+
while (active.length > 1) {
|
|
140
|
+
active.sort((a, b) => weights[a] - weights[b]);
|
|
141
|
+
const a = active.shift();
|
|
142
|
+
const b = active.shift();
|
|
143
|
+
mergeOrder.push([a, b]);
|
|
144
|
+
weights[a] += weights[b];
|
|
145
|
+
weights[b] = -1;
|
|
146
|
+
active.push(a);
|
|
147
|
+
}
|
|
148
|
+
for (let i = mergeOrder.length - 1; i >= 0; i--) {
|
|
149
|
+
const [a, b] = mergeOrder[i];
|
|
150
|
+
lengths[b] = lengths[a] + 1;
|
|
151
|
+
lengths[a]++;
|
|
152
|
+
}
|
|
153
|
+
if (lengths.some((length) => length > 32))
|
|
154
|
+
throw new Error('tablebase Huffman code too deep');
|
|
155
|
+
return lengths;
|
|
156
|
+
}
|
|
157
|
+
/** canonical codes from (symbol, length) sorted by symbol: counted, not stored */
|
|
158
|
+
function canonicalCodes(ordered) {
|
|
159
|
+
const byLength = ordered.slice().sort((a, b) => a.length - b.length || a.symbol - b.symbol);
|
|
160
|
+
let code = 0;
|
|
161
|
+
let lastLength = byLength[0].length;
|
|
162
|
+
const assigned = new Map();
|
|
163
|
+
for (const entry of byLength) {
|
|
164
|
+
code <<= entry.length - lastLength;
|
|
165
|
+
assigned.set(entry.symbol, { code, length: entry.length });
|
|
166
|
+
code++;
|
|
167
|
+
lastLength = entry.length;
|
|
168
|
+
}
|
|
169
|
+
return ordered.map((entry) => assigned.get(entry.symbol));
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The inverse of `huffEncode`: throws on malformed input rather than guessing,
|
|
173
|
+
* because a corrupt table must fail the load, never misprobe. The symbol count
|
|
174
|
+
* in the header must match the decoded symbols exactly, so truncation fails
|
|
175
|
+
* here instead of probing short.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import { huffDecode, huffEncode } from '@datamoc/mw_games/board';
|
|
180
|
+
*
|
|
181
|
+
* console.log(huffDecode(huffEncode(new Uint8Array([2, 2])))); // Uint8Array([2, 2])
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function huffDecode(code) {
|
|
185
|
+
const bytes = base64Decode(code);
|
|
186
|
+
if (bytes.length < 2)
|
|
187
|
+
throw new Error('tablebase data holds no header');
|
|
188
|
+
if (bytes[0] !== 1)
|
|
189
|
+
throw new Error(`tablebase data version ${bytes[0]} is not 1`);
|
|
190
|
+
const nSymbols = bytes[1];
|
|
191
|
+
if (2 + 2 * nSymbols > bytes.length)
|
|
192
|
+
throw new Error('tablebase data ends inside its header');
|
|
193
|
+
const symbols = [];
|
|
194
|
+
const lengths = [];
|
|
195
|
+
for (let i = 0; i < nSymbols; i++)
|
|
196
|
+
symbols.push(bytes[2 + i]);
|
|
197
|
+
for (let i = 0; i < nSymbols; i++)
|
|
198
|
+
lengths.push(bytes[2 + nSymbols + i]);
|
|
199
|
+
const at = 2 + 2 * nSymbols;
|
|
200
|
+
if (nSymbols === 0) {
|
|
201
|
+
if (at + 4 !== bytes.length)
|
|
202
|
+
throw new Error('tablebase data trails its empty header');
|
|
203
|
+
return new Uint8Array(0);
|
|
204
|
+
}
|
|
205
|
+
if (nSymbols === 1) {
|
|
206
|
+
if (at + 4 !== bytes.length)
|
|
207
|
+
throw new Error('tablebase data trails its single-symbol header');
|
|
208
|
+
const total = bytes[at] | (bytes[at + 1] << 8) | (bytes[at + 2] << 16) | (bytes[at + 3] << 24);
|
|
209
|
+
return new Uint8Array(total).fill(symbols[0]);
|
|
210
|
+
}
|
|
211
|
+
if (at + 4 > bytes.length)
|
|
212
|
+
throw new Error('tablebase data ends before its count');
|
|
213
|
+
const total = bytes[at] | (bytes[at + 1] << 8) | (bytes[at + 2] << 16) | (bytes[at + 3] << 24);
|
|
214
|
+
const ordered = symbols.map((symbol, i) => ({ symbol, length: lengths[i] }));
|
|
215
|
+
const codes = canonicalCodes(ordered);
|
|
216
|
+
const root = {};
|
|
217
|
+
for (let i = 0; i < ordered.length; i++) {
|
|
218
|
+
let node = root;
|
|
219
|
+
for (let k = codes[i].length - 1; k >= 0; k--) {
|
|
220
|
+
const bit = (codes[i].code >> k) & 1;
|
|
221
|
+
if (k === 0) {
|
|
222
|
+
if (bit)
|
|
223
|
+
node.one = { symbol: ordered[i].symbol };
|
|
224
|
+
else
|
|
225
|
+
node.zero = { symbol: ordered[i].symbol };
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
if (bit)
|
|
229
|
+
node.one = node.one ?? {};
|
|
230
|
+
else
|
|
231
|
+
node.zero = node.zero ?? {};
|
|
232
|
+
node = (bit ? node.one : node.zero);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const out = new Uint8Array(total);
|
|
237
|
+
let produced = 0;
|
|
238
|
+
let bit = 0;
|
|
239
|
+
const firstDataByte = at + 4;
|
|
240
|
+
const totalBits = (bytes.length - firstDataByte) * 8;
|
|
241
|
+
while (produced < total) {
|
|
242
|
+
if (bit >= totalBits)
|
|
243
|
+
throw new Error('tablebase data ends before its count');
|
|
244
|
+
let node = root;
|
|
245
|
+
for (;;) {
|
|
246
|
+
const byte = bytes[firstDataByte + (bit >> 3)];
|
|
247
|
+
const value = (byte >> (7 - (bit & 7))) & 1;
|
|
248
|
+
bit++;
|
|
249
|
+
node = (value ? node.one : node.zero);
|
|
250
|
+
if (!node)
|
|
251
|
+
throw new Error('tablebase data walks off its Huffman tree');
|
|
252
|
+
if (node.symbol !== undefined)
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
out[produced++] = node.symbol;
|
|
256
|
+
}
|
|
257
|
+
for (; bit < totalBits; bit++) {
|
|
258
|
+
const byte = bytes[firstDataByte + (bit >> 3)];
|
|
259
|
+
if ((byte >> (7 - (bit & 7))) & 1)
|
|
260
|
+
throw new Error('tablebase data does not end in zero padding');
|
|
261
|
+
}
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
function huffDecodeU16(code) {
|
|
265
|
+
const bytes = huffDecode(code);
|
|
266
|
+
if (bytes.length % 2 !== 0)
|
|
267
|
+
throw new Error('tablebase distances are not byte pairs');
|
|
268
|
+
const out = new Uint16Array(bytes.length / 2);
|
|
269
|
+
for (let i = 0; i < out.length; i++)
|
|
270
|
+
out[i] = bytes[2 * i] | (bytes[2 * i + 1] << 8);
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Loads a checked-in ending file into probeable arrays: validates the id against
|
|
275
|
+
* its extras, the position count against the piece count, and both payloads
|
|
276
|
+
* against the count, so a truncated artifact fails here with its ending named.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* import { loadTablebaseEnding } from '@datamoc/mw_games/board';
|
|
281
|
+
*
|
|
282
|
+
* const ending = loadTablebaseEnding({ version: 1, id: 'KBK', white: ['bishop'], positions: 2, wdl: 'AgEC', dtm: 'AAQAAQ' });
|
|
283
|
+
* console.log(ending.id); // 'KBK'
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
export function loadTablebaseEnding(file) {
|
|
287
|
+
if (file.version !== 1)
|
|
288
|
+
throw new Error(`${file.id}: unknown tablebase version ${String(file.version)}`);
|
|
289
|
+
if (file.id !== tablebaseId(file.white))
|
|
290
|
+
throw new Error(`${file.id}: id does not match its extras`);
|
|
291
|
+
for (const kind of file.white) {
|
|
292
|
+
if (!LETTER_EXTRA[EXTRA_LETTER[kind]])
|
|
293
|
+
throw new Error(`${file.id}: not a tablebase piece: ${String(kind)}`);
|
|
294
|
+
}
|
|
295
|
+
const pieces = 2 + file.white.length;
|
|
296
|
+
let positions = 1;
|
|
297
|
+
for (let i = 0; i < pieces; i++)
|
|
298
|
+
positions *= 64;
|
|
299
|
+
positions *= 2;
|
|
300
|
+
if (file.positions !== positions)
|
|
301
|
+
throw new Error(`${file.id}: claims ${file.positions} positions, holds ${positions}`);
|
|
302
|
+
const wdl = huffDecode(file.wdl);
|
|
303
|
+
if (wdl.length !== positions)
|
|
304
|
+
throw new Error(`${file.id}: WDL decodes to ${wdl.length} positions, needs ${positions}`);
|
|
305
|
+
const dtm = huffDecodeU16(file.dtm);
|
|
306
|
+
if (dtm.length !== positions)
|
|
307
|
+
throw new Error(`${file.id}: distances decode to ${dtm.length} positions, need ${positions}`);
|
|
308
|
+
const strength = { queen: 0, rook: 1, bishop: 2, knight: 3 };
|
|
309
|
+
return {
|
|
310
|
+
id: file.id,
|
|
311
|
+
extras: file.white
|
|
312
|
+
.slice()
|
|
313
|
+
.sort((a, b) => strength[a] - strength[b])
|
|
314
|
+
.map((kind) => KIND_INDEX[kind]),
|
|
315
|
+
positions,
|
|
316
|
+
wdl,
|
|
317
|
+
dtm,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function placedPieces(state) {
|
|
321
|
+
if ('pieces' in state) {
|
|
322
|
+
const out = [];
|
|
323
|
+
for (let i = 0; i < 12; i++) {
|
|
324
|
+
let bb = state.pieces[i];
|
|
325
|
+
while (bb) {
|
|
326
|
+
const single = bb & -bb;
|
|
327
|
+
out.push({ kind: i % 6, side: i < 6 ? 'white' : 'black', square: Math.log2(Number(single)) });
|
|
328
|
+
bb ^= single;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return out;
|
|
332
|
+
}
|
|
333
|
+
const out = [];
|
|
334
|
+
state.board.forEach((piece, square) => {
|
|
335
|
+
if (piece)
|
|
336
|
+
out.push({ kind: KIND_INDEX[piece.kind], side: piece.side, square });
|
|
337
|
+
});
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
function castlingRights(state) {
|
|
341
|
+
if ('pieces' in state)
|
|
342
|
+
return state.castling !== 0;
|
|
343
|
+
const rights = state.castling;
|
|
344
|
+
return rights.whiteKingside || rights.whiteQueenside || rights.blackKingside || rights.blackQueenside;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Probes loaded endings for an exact position: its WDL outcome from the side to
|
|
348
|
+
* move's view with the distance, fifty-move-adjudicated against `halfmove` (a win
|
|
349
|
+
* too far to force in time comes back a draw, and likewise a distant loss).
|
|
350
|
+
* Pure and total: anything outside the shipped scope - pawns, rights, black
|
|
351
|
+
* extras, bare kings, an ending the game never loaded - is a miss (`null`).
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```ts
|
|
355
|
+
* import { probeTablebase, startingChess } from '@datamoc/mw_games/board';
|
|
356
|
+
*
|
|
357
|
+
* console.log(probeTablebase({}, startingChess())); // null - no endings loaded, never an error
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
export function probeTablebase(loaded, state, halfmove = 0) {
|
|
361
|
+
if (!Number.isInteger(halfmove) || halfmove < 0)
|
|
362
|
+
throw new RangeError('halfmove must be a non-negative integer');
|
|
363
|
+
const pieces = placedPieces(state);
|
|
364
|
+
const whiteKings = pieces.filter((piece) => piece.kind === 5 && piece.side === 'white');
|
|
365
|
+
const blackKings = pieces.filter((piece) => piece.kind === 5 && piece.side === 'black');
|
|
366
|
+
if (whiteKings.length !== 1 || blackKings.length !== 1)
|
|
367
|
+
return null;
|
|
368
|
+
if (pieces.some((piece) => piece.kind === 0))
|
|
369
|
+
return null;
|
|
370
|
+
if (pieces.some((piece) => piece.kind !== 5 && piece.side === 'black'))
|
|
371
|
+
return null;
|
|
372
|
+
if (castlingRights(state))
|
|
373
|
+
return null;
|
|
374
|
+
const extras = pieces
|
|
375
|
+
.filter((piece) => piece.kind !== 5)
|
|
376
|
+
.sort((a, b) => b.kind - a.kind)
|
|
377
|
+
.map((piece) => piece.kind);
|
|
378
|
+
if (!extras.length)
|
|
379
|
+
return null;
|
|
380
|
+
const order = { 4: 'Q', 3: 'R', 2: 'B', 1: 'N' };
|
|
381
|
+
const id = `K${extras.map((kind) => order[kind]).join('')}K`;
|
|
382
|
+
const ending = loaded[id];
|
|
383
|
+
if (!ending)
|
|
384
|
+
return null;
|
|
385
|
+
const whiteKing = pieces.find((piece) => piece.kind === 5 && piece.side === 'white').square;
|
|
386
|
+
const blackKing = pieces.find((piece) => piece.kind === 5 && piece.side === 'black').square;
|
|
387
|
+
const extraSquares = extras.map((kind, i) => {
|
|
388
|
+
const candidates = pieces.filter((piece) => piece.kind === kind && piece.side === 'white').map((p) => p.square);
|
|
389
|
+
return candidates.sort((a, b) => a - b)[countBefore(extras, kind, i)];
|
|
390
|
+
});
|
|
391
|
+
let index = whiteKing;
|
|
392
|
+
for (const square of extraSquares)
|
|
393
|
+
index = index * 64 + square;
|
|
394
|
+
index = index * 64 + blackKing;
|
|
395
|
+
index = index * 2 + (state.turn === 'black' ? 1 : 0);
|
|
396
|
+
const value = ending.wdl[index];
|
|
397
|
+
if (value === 0)
|
|
398
|
+
return null;
|
|
399
|
+
const dtm = ending.dtm[index];
|
|
400
|
+
let outcome = value === 3 ? 'win' : value === 1 ? 'loss' : 'draw';
|
|
401
|
+
if (outcome !== 'draw' && dtm > 100 - halfmove)
|
|
402
|
+
outcome = 'draw';
|
|
403
|
+
return { outcome, dtm };
|
|
404
|
+
}
|
|
405
|
+
/** which same-kind extra this is: the nth occurrence takes the nth square */
|
|
406
|
+
function countBefore(extras, kind, upto) {
|
|
407
|
+
let seen = 0;
|
|
408
|
+
for (let i = 0; i < upto; i++) {
|
|
409
|
+
if (extras[i] === kind)
|
|
410
|
+
seen++;
|
|
411
|
+
}
|
|
412
|
+
return seen;
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=tablebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tablebase.js","sourceRoot":"","sources":["../../src/board/tablebase.ts"],"names":[],"mappings":"AAmDA,MAAM,YAAY,GAAmC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AACzG,MAAM,YAAY,GAAmC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;AACzG,MAAM,UAAU,GAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAEzG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IAClD,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC1D,OAAO,IAAI,KAAK;SACd,KAAK,EAAE;SACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;SACnC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;SACjC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;AACf,CAAC;AAED,MAAM,MAAM,GAAG,kEAAkE,CAAC;AAElF,SAAS,YAAY,CAAC,GAAe;IACpC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,GAAG,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACrE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IACjC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC1G,MAAM,MAAM,GAAG,IAAI,KAAK,CAAS,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACf,SAAS;QACV,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9E,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACpG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,UAAU,CAAC,GAAe;IACzC,MAAM,MAAM,GAAG,IAAI,KAAK,CAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,GAAG;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACtG,MAAM,MAAM,GAAa,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;QACrD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,OAAO;SACrB,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACjE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvD,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4C,CAAC;IAClE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,SAAS,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC,MAAM,CAAC;IACxF,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3E,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;IACxC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;IACnD,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;IACpD,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;IACpD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC;gBAAE,KAAK,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACrF,GAAG,EAAE,CAAC;QACP,CAAC;IACF,CAAC;IACD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,yEAAyE;AACzE,SAAS,cAAc,CAAC,MAAgB;IACvC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,KAAK,CAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,EAAG,CAAC;QAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,EAAG,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACd,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC9F,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,SAAS,cAAc,CAAC,OAAkD;IACzE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA4C,CAAC;IACrE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAK,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;QACnC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,IAAI,EAAE,CAAC;QACP,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACxE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACnF,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,GAAG,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;IAC5B,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACpB,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACvF,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACpB,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC/F,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/F,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAMtC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACb,IAAI,GAAG;oBAAE,IAAI,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;;oBAC7C,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACP,IAAI,GAAG;oBAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;;oBAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;gBACjC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAa,CAAC;YACjD,CAAC;QACF,CAAC;IACF,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,MAAM,aAAa,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACrD,OAAO,QAAQ,GAAG,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,IAAI,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC9E,IAAI,IAAI,GAAa,IAAI,CAAC;QAC1B,SAAS,CAAC;YACT,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC5C,GAAG,EAAE,CAAC;YACN,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAgB,CAAC;YACrD,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;YACxE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM;QACtC,CAAC;QACD,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,GAAG,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IAClC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrF,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAqB;IACxD,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,+BAA+B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzG,IAAI,IAAI,CAAC,EAAE,KAAK,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,gCAAgC,CAAC,CAAC;IACrG,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,4BAA4B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9G,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACrC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE;QAAE,SAAS,IAAI,EAAE,CAAC;IACjD,SAAS,IAAI,CAAC,CAAC;IACf,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;QAC/B,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,YAAY,IAAI,CAAC,SAAS,qBAAqB,SAAS,EAAE,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,oBAAoB,GAAG,CAAC,MAAM,qBAAqB,SAAS,EAAE,CAAC,CAAC;IAC3F,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,yBAAyB,GAAG,CAAC,MAAM,oBAAoB,SAAS,EAAE,CAAC,CAAC;IAC/F,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC7D,OAAO;QACN,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,MAAM,EAAE,IAAI,CAAC,KAAK;aAChB,KAAK,EAAE;aACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;aACzC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACjC,SAAS;QACT,GAAG;QACH,GAAG;KACH,CAAC;AACH,CAAC;AAQD,SAAS,YAAY,CAAC,KAAiC;IACtD,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,GAAG,GAAkB,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,OAAO,EAAE,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;gBACxB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9F,EAAE,IAAI,MAAM,CAAC;YACd,CAAC;QACF,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,cAAc,CAAC,KAAiC;IACxD,IAAI,QAAQ,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC9B,OAAO,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,cAAc,CAAC;AACvG,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC7B,MAAoC,EACpC,KAAiC,EACjC,QAAQ,GAAG,CAAC;IAEZ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,yCAAyC,CAAC,CAAC;IACjH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACxF,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACxF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACpF,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;SACnC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;SAC/B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAA4B,CAAC;IAC3E,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAE,CAAC,MAAM,CAAC;IAC7F,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAE,CAAC,MAAM,CAAC;IAC7F,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChH,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,GAAG,SAAS,CAAC;IACtB,KAAK,MAAM,MAAM,IAAI,YAAY;QAAE,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,MAAM,CAAC;IAC/D,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,SAAS,CAAC;IAC/B,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,OAAO,GAA8B,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7F,IAAI,OAAO,KAAK,MAAM,IAAI,GAAG,GAAG,GAAG,GAAG,QAAQ;QAAE,OAAO,GAAG,MAAM,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACzB,CAAC;AAED,6EAA6E;AAE7E,SAAS,WAAW,CAAC,MAAgB,EAAE,IAAY,EAAE,IAAY;IAChE,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,IAAI,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { BitboardMove, BitboardState } from './bitboard.ts';
|
|
2
|
+
import type { ChessState } from './chess.ts';
|
|
3
|
+
export interface TourneyOptions {
|
|
4
|
+
/** plies to search; the iterative deepener completes 1..depth while the budget lasts */
|
|
5
|
+
depth?: number;
|
|
6
|
+
/** hard cap on visited positions; the best completed iteration is returned past it */
|
|
7
|
+
maxNodes?: number;
|
|
8
|
+
/** soft wall-clock budget in milliseconds; checked every few thousand nodes */
|
|
9
|
+
timeMs?: number;
|
|
10
|
+
/** aborting stops the search at the next check and keeps the best completed iteration */
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
}
|
|
13
|
+
export interface TourneyAsyncOptions extends TourneyOptions {
|
|
14
|
+
/** root moves searched at once (default: hardware threads capped at 8, else 4) */
|
|
15
|
+
jobs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface TourneyResult {
|
|
18
|
+
/** the move to play, null only with no legal moves */
|
|
19
|
+
move: BitboardMove | null;
|
|
20
|
+
/** centipawns from the side to move's view; mate scores near 100000, adjusted by distance */
|
|
21
|
+
score: number;
|
|
22
|
+
/** positions visited, quiescence included */
|
|
23
|
+
nodes: number;
|
|
24
|
+
/** the deepest fully completed iteration */
|
|
25
|
+
depth: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The tournament engine's serializable task: a full iterative-deepening search over a
|
|
29
|
+
* bitboard position, with nothing outside its own body.
|
|
30
|
+
*
|
|
31
|
+
* `threads.spawn` rehydrates this function in a worker with `new Function`, so it may
|
|
32
|
+
* not reference imports, module scope, or any outer binding: every rule it touches is
|
|
33
|
+
* nested inside it. The main-thread wrappers call this same function directly, so the
|
|
34
|
+
* two sides cannot diverge the way a copied worker body could.
|
|
35
|
+
*
|
|
36
|
+
* What it does, per Roadmap item 390 phase 1: negamax alpha-beta with principal
|
|
37
|
+
* variation search, null-move pruning, late-move reductions, iterative deepening with
|
|
38
|
+
* aspiration windows, a bounded transposition table over Zobrist keys, quiescence over
|
|
39
|
+
* captures and promotions, ordering by hash move then MVV-LVA captures then killers
|
|
40
|
+
* then history, and a classical material plus in-house piece-square evaluation.
|
|
41
|
+
* Positions are plain bitboard data, so they structured-clone into a worker untouched.
|
|
42
|
+
*
|
|
43
|
+
* Draws: stalemate, fifty moves, KvK/KBvK/KNvK dead material, and repetition along the
|
|
44
|
+
* search path all score 0. Repetition only sees the path from the searched position,
|
|
45
|
+
* not the game before it; mate scores prefer the faster mate.
|
|
46
|
+
*/
|
|
47
|
+
export declare function tourneyThink(position: BitboardState, options?: {
|
|
48
|
+
depth?: number;
|
|
49
|
+
maxNodes?: number;
|
|
50
|
+
timeMs?: number;
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}): TourneyResult;
|
|
53
|
+
/**
|
|
54
|
+
* Chooses a move with the tournament search: the same `tourneyThink` task the
|
|
55
|
+
* workers run, called directly, so one implementation serves both sides.
|
|
56
|
+
*
|
|
57
|
+
* This is the stronger engine beside `board/Engine`'s small deterministic one: the
|
|
58
|
+
* minigame path keeps the small search and never pays for this module. Scores are
|
|
59
|
+
* centipawns from the side to move's view; mate scores sit near 100000, adjusted so
|
|
60
|
+
* the faster mate scores higher.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { searchTourney, startingBitboard, tourneyThink } from '@datamoc/mw_games/board';
|
|
65
|
+
*
|
|
66
|
+
* const direct = tourneyThink(startingBitboard(), { depth: 1 });
|
|
67
|
+
* const result = searchTourney(startingBitboard(), { depth: 2 });
|
|
68
|
+
* console.log(direct.move !== null && result.move !== null); // true - the opening position always has legal moves
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function searchTourney(state: ChessState | BitboardState, options?: TourneyOptions): TourneyResult;
|
|
72
|
+
/**
|
|
73
|
+
* Chooses a move the way `searchTourney` does, but thinks on worker threads through
|
|
74
|
+
* `threads.spawn`, so a deep search does not drop the caller's frames. Each root move
|
|
75
|
+
* is a self-contained `tourneyThink` task over a structured-cloned bitboard, scored
|
|
76
|
+
* concurrently down a capped lane queue; the best child score from the opponent's
|
|
77
|
+
* view is the worst for us, so the root plays the move whose child scored lowest,
|
|
78
|
+
* with ties going to the earlier root move. An aborting signal rejects through
|
|
79
|
+
* `threads.spawn` and terminates the workers.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { searchTourneyAsync, startingBitboard } from '@datamoc/mw_games/board';
|
|
84
|
+
*
|
|
85
|
+
* const result = await searchTourneyAsync(startingBitboard(), { depth: 2 });
|
|
86
|
+
* console.log(result.move !== null); // true - the opening position always has legal moves
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function searchTourneyAsync(state: ChessState | BitboardState, options?: TourneyAsyncOptions): Promise<TourneyResult>;
|
|
90
|
+
//# sourceMappingURL=tourney.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tourney.d.ts","sourceRoot":"","sources":["../../src/board/tourney.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,WAAW,cAAc;IAC9B,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IAC1D,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC7B,sDAAsD;IACtD,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,6FAA6F;IAC7F,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC3B,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GACxF,aAAa,CAo0Bf;AAcD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CAO5G;AAuBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,UAAU,GAAG,aAAa,EACjC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
|