@slot-engine/core 0.2.0 → 0.2.2
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/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +109 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -31,6 +31,7 @@ function createPermanentFilePaths(basePath) {
|
|
|
31
31
|
`books_${mode}_chunk_${worker}-${chunk}.jsonl.zst`
|
|
32
32
|
),
|
|
33
33
|
booksCompressed: (mode) => path.join(basePath, "publish_files", `books_${mode}.jsonl.zst`),
|
|
34
|
+
booksUncompressed: (mode) => path.join(basePath, `books_${mode}.jsonl`),
|
|
34
35
|
lookupTable: (mode) => path.join(basePath, `lookUpTable_${mode}.csv`),
|
|
35
36
|
lookupTableIndex: (mode) => path.join(basePath, `lookUpTable_${mode}.index`),
|
|
36
37
|
lookupTableSegmented: (mode) => path.join(basePath, `lookUpTableSegmented_${mode}.csv`),
|
|
@@ -428,8 +429,18 @@ var Board = class {
|
|
|
428
429
|
* Used for triggering anticipation effects.
|
|
429
430
|
*/
|
|
430
431
|
anticipation;
|
|
432
|
+
/**
|
|
433
|
+
* The most recent stop positions for the reels.
|
|
434
|
+
*/
|
|
431
435
|
lastDrawnReelStops;
|
|
436
|
+
/**
|
|
437
|
+
* The reel set used in the most recent draw.
|
|
438
|
+
*/
|
|
432
439
|
lastUsedReels;
|
|
440
|
+
/**
|
|
441
|
+
* Indicates whether each reel is locked or not.
|
|
442
|
+
*/
|
|
443
|
+
reelsLocked;
|
|
433
444
|
constructor() {
|
|
434
445
|
this.reels = [];
|
|
435
446
|
this.paddingTop = [];
|
|
@@ -437,6 +448,7 @@ var Board = class {
|
|
|
437
448
|
this.anticipation = [];
|
|
438
449
|
this.lastDrawnReelStops = [];
|
|
439
450
|
this.lastUsedReels = [];
|
|
451
|
+
this.reelsLocked = [];
|
|
440
452
|
}
|
|
441
453
|
getSymbol(reelIndex, rowIndex) {
|
|
442
454
|
return this.reels[reelIndex]?.[rowIndex];
|
|
@@ -584,14 +596,19 @@ var Board = class {
|
|
|
584
596
|
return reelSet;
|
|
585
597
|
}
|
|
586
598
|
resetReels(opts) {
|
|
587
|
-
const
|
|
599
|
+
const { ctx, reelsAmount, reelsLocked } = opts;
|
|
600
|
+
const length = reelsAmount ?? ctx.services.game.getCurrentGameMode().reelsAmount;
|
|
588
601
|
this.reels = this.makeEmptyReels(opts);
|
|
589
602
|
this.anticipation = Array.from({ length }, () => false);
|
|
603
|
+
this.reelsLocked = reelsLocked ?? Array.from({ length }, () => false);
|
|
590
604
|
this.paddingTop = this.makeEmptyReels(opts);
|
|
591
605
|
this.paddingBottom = this.makeEmptyReels(opts);
|
|
592
606
|
}
|
|
593
607
|
drawBoardMixed(opts) {
|
|
594
|
-
this.resetReels(
|
|
608
|
+
this.resetReels({
|
|
609
|
+
...opts,
|
|
610
|
+
...this.reelsLocked.length && { reelsLocked: this.reelsLocked }
|
|
611
|
+
});
|
|
595
612
|
const reelsAmount = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
|
|
596
613
|
const symbolsPerReel = opts.symbolsPerReel ?? opts.ctx.services.game.getCurrentGameMode().symbolsPerReel;
|
|
597
614
|
const padSymbols = opts.padSymbols ?? opts.ctx.config.padSymbols;
|
|
@@ -620,6 +637,18 @@ var Board = class {
|
|
|
620
637
|
);
|
|
621
638
|
}
|
|
622
639
|
}
|
|
640
|
+
if (this.reelsLocked.some((locked) => locked) && this.lastDrawnReelStops.length == 0) {
|
|
641
|
+
throw new Error(
|
|
642
|
+
"Cannot draw board with locked reels before drawing it at least once."
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
if (this.reelsLocked.some((locked) => locked)) {
|
|
646
|
+
for (let ridx = 0; ridx < reelsAmount; ridx++) {
|
|
647
|
+
if (this.reelsLocked[ridx]) {
|
|
648
|
+
finalReelStops[ridx] = this.lastDrawnReelStops[ridx];
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
623
652
|
this.lastDrawnReelStops = finalReelStops.map((pos) => pos);
|
|
624
653
|
this.lastUsedReels = opts.reels;
|
|
625
654
|
for (let ridx = 0; ridx < reelsAmount; ridx++) {
|
|
@@ -781,6 +810,9 @@ var BoardService = class extends AbstractService {
|
|
|
781
810
|
getAnticipation() {
|
|
782
811
|
return this.board.anticipation;
|
|
783
812
|
}
|
|
813
|
+
getLockedReels() {
|
|
814
|
+
return this.board.reelsLocked;
|
|
815
|
+
}
|
|
784
816
|
/**
|
|
785
817
|
* Gets the symbol at the specified reel and row index.
|
|
786
818
|
*/
|
|
@@ -810,6 +842,12 @@ var BoardService = class extends AbstractService {
|
|
|
810
842
|
setAnticipationForReel(reelIndex, value) {
|
|
811
843
|
this.board.anticipation[reelIndex] = value;
|
|
812
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* Sets the locked state for a specific reel.
|
|
847
|
+
*/
|
|
848
|
+
setReelLocked(reelIndex, value) {
|
|
849
|
+
this.board.reelsLocked[reelIndex] = value;
|
|
850
|
+
}
|
|
813
851
|
/**
|
|
814
852
|
* Counts how many symbols matching the criteria are on a specific reel.
|
|
815
853
|
*/
|
|
@@ -1751,6 +1789,8 @@ var TerminalUi = class {
|
|
|
1751
1789
|
logs = [];
|
|
1752
1790
|
logScrollOffset = 0;
|
|
1753
1791
|
isScrolled = false;
|
|
1792
|
+
maxLogs = 500;
|
|
1793
|
+
totalLogs = 0;
|
|
1754
1794
|
minWidth = 50;
|
|
1755
1795
|
minHeight = 12;
|
|
1756
1796
|
isRendering = false;
|
|
@@ -1776,12 +1816,13 @@ var TerminalUi = class {
|
|
|
1776
1816
|
this.scrollDown();
|
|
1777
1817
|
} else if (key === "l") {
|
|
1778
1818
|
this.scrollToBottom();
|
|
1779
|
-
} else if (key === "") {
|
|
1819
|
+
} else if (key === "q" || key === "") {
|
|
1780
1820
|
this.stop();
|
|
1781
1821
|
process.exit(0);
|
|
1782
1822
|
}
|
|
1783
1823
|
};
|
|
1784
1824
|
process.stdout.on("resize", this.resizeHandler);
|
|
1825
|
+
process.on("SIGINT", this.sigintHandler);
|
|
1785
1826
|
}
|
|
1786
1827
|
get terminalWidth() {
|
|
1787
1828
|
return process.stdout.columns || 80;
|
|
@@ -1803,7 +1844,6 @@ var TerminalUi = class {
|
|
|
1803
1844
|
}
|
|
1804
1845
|
this.render();
|
|
1805
1846
|
this.renderInterval = setInterval(() => this.render(), 100);
|
|
1806
|
-
process.on("SIGINT", this.sigintHandler);
|
|
1807
1847
|
}
|
|
1808
1848
|
stop() {
|
|
1809
1849
|
if (this.renderInterval) {
|
|
@@ -1831,7 +1871,16 @@ var TerminalUi = class {
|
|
|
1831
1871
|
this.totalSims = opts.totalSims;
|
|
1832
1872
|
}
|
|
1833
1873
|
log(message) {
|
|
1834
|
-
this.logs.push({ i: this.
|
|
1874
|
+
this.logs.push({ i: this.totalLogs, m: message });
|
|
1875
|
+
this.totalLogs++;
|
|
1876
|
+
if (this.logs.length > this.maxLogs) {
|
|
1877
|
+
const excess = this.logs.length - this.maxLogs;
|
|
1878
|
+
this.logs.splice(0, excess);
|
|
1879
|
+
this.logScrollOffset = Math.min(
|
|
1880
|
+
this.logScrollOffset,
|
|
1881
|
+
Math.max(0, this.logs.length - this.getLogAreaHeight())
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1835
1884
|
if (!this.isScrolled) this.scrollToBottom();
|
|
1836
1885
|
}
|
|
1837
1886
|
scrollUp(lines = 1) {
|
|
@@ -1996,6 +2045,7 @@ var Simulation = class {
|
|
|
1996
2045
|
gameConfig;
|
|
1997
2046
|
simRunsAmount;
|
|
1998
2047
|
concurrency;
|
|
2048
|
+
makeUncompressedBooks;
|
|
1999
2049
|
debug = false;
|
|
2000
2050
|
actualSims = 0;
|
|
2001
2051
|
wallet = new Wallet();
|
|
@@ -2024,6 +2074,7 @@ var Simulation = class {
|
|
|
2024
2074
|
const { config, metadata } = createGameConfig(gameConfigOpts);
|
|
2025
2075
|
this.gameConfig = { ...config, ...metadata };
|
|
2026
2076
|
this.gameConfigOpts = gameConfigOpts;
|
|
2077
|
+
this.makeUncompressedBooks = opts.makeUncompressedBooks || false;
|
|
2027
2078
|
this.simRunsAmount = opts.simRunsAmount || {};
|
|
2028
2079
|
this.concurrency = (opts.concurrency || 6) >= 2 ? opts.concurrency || 6 : 2;
|
|
2029
2080
|
this.maxPendingSims = opts.maxPendingSims ?? 25;
|
|
@@ -2101,9 +2152,7 @@ var Simulation = class {
|
|
|
2101
2152
|
const startTime = Date.now();
|
|
2102
2153
|
statusMessage = `Simulating mode "${mode}" with ${this.simRunsAmount[mode]} runs.`;
|
|
2103
2154
|
this.tui?.log(statusMessage);
|
|
2104
|
-
|
|
2105
|
-
this.socket.emit("simulationStatus", statusMessage);
|
|
2106
|
-
}
|
|
2155
|
+
this.sendSimulationStatus(statusMessage);
|
|
2107
2156
|
const runs = this.simRunsAmount[mode] || 0;
|
|
2108
2157
|
if (runs <= 0) continue;
|
|
2109
2158
|
if (!configuredGameModes.includes(mode)) {
|
|
@@ -2140,9 +2189,7 @@ var Simulation = class {
|
|
|
2140
2189
|
createDirIfNotExists(this.PATHS.publishFiles);
|
|
2141
2190
|
statusMessage = `Writing final files for game mode "${mode}". This may take a while...`;
|
|
2142
2191
|
this.tui?.log(statusMessage);
|
|
2143
|
-
|
|
2144
|
-
this.socket.emit("simulationStatus", statusMessage);
|
|
2145
|
-
}
|
|
2192
|
+
this.sendSimulationStatus(statusMessage);
|
|
2146
2193
|
writeFile(
|
|
2147
2194
|
this.PATHS.booksIndexMeta(mode),
|
|
2148
2195
|
JSON.stringify(
|
|
@@ -2197,13 +2244,43 @@ var Simulation = class {
|
|
|
2197
2244
|
}
|
|
2198
2245
|
await this.writeRecords(mode);
|
|
2199
2246
|
this.writeIndexJson();
|
|
2247
|
+
if (this.makeUncompressedBooks) {
|
|
2248
|
+
statusMessage = `Creating decompressed book file for mode "${mode}". This may take a while...`;
|
|
2249
|
+
this.tui?.log(statusMessage);
|
|
2250
|
+
this.sendSimulationStatus(statusMessage);
|
|
2251
|
+
const uncompressedBooksPath = this.PATHS.booksUncompressed(mode);
|
|
2252
|
+
const outputStream = fs3.createWriteStream(uncompressedBooksPath, {
|
|
2253
|
+
highWaterMark: this.streamHighWaterMark
|
|
2254
|
+
});
|
|
2255
|
+
try {
|
|
2256
|
+
for (const { worker, chunks: chunks2 } of this.bookIndexMetas) {
|
|
2257
|
+
for (let chunk = 0; chunk < chunks2; chunk++) {
|
|
2258
|
+
const bookChunkPath = this.PATHS.booksChunk(mode, worker, chunk);
|
|
2259
|
+
if (!fs3.existsSync(bookChunkPath)) continue;
|
|
2260
|
+
const inputStream = fs3.createReadStream(bookChunkPath);
|
|
2261
|
+
const compress = zlib.createZstdDecompress();
|
|
2262
|
+
for await (const decompChunk of inputStream.pipe(compress)) {
|
|
2263
|
+
if (!outputStream.write(decompChunk)) {
|
|
2264
|
+
await new Promise((r) => outputStream.once("drain", () => r()));
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
outputStream.end();
|
|
2270
|
+
await new Promise((r) => outputStream.on("finish", () => r()));
|
|
2271
|
+
} catch (error) {
|
|
2272
|
+
statusMessage = chalk2.yellow(
|
|
2273
|
+
`Error creating uncompressed book file: ${error.message}`
|
|
2274
|
+
);
|
|
2275
|
+
this.tui?.log(statusMessage);
|
|
2276
|
+
this.sendSimulationStatus(statusMessage);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2200
2279
|
const endTime = Date.now();
|
|
2201
2280
|
const prettyTime = new Date(endTime - startTime).toISOString().slice(11, -1);
|
|
2202
2281
|
statusMessage = `Mode ${mode} done! Time taken: ${prettyTime}`;
|
|
2203
2282
|
this.tui?.log(statusMessage);
|
|
2204
|
-
|
|
2205
|
-
this.socket.emit("simulationStatus", statusMessage);
|
|
2206
|
-
}
|
|
2283
|
+
this.sendSimulationStatus(statusMessage);
|
|
2207
2284
|
}
|
|
2208
2285
|
this.tui?.stop();
|
|
2209
2286
|
await this.printSimulationSummary();
|
|
@@ -2405,7 +2482,7 @@ var Simulation = class {
|
|
|
2405
2482
|
`
|
|
2406
2483
|
)
|
|
2407
2484
|
]);
|
|
2408
|
-
if (this.bookBufferSizes.get(index) >=
|
|
2485
|
+
if (this.bookBufferSizes.get(index) >= 10 * 1024 * 1024) {
|
|
2409
2486
|
await flushBookChunk();
|
|
2410
2487
|
}
|
|
2411
2488
|
if (this.recordsWriteStream) {
|
|
@@ -2851,6 +2928,11 @@ var Simulation = class {
|
|
|
2851
2928
|
});
|
|
2852
2929
|
}
|
|
2853
2930
|
}
|
|
2931
|
+
sendSimulationStatus(message) {
|
|
2932
|
+
if (this.socket && this.panelActive) {
|
|
2933
|
+
this.socket.emit("simulationStatus", message);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2854
2936
|
};
|
|
2855
2937
|
|
|
2856
2938
|
// src/analysis/index.ts
|
|
@@ -4498,6 +4580,12 @@ var StandaloneBoard = class {
|
|
|
4498
4580
|
getPaddingBottom() {
|
|
4499
4581
|
return this.board.paddingBottom;
|
|
4500
4582
|
}
|
|
4583
|
+
getAnticipation() {
|
|
4584
|
+
return this.board.anticipation;
|
|
4585
|
+
}
|
|
4586
|
+
getLockedReels() {
|
|
4587
|
+
return this.board.reelsLocked;
|
|
4588
|
+
}
|
|
4501
4589
|
/**
|
|
4502
4590
|
* Gets the symbol at the specified reel and row index.
|
|
4503
4591
|
*/
|
|
@@ -4527,6 +4615,12 @@ var StandaloneBoard = class {
|
|
|
4527
4615
|
setAnticipationForReel(reelIndex, value) {
|
|
4528
4616
|
this.board.anticipation[reelIndex] = value;
|
|
4529
4617
|
}
|
|
4618
|
+
/**
|
|
4619
|
+
* Sets the locked state for a specific reel.
|
|
4620
|
+
*/
|
|
4621
|
+
setReelLocked(reelIndex, value) {
|
|
4622
|
+
this.board.reelsLocked[reelIndex] = value;
|
|
4623
|
+
}
|
|
4530
4624
|
/**
|
|
4531
4625
|
* Counts how many symbols matching the criteria are on a specific reel.
|
|
4532
4626
|
*/
|