@slot-engine/core 0.1.1 → 0.1.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 +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +120 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +120 -39
- package/dist/index.mjs.map +1 -1
- package/dist/optimizer-rust/src/exes.rs +2 -0
- package/dist/optimizer-rust/src/main.rs +12 -2
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,12 @@ interface GameConfigOptions<TGameModes extends AnyGameModes = AnyGameModes, TSym
|
|
|
61
61
|
* Some required hooks must be implemented for certain features to work.
|
|
62
62
|
*/
|
|
63
63
|
hooks: GameHooks<TGameModes, TSymbols, TUserState>;
|
|
64
|
+
/**
|
|
65
|
+
* If, for some reason, you run your game WITHOUT `cd`ing into the game root,\
|
|
66
|
+
* you can specify the root directory here to ensure assets are resolved correctly.\
|
|
67
|
+
* Normally, this is not needed.
|
|
68
|
+
*/
|
|
69
|
+
rootDir?: string;
|
|
64
70
|
}
|
|
65
71
|
type GameConfig<TGameModes extends AnyGameModes = AnyGameModes, TSymbols extends AnySymbols = AnySymbols, TUserState extends AnyUserData = AnyUserData> = Required<Omit<GameConfigOptions<TGameModes, TSymbols, TUserState>, "symbols">> & {
|
|
66
72
|
/**
|
|
@@ -68,6 +74,7 @@ type GameConfig<TGameModes extends AnyGameModes = AnyGameModes, TSymbols extends
|
|
|
68
74
|
*/
|
|
69
75
|
symbols: Map<keyof TSymbols & string, TSymbols[keyof TSymbols]>;
|
|
70
76
|
outputDir: string;
|
|
77
|
+
rootDir: string;
|
|
71
78
|
/**
|
|
72
79
|
* A mapping of spin types to the number of scatter symbols required to trigger anticipation.
|
|
73
80
|
*/
|
|
@@ -1113,6 +1120,7 @@ declare class SlotGame<TGameModes extends AnyGameModes = AnyGameModes, TSymbols
|
|
|
1113
1120
|
freespins: number;
|
|
1114
1121
|
};
|
|
1115
1122
|
outputDir: string;
|
|
1123
|
+
rootDir: string;
|
|
1116
1124
|
id: string;
|
|
1117
1125
|
name: string;
|
|
1118
1126
|
gameModes: TGameModes;
|
|
@@ -1304,8 +1312,6 @@ declare class ManywaysWinType extends WinType {
|
|
|
1304
1312
|
payout: number;
|
|
1305
1313
|
winCombinations: ManywaysWinCombination[];
|
|
1306
1314
|
};
|
|
1307
|
-
private _checked;
|
|
1308
|
-
private _checkedWilds;
|
|
1309
1315
|
constructor(opts: ManywaysWinTypeOpts);
|
|
1310
1316
|
private validateConfig;
|
|
1311
1317
|
/**
|
|
@@ -1314,8 +1320,6 @@ declare class ManywaysWinType extends WinType {
|
|
|
1314
1320
|
*/
|
|
1315
1321
|
evaluateWins(board: Reels): this;
|
|
1316
1322
|
private getWayLength;
|
|
1317
|
-
private isChecked;
|
|
1318
|
-
private isCheckedWild;
|
|
1319
1323
|
}
|
|
1320
1324
|
interface ManywaysWinTypeOpts extends WinTypeOpts {
|
|
1321
1325
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,12 @@ interface GameConfigOptions<TGameModes extends AnyGameModes = AnyGameModes, TSym
|
|
|
61
61
|
* Some required hooks must be implemented for certain features to work.
|
|
62
62
|
*/
|
|
63
63
|
hooks: GameHooks<TGameModes, TSymbols, TUserState>;
|
|
64
|
+
/**
|
|
65
|
+
* If, for some reason, you run your game WITHOUT `cd`ing into the game root,\
|
|
66
|
+
* you can specify the root directory here to ensure assets are resolved correctly.\
|
|
67
|
+
* Normally, this is not needed.
|
|
68
|
+
*/
|
|
69
|
+
rootDir?: string;
|
|
64
70
|
}
|
|
65
71
|
type GameConfig<TGameModes extends AnyGameModes = AnyGameModes, TSymbols extends AnySymbols = AnySymbols, TUserState extends AnyUserData = AnyUserData> = Required<Omit<GameConfigOptions<TGameModes, TSymbols, TUserState>, "symbols">> & {
|
|
66
72
|
/**
|
|
@@ -68,6 +74,7 @@ type GameConfig<TGameModes extends AnyGameModes = AnyGameModes, TSymbols extends
|
|
|
68
74
|
*/
|
|
69
75
|
symbols: Map<keyof TSymbols & string, TSymbols[keyof TSymbols]>;
|
|
70
76
|
outputDir: string;
|
|
77
|
+
rootDir: string;
|
|
71
78
|
/**
|
|
72
79
|
* A mapping of spin types to the number of scatter symbols required to trigger anticipation.
|
|
73
80
|
*/
|
|
@@ -1113,6 +1120,7 @@ declare class SlotGame<TGameModes extends AnyGameModes = AnyGameModes, TSymbols
|
|
|
1113
1120
|
freespins: number;
|
|
1114
1121
|
};
|
|
1115
1122
|
outputDir: string;
|
|
1123
|
+
rootDir: string;
|
|
1116
1124
|
id: string;
|
|
1117
1125
|
name: string;
|
|
1118
1126
|
gameModes: TGameModes;
|
|
@@ -1304,8 +1312,6 @@ declare class ManywaysWinType extends WinType {
|
|
|
1304
1312
|
payout: number;
|
|
1305
1313
|
winCombinations: ManywaysWinCombination[];
|
|
1306
1314
|
};
|
|
1307
|
-
private _checked;
|
|
1308
|
-
private _checkedWilds;
|
|
1309
1315
|
constructor(opts: ManywaysWinTypeOpts);
|
|
1310
1316
|
private validateConfig;
|
|
1311
1317
|
/**
|
|
@@ -1314,8 +1320,6 @@ declare class ManywaysWinType extends WinType {
|
|
|
1314
1320
|
*/
|
|
1315
1321
|
evaluateWins(board: Reels): this;
|
|
1316
1322
|
private getWayLength;
|
|
1317
|
-
private isChecked;
|
|
1318
|
-
private isCheckedWild;
|
|
1319
1323
|
}
|
|
1320
1324
|
interface ManywaysWinTypeOpts extends WinTypeOpts {
|
|
1321
1325
|
}
|
package/dist/index.js
CHANGED
|
@@ -76,7 +76,8 @@ function createGameConfig(opts) {
|
|
|
76
76
|
[SPIN_TYPE.BASE_GAME]: getAnticipationTrigger(SPIN_TYPE.BASE_GAME),
|
|
77
77
|
[SPIN_TYPE.FREE_SPINS]: getAnticipationTrigger(SPIN_TYPE.FREE_SPINS)
|
|
78
78
|
},
|
|
79
|
-
outputDir: "__build__"
|
|
79
|
+
outputDir: "__build__",
|
|
80
|
+
rootDir: opts.rootDir || process.cwd()
|
|
80
81
|
};
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -1200,6 +1201,7 @@ var Book = class _Book {
|
|
|
1200
1201
|
freespinsWins = 0;
|
|
1201
1202
|
constructor(opts) {
|
|
1202
1203
|
this.id = opts.id;
|
|
1204
|
+
this.criteria = opts.criteria;
|
|
1203
1205
|
}
|
|
1204
1206
|
/**
|
|
1205
1207
|
* Intended for internal use only.
|
|
@@ -1521,10 +1523,14 @@ Simulating game mode: ${mode}`);
|
|
|
1521
1523
|
const simNumsToCriteria = ResultSet.assignCriteriaToSimulations(this, mode);
|
|
1522
1524
|
await this.spawnWorkersForGameMode({ mode, simNumsToCriteria });
|
|
1523
1525
|
createDirIfNotExists(
|
|
1524
|
-
import_path.default.join(
|
|
1526
|
+
import_path.default.join(
|
|
1527
|
+
this.gameConfig.rootDir,
|
|
1528
|
+
this.gameConfig.outputDir,
|
|
1529
|
+
"optimization_files"
|
|
1530
|
+
)
|
|
1525
1531
|
);
|
|
1526
1532
|
createDirIfNotExists(
|
|
1527
|
-
import_path.default.join(
|
|
1533
|
+
import_path.default.join(this.gameConfig.rootDir, this.gameConfig.outputDir, "publish_files")
|
|
1528
1534
|
);
|
|
1529
1535
|
this.writeLookupTableCSV(mode);
|
|
1530
1536
|
this.writeLookupTableSegmentedCSV(mode);
|
|
@@ -1577,7 +1583,7 @@ Simulating game mode: ${mode}`);
|
|
|
1577
1583
|
await Promise.all(
|
|
1578
1584
|
simRangesPerChunk.map(([simStart, simEnd], index) => {
|
|
1579
1585
|
return this.callWorker({
|
|
1580
|
-
basePath: this.gameConfig.outputDir,
|
|
1586
|
+
basePath: import_path.default.join(this.gameConfig.rootDir, this.gameConfig.outputDir),
|
|
1581
1587
|
mode,
|
|
1582
1588
|
simStart,
|
|
1583
1589
|
simEnd,
|
|
@@ -1600,7 +1606,7 @@ Simulating game mode: ${mode}`);
|
|
|
1600
1606
|
}
|
|
1601
1607
|
}
|
|
1602
1608
|
return new Promise((resolve, reject) => {
|
|
1603
|
-
const scriptPath = import_path.default.join(
|
|
1609
|
+
const scriptPath = import_path.default.join(basePath, TEMP_FILENAME);
|
|
1604
1610
|
const worker = new import_worker_threads.Worker(scriptPath, {
|
|
1605
1611
|
workerData: {
|
|
1606
1612
|
mode,
|
|
@@ -1650,10 +1656,10 @@ Simulating game mode: ${mode}`);
|
|
|
1650
1656
|
ctx.state.currentGameMode,
|
|
1651
1657
|
criteria
|
|
1652
1658
|
);
|
|
1659
|
+
ctx.state.currentResultSet = resultSet;
|
|
1653
1660
|
while (!ctx.state.isCriteriaMet) {
|
|
1654
1661
|
this.actualSims++;
|
|
1655
1662
|
this.resetSimulation(ctx);
|
|
1656
|
-
ctx.state.currentResultSet = resultSet;
|
|
1657
1663
|
this.handleGameFlow(ctx);
|
|
1658
1664
|
if (resultSet.meetsCriteria(ctx)) {
|
|
1659
1665
|
ctx.state.isCriteriaMet = true;
|
|
@@ -1728,10 +1734,19 @@ Simulating game mode: ${mode}`);
|
|
|
1728
1734
|
}
|
|
1729
1735
|
rows.sort((a, b) => Number(a.split(",")[0]) - Number(b.split(",")[0]));
|
|
1730
1736
|
let outputFileName = `lookUpTable_${gameMode}.csv`;
|
|
1731
|
-
let outputFilePath = import_path.default.join(
|
|
1737
|
+
let outputFilePath = import_path.default.join(
|
|
1738
|
+
this.gameConfig.rootDir,
|
|
1739
|
+
this.gameConfig.outputDir,
|
|
1740
|
+
outputFileName
|
|
1741
|
+
);
|
|
1732
1742
|
writeFile(outputFilePath, rows.join("\n"));
|
|
1733
1743
|
outputFileName = `lookUpTable_${gameMode}_0.csv`;
|
|
1734
|
-
outputFilePath = import_path.default.join(
|
|
1744
|
+
outputFilePath = import_path.default.join(
|
|
1745
|
+
this.gameConfig.rootDir,
|
|
1746
|
+
this.gameConfig.outputDir,
|
|
1747
|
+
"publish_files",
|
|
1748
|
+
outputFileName
|
|
1749
|
+
);
|
|
1735
1750
|
writeFile(outputFilePath, rows.join("\n"));
|
|
1736
1751
|
return outputFilePath;
|
|
1737
1752
|
}
|
|
@@ -1745,20 +1760,28 @@ Simulating game mode: ${mode}`);
|
|
|
1745
1760
|
}
|
|
1746
1761
|
rows.sort((a, b) => Number(a.split(",")[0]) - Number(b.split(",")[0]));
|
|
1747
1762
|
const outputFileName = `lookUpTableSegmented_${gameMode}.csv`;
|
|
1748
|
-
const outputFilePath = import_path.default.join(
|
|
1763
|
+
const outputFilePath = import_path.default.join(
|
|
1764
|
+
this.gameConfig.rootDir,
|
|
1765
|
+
this.gameConfig.outputDir,
|
|
1766
|
+
outputFileName
|
|
1767
|
+
);
|
|
1749
1768
|
writeFile(outputFilePath, rows.join("\n"));
|
|
1750
1769
|
return outputFilePath;
|
|
1751
1770
|
}
|
|
1752
1771
|
writeRecords(gameMode) {
|
|
1753
1772
|
const outputFileName = `force_record_${gameMode}.json`;
|
|
1754
|
-
const outputFilePath = import_path.default.join(
|
|
1773
|
+
const outputFilePath = import_path.default.join(
|
|
1774
|
+
this.gameConfig.rootDir,
|
|
1775
|
+
this.gameConfig.outputDir,
|
|
1776
|
+
outputFileName
|
|
1777
|
+
);
|
|
1755
1778
|
writeFile(outputFilePath, JSON.stringify(this.recorder.records, null, 2));
|
|
1756
1779
|
if (this.debug) this.logSymbolOccurrences();
|
|
1757
1780
|
return outputFilePath;
|
|
1758
1781
|
}
|
|
1759
1782
|
writeIndexJson() {
|
|
1760
1783
|
const outputFilePath = import_path.default.join(
|
|
1761
|
-
|
|
1784
|
+
this.gameConfig.rootDir,
|
|
1762
1785
|
this.gameConfig.outputDir,
|
|
1763
1786
|
"publish_files",
|
|
1764
1787
|
"index.json"
|
|
@@ -1777,7 +1800,11 @@ Simulating game mode: ${mode}`);
|
|
|
1777
1800
|
}
|
|
1778
1801
|
async writeBooksJson(gameMode) {
|
|
1779
1802
|
const outputFileName = `books_${gameMode}.jsonl`;
|
|
1780
|
-
const outputFilePath = import_path.default.join(
|
|
1803
|
+
const outputFilePath = import_path.default.join(
|
|
1804
|
+
this.gameConfig.rootDir,
|
|
1805
|
+
this.gameConfig.outputDir,
|
|
1806
|
+
outputFileName
|
|
1807
|
+
);
|
|
1781
1808
|
const books = Array.from(this.library.values()).map((b) => b.serialize()).map((b) => ({
|
|
1782
1809
|
id: b.id,
|
|
1783
1810
|
payoutMultiplier: b.payout,
|
|
@@ -1787,7 +1814,7 @@ Simulating game mode: ${mode}`);
|
|
|
1787
1814
|
writeFile(outputFilePath, contents);
|
|
1788
1815
|
const compressedFileName = `books_${gameMode}.jsonl.zst`;
|
|
1789
1816
|
const compressedFilePath = import_path.default.join(
|
|
1790
|
-
|
|
1817
|
+
this.gameConfig.rootDir,
|
|
1791
1818
|
this.gameConfig.outputDir,
|
|
1792
1819
|
"publish_files",
|
|
1793
1820
|
compressedFileName
|
|
@@ -1825,13 +1852,21 @@ Simulating game mode: ${mode}`);
|
|
|
1825
1852
|
* Compiles user configured game to JS for use in different Node processes
|
|
1826
1853
|
*/
|
|
1827
1854
|
preprocessFiles() {
|
|
1828
|
-
const builtFilePath = import_path.default.join(
|
|
1855
|
+
const builtFilePath = import_path.default.join(
|
|
1856
|
+
this.gameConfig.rootDir,
|
|
1857
|
+
this.gameConfig.outputDir,
|
|
1858
|
+
TEMP_FILENAME
|
|
1859
|
+
);
|
|
1829
1860
|
import_fs2.default.rmSync(builtFilePath, { force: true });
|
|
1830
1861
|
(0, import_esbuild.buildSync)({
|
|
1831
|
-
entryPoints: [
|
|
1862
|
+
entryPoints: [this.gameConfig.rootDir],
|
|
1832
1863
|
bundle: true,
|
|
1833
1864
|
platform: "node",
|
|
1834
|
-
outfile: import_path.default.join(
|
|
1865
|
+
outfile: import_path.default.join(
|
|
1866
|
+
this.gameConfig.rootDir,
|
|
1867
|
+
this.gameConfig.outputDir,
|
|
1868
|
+
TEMP_FILENAME
|
|
1869
|
+
),
|
|
1835
1870
|
external: ["esbuild"]
|
|
1836
1871
|
});
|
|
1837
1872
|
}
|
|
@@ -1942,6 +1977,18 @@ function parseLookupTable(content) {
|
|
|
1942
1977
|
}
|
|
1943
1978
|
return lut;
|
|
1944
1979
|
}
|
|
1980
|
+
function parseLookupTableSegmented(content) {
|
|
1981
|
+
const lines = content.trim().split("\n");
|
|
1982
|
+
const lut = [];
|
|
1983
|
+
for (const line of lines) {
|
|
1984
|
+
const [indexStr, criteria, weightStr, payoutStr] = line.split(",");
|
|
1985
|
+
const index = parseInt(indexStr.trim());
|
|
1986
|
+
const weight = parseInt(weightStr.trim());
|
|
1987
|
+
const payout = parseFloat(payoutStr.trim());
|
|
1988
|
+
lut.push([index, criteria, weight, payout]);
|
|
1989
|
+
}
|
|
1990
|
+
return lut;
|
|
1991
|
+
}
|
|
1945
1992
|
function getTotalLutWeight(lut) {
|
|
1946
1993
|
return lut.reduce((sum, [, weight]) => sum + weight, 0);
|
|
1947
1994
|
}
|
|
@@ -2054,7 +2101,7 @@ var Analysis = class {
|
|
|
2054
2101
|
console.log("Analysis complete. Files written to build directory.");
|
|
2055
2102
|
}
|
|
2056
2103
|
getPathsForModes(gameModes) {
|
|
2057
|
-
const rootPath =
|
|
2104
|
+
const rootPath = this.gameConfig.rootDir;
|
|
2058
2105
|
const paths = {};
|
|
2059
2106
|
for (const modeStr of gameModes) {
|
|
2060
2107
|
const lut = import_path2.default.join(
|
|
@@ -2126,7 +2173,7 @@ var Analysis = class {
|
|
|
2126
2173
|
});
|
|
2127
2174
|
}
|
|
2128
2175
|
writeJsonFile(
|
|
2129
|
-
import_path2.default.join(
|
|
2176
|
+
import_path2.default.join(this.gameConfig.rootDir, this.gameConfig.outputDir, "stats_summary.json"),
|
|
2130
2177
|
stats
|
|
2131
2178
|
);
|
|
2132
2179
|
}
|
|
@@ -2155,35 +2202,76 @@ var Analysis = class {
|
|
|
2155
2202
|
];
|
|
2156
2203
|
const payoutRanges = {};
|
|
2157
2204
|
for (const modeStr of gameModes) {
|
|
2158
|
-
payoutRanges[modeStr] = {};
|
|
2205
|
+
payoutRanges[modeStr] = { overall: {}, criteria: {} };
|
|
2159
2206
|
const lutOptimized = parseLookupTable(
|
|
2160
2207
|
import_fs3.default.readFileSync(this.filePaths[modeStr].lutOptimized, "utf-8")
|
|
2161
2208
|
);
|
|
2209
|
+
const lutSegmented = parseLookupTableSegmented(
|
|
2210
|
+
import_fs3.default.readFileSync(this.filePaths[modeStr].lutSegmented, "utf-8")
|
|
2211
|
+
);
|
|
2162
2212
|
lutOptimized.forEach(([, , p]) => {
|
|
2163
2213
|
const payout = p / 100;
|
|
2164
2214
|
for (const [min, max] of winRanges) {
|
|
2165
2215
|
if (payout >= min && payout <= max) {
|
|
2166
2216
|
const rangeKey = `${min}-${max}`;
|
|
2167
|
-
if (!payoutRanges[modeStr][rangeKey]) {
|
|
2168
|
-
payoutRanges[modeStr][rangeKey] = 0;
|
|
2217
|
+
if (!payoutRanges[modeStr].overall[rangeKey]) {
|
|
2218
|
+
payoutRanges[modeStr].overall[rangeKey] = 0;
|
|
2219
|
+
}
|
|
2220
|
+
payoutRanges[modeStr].overall[rangeKey] += 1;
|
|
2221
|
+
break;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
lutSegmented.forEach(([, criteria, bp, fsp]) => {
|
|
2226
|
+
const basePayout = bp / 100;
|
|
2227
|
+
const freeSpinPayout = fsp / 100;
|
|
2228
|
+
const payout = basePayout + freeSpinPayout;
|
|
2229
|
+
for (const [min, max] of winRanges) {
|
|
2230
|
+
if (payout >= min && payout <= max) {
|
|
2231
|
+
const rangeKey = `${min}-${max}`;
|
|
2232
|
+
if (!payoutRanges[modeStr].overall[rangeKey]) {
|
|
2233
|
+
payoutRanges[modeStr].overall[rangeKey] = 0;
|
|
2234
|
+
}
|
|
2235
|
+
payoutRanges[modeStr].overall[rangeKey] += 1;
|
|
2236
|
+
if (!payoutRanges[modeStr].criteria[criteria]) {
|
|
2237
|
+
payoutRanges[modeStr].criteria[criteria] = {};
|
|
2169
2238
|
}
|
|
2170
|
-
payoutRanges[modeStr][rangeKey]
|
|
2239
|
+
if (!payoutRanges[modeStr].criteria[criteria][rangeKey]) {
|
|
2240
|
+
payoutRanges[modeStr].criteria[criteria][rangeKey] = 0;
|
|
2241
|
+
}
|
|
2242
|
+
payoutRanges[modeStr].criteria[criteria][rangeKey] += 1;
|
|
2171
2243
|
break;
|
|
2172
2244
|
}
|
|
2173
2245
|
}
|
|
2174
2246
|
});
|
|
2175
|
-
const
|
|
2176
|
-
Object.keys(payoutRanges[modeStr]).sort((a, b) => {
|
|
2247
|
+
const orderedOverall = {};
|
|
2248
|
+
Object.keys(payoutRanges[modeStr].overall).sort((a, b) => {
|
|
2177
2249
|
const [aMin] = a.split("-").map(Number);
|
|
2178
2250
|
const [bMin] = b.split("-").map(Number);
|
|
2179
2251
|
return aMin - bMin;
|
|
2180
2252
|
}).forEach((key) => {
|
|
2181
|
-
|
|
2253
|
+
orderedOverall[key] = payoutRanges[modeStr].overall[key];
|
|
2254
|
+
});
|
|
2255
|
+
const orderedCriteria = {};
|
|
2256
|
+
Object.keys(payoutRanges[modeStr].criteria).forEach((crit) => {
|
|
2257
|
+
const critMap = payoutRanges[modeStr].criteria[crit];
|
|
2258
|
+
const orderedCritMap = {};
|
|
2259
|
+
Object.keys(critMap).sort((a, b) => {
|
|
2260
|
+
const [aMin] = a.split("-").map(Number);
|
|
2261
|
+
const [bMin] = b.split("-").map(Number);
|
|
2262
|
+
return aMin - bMin;
|
|
2263
|
+
}).forEach((key) => {
|
|
2264
|
+
orderedCritMap[key] = critMap[key];
|
|
2265
|
+
});
|
|
2266
|
+
orderedCriteria[crit] = orderedCritMap;
|
|
2182
2267
|
});
|
|
2183
|
-
payoutRanges[modeStr] =
|
|
2268
|
+
payoutRanges[modeStr] = {
|
|
2269
|
+
overall: orderedOverall,
|
|
2270
|
+
criteria: {}
|
|
2271
|
+
};
|
|
2184
2272
|
}
|
|
2185
2273
|
writeJsonFile(
|
|
2186
|
-
import_path2.default.join(
|
|
2274
|
+
import_path2.default.join(this.gameConfig.rootDir, this.gameConfig.outputDir, "stats_payouts.json"),
|
|
2187
2275
|
payoutRanges
|
|
2188
2276
|
);
|
|
2189
2277
|
}
|
|
@@ -2245,7 +2333,7 @@ function makeMathConfig(optimizer, opts = {}) {
|
|
|
2245
2333
|
}))
|
|
2246
2334
|
};
|
|
2247
2335
|
if (writeToFile) {
|
|
2248
|
-
const outPath = import_path3.default.join(
|
|
2336
|
+
const outPath = import_path3.default.join(game.rootDir, game.outputDir, "math_config.json");
|
|
2249
2337
|
writeJsonFile(outPath, config);
|
|
2250
2338
|
}
|
|
2251
2339
|
return config;
|
|
@@ -2288,7 +2376,7 @@ function makeSetupFile(optimizer, gameMode) {
|
|
|
2288
2376
|
`;
|
|
2289
2377
|
content += `simulation_trials;${params.simulationTrials}
|
|
2290
2378
|
`;
|
|
2291
|
-
content += `user_game_build_path;${import_path4.default.join(
|
|
2379
|
+
content += `user_game_build_path;${import_path4.default.join(gameConfig.rootDir, gameConfig.outputDir)}
|
|
2292
2380
|
`;
|
|
2293
2381
|
content += `pmb_rtp;${params.pmbRtp}
|
|
2294
2382
|
`;
|
|
@@ -2462,9 +2550,9 @@ var Optimizer = class {
|
|
|
2462
2550
|
}
|
|
2463
2551
|
};
|
|
2464
2552
|
async function rustProgram(...args) {
|
|
2553
|
+
console.log("Starting Rust optimizer. This may take a while...");
|
|
2465
2554
|
return new Promise((resolve, reject) => {
|
|
2466
|
-
const task = (0, import_child_process.spawn)("cargo", ["run", "--release", ...args], {
|
|
2467
|
-
shell: true,
|
|
2555
|
+
const task = (0, import_child_process.spawn)("cargo", ["run", "-q", "--release", ...args], {
|
|
2468
2556
|
cwd: import_path5.default.join(__dirname, "./optimizer-rust"),
|
|
2469
2557
|
stdio: "pipe"
|
|
2470
2558
|
});
|
|
@@ -2930,8 +3018,6 @@ var ClusterWinType = class extends WinType {
|
|
|
2930
3018
|
|
|
2931
3019
|
// src/win-types/ManywaysWinType.ts
|
|
2932
3020
|
var ManywaysWinType = class extends WinType {
|
|
2933
|
-
_checked = [];
|
|
2934
|
-
_checkedWilds = [];
|
|
2935
3021
|
constructor(opts) {
|
|
2936
3022
|
super(opts);
|
|
2937
3023
|
}
|
|
@@ -3029,12 +3115,6 @@ var ManywaysWinType = class extends WinType {
|
|
|
3029
3115
|
getWayLength(symbolList) {
|
|
3030
3116
|
return Math.max(...Object.keys(symbolList).map((k) => parseInt(k, 10))) + 1;
|
|
3031
3117
|
}
|
|
3032
|
-
isChecked(ridx, sidx) {
|
|
3033
|
-
return !!this._checked.find((c) => c.reel === ridx && c.row === sidx);
|
|
3034
|
-
}
|
|
3035
|
-
isCheckedWild(ridx, sidx) {
|
|
3036
|
-
return !!this._checkedWilds.find((c) => c.reel === ridx && c.row === sidx);
|
|
3037
|
-
}
|
|
3038
3118
|
};
|
|
3039
3119
|
|
|
3040
3120
|
// src/reel-set/GeneratedReelSet.ts
|
|
@@ -3238,6 +3318,7 @@ var GeneratedReelSet = class extends ReelSet {
|
|
|
3238
3318
|
);
|
|
3239
3319
|
}
|
|
3240
3320
|
const filePath = import_path7.default.join(
|
|
3321
|
+
config.rootDir,
|
|
3241
3322
|
config.outputDir,
|
|
3242
3323
|
`reels_${this.associatedGameModeName}-${this.id}.csv`
|
|
3243
3324
|
);
|