@omnitronix/bonnys-fortune-game-engine 1.3.2 → 1.5.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.
Files changed (175) hide show
  1. package/README.md +25 -15
  2. package/dist/__tests__/base-game.test.js +255 -0
  3. package/dist/__tests__/base-game.test.js.map +1 -0
  4. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.js +1 -1
  5. package/dist/__tests__/bonus-handlers.test.js +303 -0
  6. package/dist/__tests__/bonus-handlers.test.js.map +1 -0
  7. package/dist/__tests__/bonus-meters.test.js +508 -0
  8. package/dist/__tests__/bonus-meters.test.js.map +1 -0
  9. package/dist/__tests__/collect-feature-handler.test.js +386 -0
  10. package/dist/__tests__/collect-feature-handler.test.js.map +1 -0
  11. package/dist/__tests__/comprehensive.test.js +747 -0
  12. package/dist/__tests__/comprehensive.test.js.map +1 -0
  13. package/dist/__tests__/error-paths.test.js +373 -0
  14. package/dist/__tests__/error-paths.test.js.map +1 -0
  15. package/dist/__tests__/helpers/test-engine-factory.js +268 -0
  16. package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
  17. package/dist/__tests__/rng-gli19-compliance.test.js +292 -0
  18. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
  19. package/dist/__tests__/rng-security.test.js +383 -0
  20. package/dist/__tests__/rng-security.test.js.map +1 -0
  21. package/dist/__tests__/rtp-simulation.test.js +242 -0
  22. package/dist/__tests__/rtp-simulation.test.js.map +1 -0
  23. package/dist/__tests__/state-transitions.test.js +307 -0
  24. package/dist/__tests__/state-transitions.test.js.map +1 -0
  25. package/dist/__tests__/steering-fortune-handler.test.js +286 -0
  26. package/dist/__tests__/steering-fortune-handler.test.js.map +1 -0
  27. package/dist/__tests__/symbol-distribution.test.js +195 -0
  28. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  29. package/dist/__tests__/treasure-hunt-handler.test.js +295 -0
  30. package/dist/__tests__/treasure-hunt-handler.test.js.map +1 -0
  31. package/dist/__tests__/win-calculator.test.js +515 -0
  32. package/dist/__tests__/win-calculator.test.js.map +1 -0
  33. package/dist/bonnys-fortune-v1.game-engine.js +14 -25
  34. package/dist/bonnys-fortune-v1.game-engine.js.map +1 -1
  35. package/dist/config/game-logic-config/game-logic-config.js +0 -2
  36. package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
  37. package/dist/domain/types/{cheat-trigger-bonus-command.js → debug-trigger-bonus-command.js} +1 -1
  38. package/dist/domain/types/debug-trigger-bonus-command.js.map +1 -0
  39. package/dist/domain/types/{cheat-trigger-bonus-request.dto.js → debug-trigger-bonus-request.dto.js} +1 -1
  40. package/dist/domain/types/debug-trigger-bonus-request.dto.js.map +1 -0
  41. package/dist/domain/types/{cheat-update-bonus-meter-progress-command.js → debug-update-bonus-meter-progress-command.js} +1 -1
  42. package/dist/domain/types/debug-update-bonus-meter-progress-command.js.map +1 -0
  43. package/dist/domain/types/{cheat-update-bonus-meter-progress-request.dto.js → debug-update-bonus-meter-progress-request.dto.js} +1 -1
  44. package/dist/domain/types/debug-update-bonus-meter-progress-request.dto.js.map +1 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/logic/bonnys-fortune.game-logic.js +37 -17
  47. package/dist/logic/bonnys-fortune.game-logic.js.map +1 -1
  48. package/dist/logic/handlers/base-game.handler.js +1 -5
  49. package/dist/logic/handlers/base-game.handler.js.map +1 -1
  50. package/dist/rng/DummyRngClient.js +8 -1
  51. package/dist/rng/DummyRngClient.js.map +1 -1
  52. package/dist/rng/rng-client.factory.js.map +1 -1
  53. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js +0 -9
  54. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js.map +1 -1
  55. package/package.json +6 -6
  56. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.d.ts +0 -1
  57. package/dist/bonnys-fortune-v1.game-engine.d.ts +0 -36
  58. package/dist/config/game-logic-config/file-system.game-logic-config-loader.d.ts +0 -4
  59. package/dist/config/game-logic-config/game-logic-config-loader.d.ts +0 -3
  60. package/dist/config/game-logic-config/game-logic-config.d.ts +0 -2
  61. package/dist/config/reel-strips-config/file-system.reel-strips-config-loader.d.ts +0 -4
  62. package/dist/config/reel-strips-config/reel-strip-option.dto.d.ts +0 -4
  63. package/dist/config/reel-strips-config/reel-strips-config-loader.d.ts +0 -3
  64. package/dist/config/reel-strips-config/reel-strips-config.dto.d.ts +0 -5
  65. package/dist/config/reel-strips-config/reel.dto.d.ts +0 -5
  66. package/dist/domain/game-round.types.d.ts +0 -9
  67. package/dist/domain/mappers/reel-strips-config.mapper.d.ts +0 -4
  68. package/dist/domain/reel-strip-option.d.ts +0 -7
  69. package/dist/domain/reel-strips-config.d.ts +0 -9
  70. package/dist/domain/reel.d.ts +0 -8
  71. package/dist/domain/types/cheat-trigger-bonus-command.d.ts +0 -5
  72. package/dist/domain/types/cheat-trigger-bonus-command.js.map +0 -1
  73. package/dist/domain/types/cheat-trigger-bonus-request.dto.d.ts +0 -5
  74. package/dist/domain/types/cheat-trigger-bonus-request.dto.js.map +0 -1
  75. package/dist/domain/types/cheat-update-bonus-meter-progress-command.d.ts +0 -5
  76. package/dist/domain/types/cheat-update-bonus-meter-progress-command.js.map +0 -1
  77. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.d.ts +0 -5
  78. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.js.map +0 -1
  79. package/dist/domain/types/game-spin-command.d.ts +0 -8
  80. package/dist/domain/types/game-spin-input.dto.d.ts +0 -8
  81. package/dist/domain/types/game-spin-output.dto.d.ts +0 -119
  82. package/dist/domain/types/game-symbols.response.dto.d.ts +0 -10
  83. package/dist/domain/types/reel-strip-option.dto.d.ts +0 -4
  84. package/dist/domain/types/reel-strips-config.dto.d.ts +0 -5
  85. package/dist/domain/types/reel.dto.d.ts +0 -5
  86. package/dist/domain/types/start-bonus-round-command.d.ts +0 -8
  87. package/dist/domain/types/start-bonus-round-input.dto.d.ts +0 -10
  88. package/dist/game-engine.interface.d.ts +0 -41
  89. package/dist/helpers/generate-hash.d.ts +0 -1
  90. package/dist/helpers/number-helper.d.ts +0 -23
  91. package/dist/helpers/optional-boolean-mapper.d.ts +0 -1
  92. package/dist/helpers/uuid-helper.d.ts +0 -3
  93. package/dist/helpers/validation-helper.d.ts +0 -14
  94. package/dist/index.d.ts +0 -2
  95. package/dist/logger/logger.d.ts +0 -22
  96. package/dist/logger/logger.js +0 -140
  97. package/dist/logger/logger.js.map +0 -1
  98. package/dist/logic/bonnys-fortune.game-logic.d.ts +0 -32
  99. package/dist/logic/bonnys-fortune.spin-generator.d.ts +0 -19
  100. package/dist/logic/bonnys-fortune.types.d.ts +0 -170
  101. package/dist/logic/bonnys-fortune.win-calculator.d.ts +0 -10
  102. package/dist/logic/game-logic-config.interface.d.ts +0 -180
  103. package/dist/logic/handlers/base-game.handler.d.ts +0 -15
  104. package/dist/logic/handlers/collect-feature-bonus.handler.d.ts +0 -13
  105. package/dist/logic/handlers/free-spins-bonus.handler.d.ts +0 -11
  106. package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.d.ts +0 -11
  107. package/dist/logic/handlers/treasure-hunt-bonus.handler.d.ts +0 -15
  108. package/dist/rng/DummyRngClient.d.ts +0 -18
  109. package/dist/rng/rng-client.factory.d.ts +0 -7
  110. package/dist/rng/rng-client.interface.d.ts +0 -16
  111. package/dist/rng/rng-service.d.ts +0 -26
  112. package/dist/validation/abstract-game-logic-config.validator.d.ts +0 -4
  113. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.d.ts +0 -131
  114. package/dist/validation/bonnys-fortune/bonnys-fortune-config.validator.d.ts +0 -5
  115. package/dist/validation/custom-decorators/IsNestedIntArray.d.ts +0 -2
  116. package/dist/validation/game-logic-config-validation.service.d.ts +0 -8
  117. package/dist/validation/reel-strips-config-validation.service.d.ts +0 -5
  118. package/src/__tests__/bonnys-fortune-v1.game-engine.test.ts +0 -80
  119. package/src/bonnys-fortune-v1.game-engine.ts +0 -314
  120. package/src/config/game-logic-config/file-system.game-logic-config-loader.ts +0 -27
  121. package/src/config/game-logic-config/game-logic-config-loader.ts +0 -3
  122. package/src/config/game-logic-config/game-logic-config.ts +0 -382
  123. package/src/config/reel-strips-config/file-system.reel-strips-config-loader.ts +0 -43
  124. package/src/config/reel-strips-config/reel-strip-option.dto.ts +0 -13
  125. package/src/config/reel-strips-config/reel-strips-config-loader.ts +0 -9
  126. package/src/config/reel-strips-config/reel-strips-config.dto.ts +0 -16
  127. package/src/config/reel-strips-config/reel.dto.ts +0 -16
  128. package/src/config/reel-strips-config/reels-BASE.csv +0 -52
  129. package/src/config/reel-strips-config/reels-BONUS.csv +0 -52
  130. package/src/domain/game-round.types.ts +0 -10
  131. package/src/domain/mappers/reel-strips-config.mapper.ts +0 -16
  132. package/src/domain/reel-strip-option.ts +0 -15
  133. package/src/domain/reel-strips-config.ts +0 -21
  134. package/src/domain/reel.ts +0 -17
  135. package/src/domain/types/cheat-trigger-bonus-command.ts +0 -5
  136. package/src/domain/types/cheat-trigger-bonus-request.dto.ts +0 -5
  137. package/src/domain/types/cheat-update-bonus-meter-progress-command.ts +0 -6
  138. package/src/domain/types/cheat-update-bonus-meter-progress-request.dto.ts +0 -5
  139. package/src/domain/types/game-spin-command.ts +0 -8
  140. package/src/domain/types/game-spin-input.dto.ts +0 -8
  141. package/src/domain/types/game-spin-output.dto.ts +0 -142
  142. package/src/domain/types/game-symbols.response.dto.ts +0 -11
  143. package/src/domain/types/reel-strip-option.dto.ts +0 -13
  144. package/src/domain/types/reel-strips-config.dto.ts +0 -15
  145. package/src/domain/types/reel.dto.ts +0 -15
  146. package/src/domain/types/start-bonus-round-command.ts +0 -8
  147. package/src/domain/types/start-bonus-round-input.dto.ts +0 -10
  148. package/src/game-engine.interface.ts +0 -59
  149. package/src/helpers/generate-hash.ts +0 -5
  150. package/src/helpers/number-helper.ts +0 -41
  151. package/src/helpers/optional-boolean-mapper.ts +0 -5
  152. package/src/helpers/uuid-helper.ts +0 -7
  153. package/src/helpers/validation-helper.ts +0 -27
  154. package/src/index.ts +0 -3
  155. package/src/logger/logger.ts +0 -178
  156. package/src/logic/bonnys-fortune.game-logic.ts +0 -490
  157. package/src/logic/bonnys-fortune.spin-generator.ts +0 -277
  158. package/src/logic/bonnys-fortune.types.ts +0 -223
  159. package/src/logic/bonnys-fortune.win-calculator.ts +0 -210
  160. package/src/logic/game-logic-config.interface.ts +0 -176
  161. package/src/logic/handlers/base-game.handler.ts +0 -221
  162. package/src/logic/handlers/collect-feature-bonus.handler.ts +0 -301
  163. package/src/logic/handlers/free-spins-bonus.handler.ts +0 -119
  164. package/src/logic/handlers/steering-to-the-fortune-bonus.handler.ts +0 -118
  165. package/src/logic/handlers/treasure-hunt-bonus.handler.ts +0 -232
  166. package/src/rng/DummyRngClient.ts +0 -108
  167. package/src/rng/rng-client.factory.ts +0 -27
  168. package/src/rng/rng-client.interface.ts +0 -38
  169. package/src/rng/rng-service.ts +0 -130
  170. package/src/validation/abstract-game-logic-config.validator.ts +0 -20
  171. package/src/validation/bonnys-fortune/bonnys-fortune-config.dto.ts +0 -379
  172. package/src/validation/bonnys-fortune/bonnys-fortune-config.validator.ts +0 -8
  173. package/src/validation/custom-decorators/IsNestedIntArray.ts +0 -29
  174. package/src/validation/game-logic-config-validation.service.ts +0 -28
  175. package/src/validation/reel-strips-config-validation.service.ts +0 -29
package/README.md CHANGED
@@ -241,19 +241,19 @@ The game engine supports 6 different command types:
241
241
 
242
242
  **Returns**: Updated state
243
243
 
244
- #### 5. CHEAT_TRIGGER_BONUS (Testing/Admin)
244
+ #### 5. DEBUG_TRIGGER_BONUS (Testing/Admin)
245
245
 
246
246
  **Purpose**: Force trigger specific bonus game
247
247
 
248
- **Payload**: `CheatTriggerBonusCommand`
248
+ **Payload**: `DebugTriggerBonusCommand`
249
249
 
250
250
  **Returns**: State with pending bonus
251
251
 
252
- #### 6. CHEAT_UPDATE_BONUS_METER_PROGRESS (Testing/Admin)
252
+ #### 6. DEBUG_UPDATE_BONUS_METER_PROGRESS (Testing/Admin)
253
253
 
254
254
  **Purpose**: Manually set bonus meter progress
255
255
 
256
- **Payload**: `CheatUpdateBonusMeterProgressCommand`
256
+ **Payload**: `DebugUpdateBonusMeterProgressCommand`
257
257
 
258
258
  **Returns**: Updated meter state
259
259
 
@@ -552,26 +552,26 @@ RNG_CLIENT_GRPC_URL=grpc://rng-prod.omnitronix.com:50051
552
552
  RNG_CLIENT_POOL_SIZE=5000
553
553
  ```
554
554
 
555
- ### Example 4: Testing with Cheat Commands
555
+ ### Example 4: Testing with Debug Commands
556
556
 
557
557
  ```typescript
558
558
  async function testBonusGame() {
559
559
  const gameEngine = new BonnysFortuneV1GameEngine();
560
-
560
+
561
561
  // Initialize session
562
562
  const initResult = await gameEngine.processCommand({}, {}, {
563
563
  id: 'test-init',
564
564
  type: 'INIT_SESSION_STATE',
565
565
  payload: { betAmountThresholds: [10], defaultBetAmount: 10 }
566
566
  });
567
-
567
+
568
568
  // Force trigger treasure hunt bonus
569
- const cheatResult = await gameEngine.processCommand(
569
+ const debugResult = await gameEngine.processCommand(
570
570
  initResult.publicState,
571
571
  initResult.privateState,
572
572
  {
573
- id: 'test-cheat',
574
- type: 'CHEAT_TRIGGER_BONUS',
573
+ id: 'test-debug',
574
+ type: 'DEBUG_TRIGGER_BONUS',
575
575
  payload: {
576
576
  sessionId: 'test-session',
577
577
  bonusType: 'bonusGame1',
@@ -579,11 +579,11 @@ async function testBonusGame() {
579
579
  }
580
580
  }
581
581
  );
582
-
582
+
583
583
  // Now start the bonus
584
584
  const bonusResult = await gameEngine.processCommand(
585
- cheatResult.publicState,
586
- cheatResult.privateState,
585
+ debugResult.publicState,
586
+ debugResult.privateState,
587
587
  {
588
588
  id: 'test-bonus-start',
589
589
  type: 'START_BONUS_ROUND',
@@ -593,15 +593,25 @@ async function testBonusGame() {
593
593
  betAmount: 10,
594
594
  gameCode: 'bonnys-fortune',
595
595
  gameVersion: '1.0.0',
596
- bonusId: cheatResult.privateState.pendingBonuses[0].bonusId
596
+ bonusId: debugResult.privateState.pendingBonuses[0].bonusId
597
597
  }
598
598
  }
599
599
  );
600
-
600
+
601
601
  console.log('Bonus results:', bonusResult.outcome);
602
602
  }
603
603
  ```
604
604
 
605
+ ## Testing
606
+
607
+ This engine uses [@omnitronix/game-test-utils](https://github.com/omnitronix/game-test-utils) for comprehensive testing including:
608
+ - GLI-19 compliance validation
609
+ - RNG security testing
610
+ - Statistical RTP simulation
611
+ - Symbol distribution analysis
612
+
613
+ Run tests: `npm test`
614
+
605
615
  ## Development
606
616
 
607
617
  ### Running Tests
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Base Game Logic Tests — Bonnys Fortune
5
+ *
6
+ * Tests the core base game mechanics:
7
+ * - Screen generation (5x3 grid, 243 ways)
8
+ * - Win calculation (ways evaluation)
9
+ * - Bonus meter tracking and progression
10
+ * - Bet amount handling
11
+ * - Per-bet-amount meter state
12
+ */
13
+ const test_engine_factory_1 = require("./helpers/test-engine-factory");
14
+ describe('Base Game Logic — Bonnys Fortune', () => {
15
+ beforeEach(() => {
16
+ (0, test_engine_factory_1.resetCommandIdCounter)();
17
+ });
18
+ describe('Screen Generation', () => {
19
+ it('should generate a 5x3 screen on each spin', async () => {
20
+ const engine = (0, test_engine_factory_1.createEngine)();
21
+ const session = await (0, test_engine_factory_1.initSession)(engine);
22
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
23
+ expect(result.success).toBe(true);
24
+ const screen = result.outcome?.result?.screen ?? result.outcome?.screen;
25
+ expect(screen).toBeDefined();
26
+ expect(screen.length).toBe(5);
27
+ for (const reel of screen) {
28
+ expect(reel.length).toBe(3);
29
+ }
30
+ });
31
+ it('should produce valid symbol IDs on screen', async () => {
32
+ const engine = (0, test_engine_factory_1.createEngine)();
33
+ const session = await (0, test_engine_factory_1.initSession)(engine);
34
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
35
+ expect(result.success).toBe(true);
36
+ const screen = result.outcome?.result?.screen ?? result.outcome?.screen;
37
+ for (const reel of screen) {
38
+ for (const symbol of reel) {
39
+ expect(typeof symbol).toBe('number');
40
+ expect(symbol).toBeGreaterThanOrEqual(0);
41
+ }
42
+ }
43
+ });
44
+ it('should produce different screens across multiple spins', async () => {
45
+ // Use LCG RNG to avoid DummyRng producing identical screens and
46
+ // constant bonus meter triggers that prevent base game spins
47
+ const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(54321);
48
+ const session = await (0, test_engine_factory_1.initSession)(engine);
49
+ let pub = session.publicState;
50
+ let priv = session.privateState;
51
+ const screens = [];
52
+ for (let i = 0; i < 50; i++) {
53
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN') {
54
+ // Bonus triggered — complete it via extractFinalBonusState
55
+ if (priv.pendingBonuses?.length > 0) {
56
+ const bonus = priv.pendingBonuses[0];
57
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, pub, priv, bonus.bonusType);
58
+ const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
59
+ pub = finalState.publicState;
60
+ priv = finalState.privateState;
61
+ // Handle chained bonuses (steering fortune)
62
+ while (priv.pendingBonuses?.length > 0) {
63
+ const nextBonus = priv.pendingBonuses[0];
64
+ const chainResult = await (0, test_engine_factory_1.startBonusRound)(engine, pub, priv, nextBonus.bonusType);
65
+ const chainFinal = (0, test_engine_factory_1.extractFinalBonusState)(chainResult);
66
+ pub = chainFinal.publicState;
67
+ priv = chainFinal.privateState;
68
+ }
69
+ }
70
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
71
+ break;
72
+ }
73
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
74
+ expect(result.success).toBe(true);
75
+ const screen = result.outcome?.result?.screen ?? result.outcome?.screen ?? result.privateState.screen;
76
+ screens.push(JSON.stringify(screen));
77
+ pub = result.publicState;
78
+ priv = result.privateState;
79
+ }
80
+ const unique = new Set(screens);
81
+ expect(unique.size).toBeGreaterThan(1);
82
+ });
83
+ });
84
+ describe('Win Calculation', () => {
85
+ it('should report playerWinning as non-negative number', async () => {
86
+ const engine = (0, test_engine_factory_1.createEngine)();
87
+ const session = await (0, test_engine_factory_1.initSession)(engine);
88
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
89
+ expect(result.success).toBe(true);
90
+ const playerWinning = result.outcome?.result?.playerWinning ?? result.outcome?.playerWinning;
91
+ if (playerWinning !== undefined) {
92
+ expect(playerWinning).toBeGreaterThanOrEqual(0);
93
+ expect(typeof playerWinning).toBe('number');
94
+ }
95
+ });
96
+ it('should produce finite win amounts', async () => {
97
+ const engine = (0, test_engine_factory_1.createEngine)();
98
+ const session = await (0, test_engine_factory_1.initSession)(engine);
99
+ let pub = session.publicState;
100
+ let priv = session.privateState;
101
+ for (let i = 0; i < 20; i++) {
102
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
103
+ break;
104
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
105
+ expect(result.success).toBe(true);
106
+ const playerWinning = result.outcome?.result?.playerWinning ?? result.outcome?.playerWinning;
107
+ if (playerWinning !== undefined) {
108
+ expect(Number.isFinite(playerWinning)).toBe(true);
109
+ }
110
+ pub = result.publicState;
111
+ priv = result.privateState;
112
+ }
113
+ });
114
+ });
115
+ describe('Bonus Meter Mechanics', () => {
116
+ it('should have bonus meters in public state after init', async () => {
117
+ const engine = (0, test_engine_factory_1.createEngine)();
118
+ const session = await (0, test_engine_factory_1.initSession)(engine);
119
+ expect(session.publicState.bonusMeters).toBeDefined();
120
+ const keys = Object.keys(session.publicState.bonusMeters || {});
121
+ expect(keys.length).toBeGreaterThan(0);
122
+ });
123
+ it('should have valid threshold and progress for each meter', async () => {
124
+ const engine = (0, test_engine_factory_1.createEngine)();
125
+ const session = await (0, test_engine_factory_1.initSession)(engine);
126
+ const meters = session.publicState.bonusMeters;
127
+ for (const [, meter] of Object.entries(meters || {})) {
128
+ const m = meter;
129
+ expect(m.threshold).toBeGreaterThan(0);
130
+ expect(m.progress).toBeGreaterThanOrEqual(0);
131
+ expect(typeof m.threshold).toBe('number');
132
+ expect(typeof m.progress).toBe('number');
133
+ }
134
+ });
135
+ it('should maintain meter state across spins', async () => {
136
+ const engine = (0, test_engine_factory_1.createEngine)();
137
+ const session = await (0, test_engine_factory_1.initSession)(engine);
138
+ let pub = session.publicState;
139
+ let priv = session.privateState;
140
+ for (let i = 0; i < 10; i++) {
141
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
142
+ break;
143
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
144
+ expect(result.success).toBe(true);
145
+ expect(result.publicState.bonusMeters).toBeDefined();
146
+ // Verify meter structure integrity
147
+ for (const [, meter] of Object.entries(result.publicState.bonusMeters || {})) {
148
+ const m = meter;
149
+ expect(m.threshold).toBeGreaterThan(0);
150
+ expect(m.progress).toBeGreaterThanOrEqual(0);
151
+ expect(m.progress).toBeLessThanOrEqual(m.threshold);
152
+ }
153
+ pub = result.publicState;
154
+ priv = result.privateState;
155
+ }
156
+ });
157
+ it('should not allow meter progress to exceed threshold', async () => {
158
+ const engine = (0, test_engine_factory_1.createEngine)();
159
+ const session = await (0, test_engine_factory_1.initSession)(engine);
160
+ let pub = session.publicState;
161
+ let priv = session.privateState;
162
+ for (let i = 0; i < 30; i++) {
163
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
164
+ break;
165
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
166
+ expect(result.success).toBe(true);
167
+ for (const [, meter] of Object.entries(result.publicState.bonusMeters || {})) {
168
+ const m = meter;
169
+ expect(m.progress).toBeLessThanOrEqual(m.threshold);
170
+ }
171
+ pub = result.publicState;
172
+ priv = result.privateState;
173
+ }
174
+ });
175
+ it('should have per-bet-amount meter state in private state', async () => {
176
+ const engine = (0, test_engine_factory_1.createEngine)();
177
+ const session = await (0, test_engine_factory_1.initSession)(engine);
178
+ expect(session.privateState.bonusMetersByAmount).toBeDefined();
179
+ const amounts = Object.keys(session.privateState.bonusMetersByAmount || {});
180
+ expect(amounts.length).toBeGreaterThan(0);
181
+ });
182
+ });
183
+ describe('RNG Outcome Tracking', () => {
184
+ it('should produce valid RNG outcome on each spin', async () => {
185
+ const engine = (0, test_engine_factory_1.createEngine)();
186
+ const session = await (0, test_engine_factory_1.initSession)(engine);
187
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
188
+ expect(result.success).toBe(true);
189
+ expect(result.rngOutcome).toBeDefined();
190
+ const validation = (0, test_engine_factory_1.validateRngOutcome)(result.rngOutcome);
191
+ expect(validation.valid).toBe(true);
192
+ });
193
+ });
194
+ describe('Bet Amount Handling', () => {
195
+ it('should accept different bet amounts', async () => {
196
+ const engine = (0, test_engine_factory_1.createEngine)();
197
+ const session = await (0, test_engine_factory_1.initSession)(engine, 0.5);
198
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState, 0.5);
199
+ expect(result.success).toBe(true);
200
+ });
201
+ it('should update currentBetAmount in public state', async () => {
202
+ const engine = (0, test_engine_factory_1.createEngine)();
203
+ const session = await (0, test_engine_factory_1.initSession)(engine, 2.0);
204
+ expect(session.publicState.currentBetAmount).toBe(2.0);
205
+ });
206
+ it('should switch meter state when bet amount changes', async () => {
207
+ const engine = (0, test_engine_factory_1.createEngine)();
208
+ const session = await (0, test_engine_factory_1.initSession)(engine, 1.0);
209
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState, 1.0);
210
+ expect(result1.success).toBe(true);
211
+ if (result1.privateState.nextSpinType === 'BASE_GAME_SPIN') {
212
+ // Change bet amount
213
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState, 2.0);
214
+ expect(result2.success).toBe(true);
215
+ // Meters should still be valid
216
+ expect(result2.publicState.bonusMeters).toBeDefined();
217
+ }
218
+ });
219
+ });
220
+ describe('Mock RNG Determinism', () => {
221
+ it('should produce deterministic results with mock RNG', async () => {
222
+ const { engine: engine1 } = (0, test_engine_factory_1.createEngineWithMockRng)([42, 42, 42, 42, 42]);
223
+ const { engine: engine2 } = (0, test_engine_factory_1.createEngineWithMockRng)([42, 42, 42, 42, 42]);
224
+ const session1 = await (0, test_engine_factory_1.initSession)(engine1);
225
+ const session2 = await (0, test_engine_factory_1.initSession)(engine2);
226
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine1, session1.publicState, session1.privateState);
227
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine2, session2.publicState, session2.privateState);
228
+ expect(result1.success).toBe(true);
229
+ expect(result2.success).toBe(true);
230
+ const screen1 = JSON.stringify(result1.outcome?.screen || result1.privateState.screen);
231
+ const screen2 = JSON.stringify(result2.outcome?.screen || result2.privateState.screen);
232
+ expect(screen1).toBe(screen2);
233
+ });
234
+ });
235
+ describe('Multiple Spin Stability', () => {
236
+ it('should handle 30 consecutive base game spins', async () => {
237
+ const engine = (0, test_engine_factory_1.createEngine)();
238
+ const session = await (0, test_engine_factory_1.initSession)(engine);
239
+ let pub = session.publicState;
240
+ let priv = session.privateState;
241
+ let spinCount = 0;
242
+ for (let i = 0; i < 30; i++) {
243
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
244
+ break;
245
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
246
+ expect(result.success).toBe(true);
247
+ spinCount++;
248
+ pub = result.publicState;
249
+ priv = result.privateState;
250
+ }
251
+ expect(spinCount).toBeGreaterThan(0);
252
+ });
253
+ });
254
+ });
255
+ //# sourceMappingURL=base-game.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-game.test.js","sourceRoot":"","sources":["../../src/__tests__/base-game.test.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ describe('BonnysFortuneV1GameEngine', () => {
10
10
  it('should initialize the game engine and return info', async () => {
11
11
  const info = gameEngine.getGameEngineInfo();
12
12
  expect(info.gameCode).toBe('bonnys-fortune');
13
- expect(info.version).toBe('1.0.0');
13
+ expect(info.version).toBe('1.5.0');
14
14
  expect(info.rtp).toBe(96);
15
15
  expect(info.gameType).toBe('slot');
16
16
  });