@slot-engine/core 0.1.5 → 0.1.7

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.mjs CHANGED
@@ -645,14 +645,15 @@ var Board = class {
645
645
  this.lastUsedReels = opts.reels;
646
646
  for (let ridx = 0; ridx < reelsAmount; ridx++) {
647
647
  const reelPos = finalReelStops[ridx];
648
+ const reelLength = opts.reels[ridx].length;
648
649
  for (let p = padSymbols - 1; p >= 0; p--) {
649
- const topPos = (reelPos - (p + 1)) % opts.reels[ridx].length;
650
+ const topPos = ((reelPos - (p + 1)) % reelLength + reelLength) % reelLength;
650
651
  this.paddingTop[ridx].push(opts.reels[ridx][topPos]);
651
- const bottomPos = (reelPos + symbolsPerReel[ridx] + p) % opts.reels[ridx].length;
652
+ const bottomPos = (reelPos + symbolsPerReel[ridx] + p) % reelLength;
652
653
  this.paddingBottom[ridx].unshift(opts.reels[ridx][bottomPos]);
653
654
  }
654
655
  for (let row = 0; row < symbolsPerReel[ridx]; row++) {
655
- const symbol = opts.reels[ridx][(reelPos + row) % opts.reels[ridx].length];
656
+ const symbol = opts.reels[ridx][(reelPos + row) % reelLength];
656
657
  if (!symbol) {
657
658
  throw new Error(`Failed to get symbol at pos ${reelPos + row} on reel ${ridx}`);
658
659
  }
@@ -728,6 +729,19 @@ var Board = class {
728
729
  newPaddingTopSymbols
729
730
  };
730
731
  }
732
+ dedupeWinSymbolsForTumble(winCombinations) {
733
+ const symbolsMap = /* @__PURE__ */ new Map();
734
+ winCombinations.forEach((wc) => {
735
+ wc.symbols.forEach((s) => {
736
+ symbolsMap.set(`${s.reelIndex},${s.posIndex}`, {
737
+ reelIdx: s.reelIndex,
738
+ rowIdx: s.posIndex
739
+ });
740
+ });
741
+ });
742
+ const symbolsToRemove = Array.from(symbolsMap.values());
743
+ return symbolsToRemove;
744
+ }
731
745
  };
732
746
 
733
747
  // src/service/board.ts
@@ -872,6 +886,16 @@ var BoardService = class extends AbstractService {
872
886
  symbolsToDelete
873
887
  });
874
888
  }
889
+ /**
890
+ * Dedupes win symbols for tumble.\
891
+ * Returns a list of symbols to remove from the board based on the given win combinations.
892
+ *
893
+ * Since it may be possible that multiple win combinations include the same symbol (e.g. Wilds),\
894
+ * this method ensures that each symbol is only listed once for removal. Otherwise tumbling may break.
895
+ */
896
+ dedupeWinSymbolsForTumble(winCombinations) {
897
+ return this.board.dedupeWinSymbolsForTumble(winCombinations);
898
+ }
875
899
  };
876
900
 
877
901
  // src/service/data.ts
@@ -2270,28 +2294,12 @@ var Analysis = class {
2270
2294
  const payoutRanges = {};
2271
2295
  for (const modeStr of gameModes) {
2272
2296
  payoutRanges[modeStr] = { overall: {}, criteria: {} };
2273
- const lutOptimized = parseLookupTable(
2274
- fs3.readFileSync(this.filePaths[modeStr].lutOptimized, "utf-8")
2275
- );
2276
2297
  const lutSegmented = parseLookupTableSegmented(
2277
2298
  fs3.readFileSync(this.filePaths[modeStr].lutSegmented, "utf-8")
2278
2299
  );
2279
- lutOptimized.forEach(([, , p]) => {
2280
- const payout = p / 100;
2281
- for (const [min, max] of winRanges) {
2282
- if (payout >= min && payout <= max) {
2283
- const rangeKey = `${min}-${max}`;
2284
- if (!payoutRanges[modeStr].overall[rangeKey]) {
2285
- payoutRanges[modeStr].overall[rangeKey] = 0;
2286
- }
2287
- payoutRanges[modeStr].overall[rangeKey] += 1;
2288
- break;
2289
- }
2290
- }
2291
- });
2292
2300
  lutSegmented.forEach(([, criteria, bp, fsp]) => {
2293
- const basePayout = bp / 100;
2294
- const freeSpinPayout = fsp / 100;
2301
+ const basePayout = bp;
2302
+ const freeSpinPayout = fsp;
2295
2303
  const payout = basePayout + freeSpinPayout;
2296
2304
  for (const [min, max] of winRanges) {
2297
2305
  if (payout >= min && payout <= max) {
@@ -2864,6 +2872,7 @@ var LinesWinType = class extends WinType {
2864
2872
  let baseSymbol;
2865
2873
  const potentialWinLine = [];
2866
2874
  const potentialWildLine = [];
2875
+ let isInterrupted = false;
2867
2876
  for (const [ridx, reel] of reels.entries()) {
2868
2877
  const sidx = line[ridx];
2869
2878
  const thisSymbol = reel[sidx];
@@ -2890,6 +2899,9 @@ var LinesWinType = class extends WinType {
2890
2899
  }
2891
2900
  if (baseSymbol.compare(thisSymbol) || this.isWild(thisSymbol)) {
2892
2901
  potentialWinLine.push({ reel: ridx, row: sidx, symbol: thisSymbol });
2902
+ } else {
2903
+ isInterrupted = true;
2904
+ break;
2893
2905
  }
2894
2906
  }
2895
2907
  const minSymLine = Math.min(
@@ -3748,6 +3760,16 @@ var StandaloneBoard = class {
3748
3760
  padSymbols: this.padSymbols
3749
3761
  });
3750
3762
  }
3763
+ /**
3764
+ * Dedupes win symbols for tumble.\
3765
+ * Returns a list of symbols to remove from the board based on the given win combinations.
3766
+ *
3767
+ * Since it may be possible that multiple win combinations include the same symbol (e.g. Wilds),\
3768
+ * this method ensures that each symbol is only listed once for removal. Otherwise tumbling may break.
3769
+ */
3770
+ dedupeWinSymbolsForTumble(winCombinations) {
3771
+ return this.board.dedupeWinSymbolsForTumble(winCombinations);
3772
+ }
3751
3773
  };
3752
3774
  export {
3753
3775
  ClusterWinType,