@omnitronix/happy-panda-game-engine 0.0.1

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.
Files changed (71) hide show
  1. package/README.md +212 -0
  2. package/dist/__tests__/bonus-sequence.test.js +337 -0
  3. package/dist/__tests__/bonus-sequence.test.js.map +1 -0
  4. package/dist/__tests__/cherry-frequency.test.js +128 -0
  5. package/dist/__tests__/cherry-frequency.test.js.map +1 -0
  6. package/dist/__tests__/counter-manager.test.js +316 -0
  7. package/dist/__tests__/counter-manager.test.js.map +1 -0
  8. package/dist/__tests__/cpp-parity.test.js +368 -0
  9. package/dist/__tests__/cpp-parity.test.js.map +1 -0
  10. package/dist/__tests__/fixtures/cpp-parity-vectors.json +438 -0
  11. package/dist/__tests__/happy-panda-engine.test.js +367 -0
  12. package/dist/__tests__/happy-panda-engine.test.js.map +1 -0
  13. package/dist/__tests__/jackpot-manager.test.js +313 -0
  14. package/dist/__tests__/jackpot-manager.test.js.map +1 -0
  15. package/dist/__tests__/jackpot-trigger-trace.test.js +146 -0
  16. package/dist/__tests__/jackpot-trigger-trace.test.js.map +1 -0
  17. package/dist/__tests__/rtp-1million.test.js +156 -0
  18. package/dist/__tests__/rtp-1million.test.js.map +1 -0
  19. package/dist/__tests__/rtp-analysis.test.js +138 -0
  20. package/dist/__tests__/rtp-analysis.test.js.map +1 -0
  21. package/dist/__tests__/rtp-diagnostic.test.js +126 -0
  22. package/dist/__tests__/rtp-diagnostic.test.js.map +1 -0
  23. package/dist/__tests__/rtp-simulation.test.js +409 -0
  24. package/dist/__tests__/rtp-simulation.test.js.map +1 -0
  25. package/dist/__tests__/special-wins.test.js +179 -0
  26. package/dist/__tests__/special-wins.test.js.map +1 -0
  27. package/dist/__tests__/spin-generator.test.js +250 -0
  28. package/dist/__tests__/spin-generator.test.js.map +1 -0
  29. package/dist/__tests__/spin-handler.test.js +210 -0
  30. package/dist/__tests__/spin-handler.test.js.map +1 -0
  31. package/dist/__tests__/symbol-distribution.test.js +119 -0
  32. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  33. package/dist/__tests__/weighted-random.test.js +165 -0
  34. package/dist/__tests__/weighted-random.test.js.map +1 -0
  35. package/dist/__tests__/win-evaluator.test.js +254 -0
  36. package/dist/__tests__/win-evaluator.test.js.map +1 -0
  37. package/dist/config/happy-panda.config.js +714 -0
  38. package/dist/config/happy-panda.config.js.map +1 -0
  39. package/dist/config/index.js +21 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/domain/index.js +21 -0
  42. package/dist/domain/index.js.map +1 -0
  43. package/dist/domain/types.js +28 -0
  44. package/dist/domain/types.js.map +1 -0
  45. package/dist/engine/happy-panda-engine.js +197 -0
  46. package/dist/engine/happy-panda-engine.js.map +1 -0
  47. package/dist/engine/index.js +21 -0
  48. package/dist/engine/index.js.map +1 -0
  49. package/dist/index.js +34 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/logic/handlers/index.js +21 -0
  52. package/dist/logic/handlers/index.js.map +1 -0
  53. package/dist/logic/handlers/spin-handler.js +256 -0
  54. package/dist/logic/handlers/spin-handler.js.map +1 -0
  55. package/dist/logic/index.js +22 -0
  56. package/dist/logic/index.js.map +1 -0
  57. package/dist/logic/services/counter-manager.js +265 -0
  58. package/dist/logic/services/counter-manager.js.map +1 -0
  59. package/dist/logic/services/index.js +23 -0
  60. package/dist/logic/services/index.js.map +1 -0
  61. package/dist/logic/services/jackpot-manager.js +142 -0
  62. package/dist/logic/services/jackpot-manager.js.map +1 -0
  63. package/dist/logic/services/win-evaluator.js +470 -0
  64. package/dist/logic/services/win-evaluator.js.map +1 -0
  65. package/dist/rng/index.js +22 -0
  66. package/dist/rng/index.js.map +1 -0
  67. package/dist/rng/spin-generator.js +341 -0
  68. package/dist/rng/spin-generator.js.map +1 -0
  69. package/dist/rng/weighted-random.js +58 -0
  70. package/dist/rng/weighted-random.js.map +1 -0
  71. package/package.json +49 -0
@@ -0,0 +1,438 @@
1
+ {
2
+ "description": "Test vectors for win evaluation. Multipliers tuned for 96.38% RTP (diverged from original C++ for RTP compliance).",
3
+ "version": "2.0.0",
4
+ "generatedFrom": "CherryMaster_A_2.cpp (tuned)",
5
+ "testCases": [
6
+ {
7
+ "id": "paid-spin-no-win-001",
8
+ "description": "Basic paid spin with no wins",
9
+ "input": {
10
+ "spinType": 0,
11
+ "gameDirection": 0,
12
+ "betStake": 1,
13
+ "betGame": 8,
14
+ "rngSequence": [45, 67, 23, 89, 12, 56, 78, 34, 90, 11, 22, 33]
15
+ },
16
+ "expected": {
17
+ "grid": [
18
+ [7, 5, 8],
19
+ [8, 6, 7],
20
+ [5, 7, 6]
21
+ ],
22
+ "gridSymbols": ["PRUNE", "MELON", "ORANGE", "ORANGE", "BELL", "PRUNE", "MELON", "PRUNE", "BELL"],
23
+ "totalPayout": 0,
24
+ "hasWallWin": false,
25
+ "hasScatterWin": false,
26
+ "lineWinCount": 0
27
+ }
28
+ },
29
+ {
30
+ "id": "paid-spin-cherry-x1-002",
31
+ "description": "Paid spin with single cherry on line",
32
+ "input": {
33
+ "spinType": 0,
34
+ "gameDirection": 0,
35
+ "betStake": 1,
36
+ "betGame": 8,
37
+ "rngSequence": [95, 67, 23, 89, 12, 56, 78, 34, 90, 11, 22, 33]
38
+ },
39
+ "expected": {
40
+ "grid": [
41
+ [9, 5, 8],
42
+ [8, 6, 7],
43
+ [5, 7, 6]
44
+ ],
45
+ "gridSymbols": ["CHERRY", "MELON", "ORANGE", "ORANGE", "BELL", "PRUNE", "MELON", "PRUNE", "BELL"],
46
+ "totalPayout": 2,
47
+ "hasWallWin": false,
48
+ "hasScatterWin": false,
49
+ "lineWinCount": 1,
50
+ "lineWins": [
51
+ {
52
+ "lineIndex": 0,
53
+ "symbol": 9,
54
+ "matchLength": 1,
55
+ "payout": 2
56
+ }
57
+ ]
58
+ }
59
+ },
60
+ {
61
+ "id": "paid-spin-bar3-line-003",
62
+ "description": "Paid spin with 3x BAR3 on line",
63
+ "input": {
64
+ "spinType": 0,
65
+ "gameDirection": 0,
66
+ "betStake": 1,
67
+ "betGame": 8,
68
+ "forcedGrid": [
69
+ [2, 5, 8],
70
+ [2, 6, 7],
71
+ [2, 7, 6]
72
+ ]
73
+ },
74
+ "expected": {
75
+ "grid": [
76
+ [2, 5, 8],
77
+ [2, 6, 7],
78
+ [2, 7, 6]
79
+ ],
80
+ "totalPayout": 80,
81
+ "hasWallWin": false,
82
+ "hasScatterWin": false,
83
+ "lineWinCount": 1,
84
+ "lineWins": [
85
+ {
86
+ "lineIndex": 0,
87
+ "symbol": 2,
88
+ "matchLength": 3,
89
+ "payout": 80
90
+ }
91
+ ]
92
+ }
93
+ },
94
+ {
95
+ "id": "wall-win-bar3-004",
96
+ "description": "Full screen BAR3 wall win",
97
+ "input": {
98
+ "spinType": 0,
99
+ "gameDirection": 0,
100
+ "betStake": 1,
101
+ "betGame": 8,
102
+ "forcedGrid": [
103
+ [2, 2, 2],
104
+ [2, 2, 2],
105
+ [2, 2, 2]
106
+ ]
107
+ },
108
+ "expected": {
109
+ "grid": [
110
+ [2, 2, 2],
111
+ [2, 2, 2],
112
+ [2, 2, 2]
113
+ ],
114
+ "totalPayout": 352,
115
+ "hasWallWin": true,
116
+ "wallWinType": 2,
117
+ "wallPayout": 352,
118
+ "hasScatterWin": false,
119
+ "lineWinCount": 0,
120
+ "comment": "Wall wins suppress line wins"
121
+ }
122
+ },
123
+ {
124
+ "id": "wall-win-cherry-mix-005",
125
+ "description": "Cherry wall win with mixed CH/CH_S",
126
+ "input": {
127
+ "spinType": 0,
128
+ "gameDirection": 0,
129
+ "betStake": 1,
130
+ "betGame": 8,
131
+ "forcedGrid": [
132
+ [9, 10, 9],
133
+ [10, 9, 10],
134
+ [9, 9, 10]
135
+ ]
136
+ },
137
+ "expected": {
138
+ "grid": [
139
+ [9, 10, 9],
140
+ [10, 9, 10],
141
+ [9, 9, 10]
142
+ ],
143
+ "totalPayout": 280,
144
+ "hasWallWin": true,
145
+ "wallWinType": 9,
146
+ "wallPayout": 280,
147
+ "hasScatterWin": false,
148
+ "lineWinCount": 0
149
+ }
150
+ },
151
+ {
152
+ "id": "scatter-win-3x-seven-006",
153
+ "description": "3x Seven scatter win",
154
+ "input": {
155
+ "spinType": 0,
156
+ "gameDirection": 0,
157
+ "betStake": 1,
158
+ "betGame": 8,
159
+ "forcedGrid": [
160
+ [1, 5, 8],
161
+ [6, 1, 7],
162
+ [5, 7, 1]
163
+ ]
164
+ },
165
+ "expected": {
166
+ "grid": [
167
+ [1, 5, 8],
168
+ [6, 1, 7],
169
+ [5, 7, 1]
170
+ ],
171
+ "totalPayout": 16,
172
+ "hasWallWin": false,
173
+ "hasScatterWin": true,
174
+ "scatterSymbol": 1,
175
+ "scatterCount": 3,
176
+ "scatterPayout": 16,
177
+ "lineWinCount": 0,
178
+ "comment": "Scatter wins suppress line wins"
179
+ }
180
+ },
181
+ {
182
+ "id": "scatter-win-3x-super-seven-doubled-007",
183
+ "description": "3x Super Seven scatter win (doubled)",
184
+ "input": {
185
+ "spinType": 0,
186
+ "gameDirection": 0,
187
+ "betStake": 1,
188
+ "betGame": 8,
189
+ "forcedGrid": [
190
+ [0, 5, 8],
191
+ [6, 0, 7],
192
+ [5, 7, 0]
193
+ ]
194
+ },
195
+ "expected": {
196
+ "grid": [
197
+ [0, 5, 8],
198
+ [6, 0, 7],
199
+ [5, 7, 0]
200
+ ],
201
+ "totalPayout": 32,
202
+ "hasWallWin": false,
203
+ "hasScatterWin": true,
204
+ "scatterSymbol": 0,
205
+ "scatterCount": 3,
206
+ "scatterPayout": 32,
207
+ "isSuperSevenOnly": true,
208
+ "lineWinCount": 0,
209
+ "comment": "Super Seven only = doubled payout"
210
+ }
211
+ },
212
+ {
213
+ "id": "any-bar-wall-008",
214
+ "description": "Any Bar wall win (mixed BAR3/BAR2/BAR1)",
215
+ "input": {
216
+ "spinType": 0,
217
+ "gameDirection": 0,
218
+ "betStake": 1,
219
+ "betGame": 8,
220
+ "forcedGrid": [
221
+ [2, 3, 4],
222
+ [4, 2, 3],
223
+ [3, 4, 2]
224
+ ]
225
+ },
226
+ "expected": {
227
+ "grid": [
228
+ [2, 3, 4],
229
+ [4, 2, 3],
230
+ [3, 4, 2]
231
+ ],
232
+ "totalPayout": 40,
233
+ "hasWallWin": true,
234
+ "wallWinType": 10,
235
+ "wallPayout": 40,
236
+ "hasScatterWin": false,
237
+ "lineWinCount": 0
238
+ }
239
+ },
240
+ {
241
+ "id": "fruit-wall-009",
242
+ "description": "All Fruits wall win",
243
+ "input": {
244
+ "spinType": 0,
245
+ "gameDirection": 0,
246
+ "betStake": 1,
247
+ "betGame": 8,
248
+ "forcedGrid": [
249
+ [5, 7, 8],
250
+ [9, 10, 5],
251
+ [7, 8, 9]
252
+ ]
253
+ },
254
+ "expected": {
255
+ "grid": [
256
+ [5, 7, 8],
257
+ [9, 10, 5],
258
+ [7, 8, 9]
259
+ ],
260
+ "totalPayout": 16,
261
+ "hasWallWin": true,
262
+ "wallWinType": 11,
263
+ "wallPayout": 16,
264
+ "hasScatterWin": false,
265
+ "lineWinCount": 0
266
+ }
267
+ },
268
+ {
269
+ "id": "bar-mix-line-010",
270
+ "description": "Any Bar line win (BAR3+BAR2+BAR1)",
271
+ "input": {
272
+ "spinType": 0,
273
+ "gameDirection": 0,
274
+ "betStake": 1,
275
+ "betGame": 8,
276
+ "forcedGrid": [
277
+ [2, 5, 8],
278
+ [3, 6, 7],
279
+ [4, 7, 6]
280
+ ]
281
+ },
282
+ "expected": {
283
+ "grid": [
284
+ [2, 5, 8],
285
+ [3, 6, 7],
286
+ [4, 7, 6]
287
+ ],
288
+ "totalPayout": 10,
289
+ "hasWallWin": false,
290
+ "hasScatterWin": false,
291
+ "lineWinCount": 1,
292
+ "lineWins": [
293
+ {
294
+ "lineIndex": 0,
295
+ "symbol": 25,
296
+ "matchLength": 3,
297
+ "payout": 10
298
+ }
299
+ ],
300
+ "comment": "Symbol 25 = BAR_ANY for mixed bar line"
301
+ }
302
+ },
303
+ {
304
+ "id": "16-line-mode-011",
305
+ "description": "16-line mode with both direction wins",
306
+ "input": {
307
+ "spinType": 0,
308
+ "gameDirection": 1,
309
+ "betStake": 1,
310
+ "betGame": 16,
311
+ "forcedGrid": [
312
+ [6, 5, 8],
313
+ [6, 6, 7],
314
+ [6, 7, 6]
315
+ ]
316
+ },
317
+ "expected": {
318
+ "grid": [
319
+ [6, 5, 8],
320
+ [6, 6, 7],
321
+ [6, 7, 6]
322
+ ],
323
+ "totalPayout": 72,
324
+ "hasWallWin": false,
325
+ "hasScatterWin": false,
326
+ "lineWinCount": 4,
327
+ "comment": "Bell on line 0 (top row), line 6 (diagonal), line 8 (reverse top row), line 14 (reverse diagonal) = 4 x 18 = 72"
328
+ }
329
+ },
330
+ {
331
+ "id": "bonus-bell-scatter-012",
332
+ "description": "Bell Bonus with bell scatter wins",
333
+ "input": {
334
+ "spinType": 3,
335
+ "gameDirection": 0,
336
+ "betStake": 1,
337
+ "betGame": 8,
338
+ "forcedGrid": [
339
+ [6, 5, 6],
340
+ [7, 6, 7],
341
+ [6, 7, 6]
342
+ ]
343
+ },
344
+ "expected": {
345
+ "grid": [
346
+ [6, 5, 6],
347
+ [7, 6, 7],
348
+ [6, 7, 6]
349
+ ],
350
+ "hasWallWin": false,
351
+ "hasScatterWin": false,
352
+ "specialWinCount": 1,
353
+ "specialWins": [
354
+ {
355
+ "winType": 14,
356
+ "count": 5,
357
+ "payout": 25
358
+ }
359
+ ],
360
+ "comment": "Bell Bonus: each bell pays as scatter (5 bells × 5 × 1 = 25)"
361
+ }
362
+ },
363
+ {
364
+ "id": "bonus-bar1-super-bar-013",
365
+ "description": "Bar1 Bonus with super bar scatter wins",
366
+ "input": {
367
+ "spinType": 4,
368
+ "gameDirection": 0,
369
+ "betStake": 1,
370
+ "betGame": 8,
371
+ "forcedGrid": [
372
+ [11, 5, 11],
373
+ [7, 11, 7],
374
+ [5, 7, 11]
375
+ ]
376
+ },
377
+ "expected": {
378
+ "grid": [
379
+ [11, 5, 11],
380
+ [7, 11, 7],
381
+ [5, 7, 11]
382
+ ],
383
+ "hasWallWin": false,
384
+ "hasScatterWin": false,
385
+ "specialWinCount": 1,
386
+ "specialWins": [
387
+ {
388
+ "winType": 15,
389
+ "count": 4,
390
+ "payout": 20
391
+ }
392
+ ],
393
+ "comment": "Bar1 Bonus: each super bar pays as scatter (4 × 5 × 1 = 20)"
394
+ }
395
+ }
396
+ ],
397
+ "multiplierTests": {
398
+ "description": "Verify multiplier values (tuned for 96.38% RTP)",
399
+ "lineMultipliers": {
400
+ "SUPER_SEVEN_x3": 150,
401
+ "SEVEN_x3": 100,
402
+ "BAR3_x3": 80,
403
+ "BAR2_x3": 50,
404
+ "BAR1_x3": 30,
405
+ "MELON_x3": 20,
406
+ "BELL_x3": 18,
407
+ "PRUNE_x3": 14,
408
+ "ORANGE_x3": 10,
409
+ "CHERRY_x1": 2,
410
+ "CHERRY_x2": 5,
411
+ "CHERRY_x3": 10,
412
+ "ANY_BAR_x3": 10
413
+ },
414
+ "wallMultipliers": {
415
+ "BAR3": 44,
416
+ "BAR2": 35,
417
+ "BAR1": 27,
418
+ "MELON": 27,
419
+ "BELL": 17,
420
+ "PRUNE": 9,
421
+ "ORANGE": 5,
422
+ "CHERRY": 35,
423
+ "ANY_BAR": 5,
424
+ "ALL_FRUITS": 2,
425
+ "ALL_COLORS": 5
426
+ },
427
+ "scatterMultipliers": {
428
+ "SEVEN_x9": 220,
429
+ "SEVEN_x8": 88,
430
+ "SEVEN_x7": 44,
431
+ "SEVEN_x6": 22,
432
+ "SEVEN_x5": 11,
433
+ "SEVEN_x4": 4,
434
+ "SEVEN_x3": 2,
435
+ "SEVEN_x2": 1
436
+ }
437
+ }
438
+ }