@omnitronix/lucky-sharky-game-engine 1.0.9 → 1.2.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 (108) hide show
  1. package/README.md +10 -0
  2. package/dist/__tests__/base-game.test.d.ts +2 -0
  3. package/dist/__tests__/base-game.test.d.ts.map +1 -0
  4. package/dist/__tests__/base-game.test.js +262 -0
  5. package/dist/__tests__/base-game.test.js.map +1 -0
  6. package/dist/__tests__/bonus-handlers.test.d.ts +2 -0
  7. package/dist/__tests__/bonus-handlers.test.d.ts.map +1 -0
  8. package/dist/__tests__/bonus-handlers.test.js +243 -0
  9. package/dist/__tests__/bonus-handlers.test.js.map +1 -0
  10. package/dist/__tests__/error-paths.test.d.ts +2 -0
  11. package/dist/__tests__/error-paths.test.d.ts.map +1 -0
  12. package/dist/__tests__/error-paths.test.js +328 -0
  13. package/dist/__tests__/error-paths.test.js.map +1 -0
  14. package/dist/__tests__/free-spins-handler.test.d.ts +2 -0
  15. package/dist/__tests__/free-spins-handler.test.d.ts.map +1 -0
  16. package/dist/__tests__/free-spins-handler.test.js +410 -0
  17. package/dist/__tests__/free-spins-handler.test.js.map +1 -0
  18. package/dist/__tests__/helpers/test-engine-factory.d.ts +98 -0
  19. package/dist/__tests__/helpers/test-engine-factory.d.ts.map +1 -0
  20. package/dist/__tests__/helpers/test-engine-factory.js +236 -0
  21. package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
  22. package/dist/__tests__/hold-win-handler.test.d.ts +2 -0
  23. package/dist/__tests__/hold-win-handler.test.d.ts.map +1 -0
  24. package/dist/__tests__/hold-win-handler.test.js +481 -0
  25. package/dist/__tests__/hold-win-handler.test.js.map +1 -0
  26. package/dist/__tests__/rng-gli19-compliance.test.d.ts +0 -4
  27. package/dist/__tests__/rng-gli19-compliance.test.d.ts.map +1 -1
  28. package/dist/__tests__/rng-gli19-compliance.test.js +232 -198
  29. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -1
  30. package/dist/__tests__/rng-security.test.d.ts +2 -0
  31. package/dist/__tests__/rng-security.test.d.ts.map +1 -0
  32. package/dist/__tests__/rng-security.test.js +379 -0
  33. package/dist/__tests__/rng-security.test.js.map +1 -0
  34. package/dist/__tests__/rtp-simulation.test.d.ts +0 -4
  35. package/dist/__tests__/rtp-simulation.test.d.ts.map +1 -1
  36. package/dist/__tests__/rtp-simulation.test.js +228 -153
  37. package/dist/__tests__/rtp-simulation.test.js.map +1 -1
  38. package/dist/__tests__/spin-generator.test.d.ts +2 -0
  39. package/dist/__tests__/spin-generator.test.d.ts.map +1 -0
  40. package/dist/__tests__/spin-generator.test.js +375 -0
  41. package/dist/__tests__/spin-generator.test.js.map +1 -0
  42. package/dist/__tests__/state-transitions.test.d.ts +2 -0
  43. package/dist/__tests__/state-transitions.test.d.ts.map +1 -0
  44. package/dist/__tests__/state-transitions.test.js +249 -0
  45. package/dist/__tests__/state-transitions.test.js.map +1 -0
  46. package/dist/__tests__/symbol-distribution.test.d.ts +2 -0
  47. package/dist/__tests__/symbol-distribution.test.d.ts.map +1 -0
  48. package/dist/__tests__/symbol-distribution.test.js +210 -0
  49. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  50. package/dist/__tests__/win-calculator.test.d.ts +2 -0
  51. package/dist/__tests__/win-calculator.test.d.ts.map +1 -0
  52. package/dist/__tests__/win-calculator.test.js +516 -0
  53. package/dist/__tests__/win-calculator.test.js.map +1 -0
  54. package/dist/config/game-logic-config/game-logic-config.d.ts.map +1 -1
  55. package/dist/config/game-logic-config/game-logic-config.js +0 -25
  56. package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
  57. package/dist/config/reel-strips-config/reels-BASE.csv +0 -0
  58. package/dist/config/reel-strips-config/reels-FREESPINS.csv +0 -0
  59. package/dist/game-engine.interface.d.ts +2 -0
  60. package/dist/game-engine.interface.d.ts.map +1 -1
  61. package/dist/index.d.ts +1 -0
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/logic/game-logic-config.interface.d.ts +0 -8
  64. package/dist/logic/game-logic-config.interface.d.ts.map +1 -1
  65. package/dist/logic/handlers/base-game.handler.d.ts.map +1 -1
  66. package/dist/logic/handlers/base-game.handler.js +3 -6
  67. package/dist/logic/handlers/base-game.handler.js.map +1 -1
  68. package/dist/logic/handlers/free-spins.handler.d.ts.map +1 -1
  69. package/dist/logic/handlers/free-spins.handler.js +2 -2
  70. package/dist/logic/handlers/free-spins.handler.js.map +1 -1
  71. package/dist/logic/handlers/hold-win-bonus.handler.d.ts +0 -5
  72. package/dist/logic/handlers/hold-win-bonus.handler.d.ts.map +1 -1
  73. package/dist/logic/handlers/hold-win-bonus.handler.js +28 -181
  74. package/dist/logic/handlers/hold-win-bonus.handler.js.map +1 -1
  75. package/dist/logic/lucky-sharky.spin-generator.d.ts +2 -2
  76. package/dist/logic/lucky-sharky.spin-generator.d.ts.map +1 -1
  77. package/dist/logic/lucky-sharky.spin-generator.js +61 -161
  78. package/dist/logic/lucky-sharky.spin-generator.js.map +1 -1
  79. package/dist/logic/lucky-sharky.types.d.ts +0 -6
  80. package/dist/logic/lucky-sharky.types.d.ts.map +1 -1
  81. package/dist/logic/lucky-sharky.types.js.map +1 -1
  82. package/dist/logic/lucky-sharky.win-calculator.d.ts.map +1 -1
  83. package/dist/logic/lucky-sharky.win-calculator.js +4 -9
  84. package/dist/logic/lucky-sharky.win-calculator.js.map +1 -1
  85. package/dist/lucky-sharky-v1.game-engine.d.ts +2 -2
  86. package/dist/lucky-sharky-v1.game-engine.d.ts.map +1 -1
  87. package/dist/lucky-sharky-v1.game-engine.js +2 -2
  88. package/dist/lucky-sharky-v1.game-engine.js.map +1 -1
  89. package/dist/rng/rng-client.factory.d.ts.map +1 -1
  90. package/dist/rng/rng-client.factory.js +1 -45
  91. package/dist/rng/rng-client.factory.js.map +1 -1
  92. package/package.json +4 -3
  93. package/dist/__tests__/rng-seed-security.test.d.ts +0 -6
  94. package/dist/__tests__/rng-seed-security.test.d.ts.map +0 -1
  95. package/dist/__tests__/rng-seed-security.test.js +0 -263
  96. package/dist/__tests__/rng-seed-security.test.js.map +0 -1
  97. package/dist/__tests__/rng-seed-type.test.d.ts +0 -16
  98. package/dist/__tests__/rng-seed-type.test.d.ts.map +0 -1
  99. package/dist/__tests__/rng-seed-type.test.js +0 -288
  100. package/dist/__tests__/rng-seed-type.test.js.map +0 -1
  101. package/dist/__tests__/rng-stress-boundary.test.d.ts +0 -5
  102. package/dist/__tests__/rng-stress-boundary.test.d.ts.map +0 -1
  103. package/dist/__tests__/rng-stress-boundary.test.js +0 -395
  104. package/dist/__tests__/rng-stress-boundary.test.js.map +0 -1
  105. package/dist/logger/logger.d.ts +0 -9
  106. package/dist/logger/logger.d.ts.map +0 -1
  107. package/dist/logger/logger.js +0 -35
  108. package/dist/logger/logger.js.map +0 -1
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * State Transition Tests — Lucky Sharky
5
+ *
6
+ * Validates the state machine that governs game flow:
7
+ * - INIT_SESSION_STATE → BASE_GAME_SPIN
8
+ * - BASE_GAME_SPIN → BASE_GAME_SPIN (no trigger)
9
+ * - BASE_GAME_SPIN → FREE_SPIN (scatter trigger via debug)
10
+ * - BASE_GAME_SPIN → HOLD_WIN_BONUS_SPIN (gold coin trigger via debug)
11
+ * - FREE_SPIN → BASE_GAME_SPIN (after completion)
12
+ * - HOLD_WIN_BONUS_SPIN → BASE_GAME_SPIN (after completion)
13
+ * - Bet amount change resets booster
14
+ * - Invalid transitions rejected
15
+ */
16
+ const test_engine_factory_1 = require("./helpers/test-engine-factory");
17
+ describe('State Transitions — Lucky Sharky', () => {
18
+ beforeEach(() => {
19
+ (0, test_engine_factory_1.resetCommandIdCounter)();
20
+ });
21
+ describe('Initial State', () => {
22
+ it('should start in BASE_GAME_SPIN state after init', async () => {
23
+ const engine = (0, test_engine_factory_1.createEngine)();
24
+ const session = await (0, test_engine_factory_1.initSession)(engine);
25
+ expect(session.privateState.nextSpinType).toBe('BASE_GAME_SPIN');
26
+ });
27
+ it('should have empty pending bonuses after init', async () => {
28
+ const engine = (0, test_engine_factory_1.createEngine)();
29
+ const session = await (0, test_engine_factory_1.initSession)(engine);
30
+ expect(session.privateState.pendingBonuses).toBeDefined();
31
+ expect(session.privateState.pendingBonuses.length).toBe(0);
32
+ });
33
+ it('should have no active bonus after init', async () => {
34
+ const engine = (0, test_engine_factory_1.createEngine)();
35
+ const session = await (0, test_engine_factory_1.initSession)(engine);
36
+ expect(session.privateState.activeBonus).toBeUndefined();
37
+ });
38
+ it('should initialize booster at level 0', async () => {
39
+ const engine = (0, test_engine_factory_1.createEngine)();
40
+ const session = await (0, test_engine_factory_1.initSession)(engine);
41
+ expect(session.publicState.boosterLevel).toBe(0);
42
+ expect(session.privateState.boosterLevel).toBe(0);
43
+ });
44
+ it('should produce a valid initial screen', async () => {
45
+ const engine = (0, test_engine_factory_1.createEngine)();
46
+ const session = await (0, test_engine_factory_1.initSession)(engine);
47
+ // Screen should be 5 reels x 3 rows
48
+ const screen = session.privateState.screen;
49
+ expect(screen).toBeDefined();
50
+ expect(screen.length).toBe(5);
51
+ for (const reel of screen) {
52
+ expect(reel.length).toBe(3);
53
+ }
54
+ });
55
+ });
56
+ describe('Base Game Transitions', () => {
57
+ it('should stay in BASE_GAME_SPIN when no bonus is triggered', async () => {
58
+ const engine = (0, test_engine_factory_1.createEngine)();
59
+ const session = await (0, test_engine_factory_1.initSession)(engine);
60
+ // Execute multiple spins - at least some should stay in base game
61
+ let pub = session.publicState;
62
+ let priv = session.privateState;
63
+ let baseGameCount = 0;
64
+ for (let i = 0; i < 10; i++) {
65
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
66
+ break;
67
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
68
+ expect(result.success).toBe(true);
69
+ if (result.privateState.nextSpinType === 'BASE_GAME_SPIN') {
70
+ baseGameCount++;
71
+ }
72
+ pub = result.publicState;
73
+ priv = result.privateState;
74
+ }
75
+ expect(baseGameCount).toBeGreaterThan(0);
76
+ });
77
+ it('should update screen after each spin', async () => {
78
+ const engine = (0, test_engine_factory_1.createEngine)();
79
+ const session = await (0, test_engine_factory_1.initSession)(engine);
80
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
81
+ expect(result.success).toBe(true);
82
+ // Outcome should contain a screen
83
+ expect(result.outcome).toBeDefined();
84
+ if (result.outcome?.screen) {
85
+ expect(result.outcome.screen.length).toBe(5);
86
+ }
87
+ });
88
+ it('should carry state forward between spins', async () => {
89
+ const engine = (0, test_engine_factory_1.createEngine)();
90
+ const session = await (0, test_engine_factory_1.initSession)(engine);
91
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
92
+ expect(result1.success).toBe(true);
93
+ if (result1.privateState.nextSpinType === 'BASE_GAME_SPIN') {
94
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState);
95
+ expect(result2.success).toBe(true);
96
+ }
97
+ });
98
+ });
99
+ describe('Free Spins Transition (via Debug)', () => {
100
+ it('should transition to FREE_SPIN after debug trigger', async () => {
101
+ const engine = (0, test_engine_factory_1.createEngine)();
102
+ const session = await (0, test_engine_factory_1.initSession)(engine);
103
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'FREE_SPINS');
104
+ expect(debugResult.success).toBe(true);
105
+ expect(debugResult.privateState.pendingBonuses.length).toBeGreaterThan(0);
106
+ const bonus = debugResult.privateState.pendingBonuses[0];
107
+ expect(bonus.bonusType).toMatch(/free.*spin/i);
108
+ });
109
+ it('should complete free spins and return to BASE_GAME_SPIN', async () => {
110
+ const engine = (0, test_engine_factory_1.createEngine)();
111
+ const session = await (0, test_engine_factory_1.initSession)(engine);
112
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'FREE_SPINS');
113
+ if (!debugResult.success)
114
+ return;
115
+ const bonus = debugResult.privateState.pendingBonuses[0];
116
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
117
+ expect(bonusResult.success).toBe(true);
118
+ // After completing free spins, should return to base game
119
+ expect(bonusResult.privateState.nextSpinType).toBe('BASE_GAME_SPIN');
120
+ });
121
+ it('should clear pending bonuses after starting free spins', async () => {
122
+ const engine = (0, test_engine_factory_1.createEngine)();
123
+ const session = await (0, test_engine_factory_1.initSession)(engine);
124
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'FREE_SPINS');
125
+ if (!debugResult.success)
126
+ return;
127
+ const bonus = debugResult.privateState.pendingBonuses[0];
128
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
129
+ expect(bonusResult.success).toBe(true);
130
+ expect(bonusResult.privateState.pendingBonuses.length).toBe(0);
131
+ });
132
+ });
133
+ describe('Hold-Win Bonus Transition (via Debug)', () => {
134
+ it('should transition to HOLD_WIN_BONUS_SPIN after debug trigger', async () => {
135
+ const engine = (0, test_engine_factory_1.createEngine)();
136
+ const session = await (0, test_engine_factory_1.initSession)(engine);
137
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'HOLD_WIN_BONUS');
138
+ expect(debugResult.success).toBe(true);
139
+ expect(debugResult.privateState.pendingBonuses.length).toBeGreaterThan(0);
140
+ const bonus = debugResult.privateState.pendingBonuses[0];
141
+ expect(bonus.bonusType).toMatch(/hold.*win/i);
142
+ });
143
+ it('should complete hold-win and return to BASE_GAME_SPIN', async () => {
144
+ const engine = (0, test_engine_factory_1.createEngine)();
145
+ const session = await (0, test_engine_factory_1.initSession)(engine);
146
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'HOLD_WIN_BONUS');
147
+ if (!debugResult.success)
148
+ return;
149
+ const bonus = debugResult.privateState.pendingBonuses[0];
150
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
151
+ expect(bonusResult.success).toBe(true);
152
+ expect(bonusResult.privateState.nextSpinType).toBe('BASE_GAME_SPIN');
153
+ });
154
+ it('should clear pending bonuses after completing hold-win', async () => {
155
+ const engine = (0, test_engine_factory_1.createEngine)();
156
+ const session = await (0, test_engine_factory_1.initSession)(engine);
157
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'HOLD_WIN_BONUS');
158
+ if (!debugResult.success)
159
+ return;
160
+ const bonus = debugResult.privateState.pendingBonuses[0];
161
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, debugResult.publicState, debugResult.privateState, bonus.bonusType);
162
+ expect(bonusResult.success).toBe(true);
163
+ expect(bonusResult.privateState.pendingBonuses.length).toBe(0);
164
+ });
165
+ });
166
+ describe('GET_SYMBOLS Command', () => {
167
+ it('should return symbol definitions', async () => {
168
+ const engine = (0, test_engine_factory_1.createEngine)();
169
+ await (0, test_engine_factory_1.waitForEngineReady)(engine);
170
+ const result = await engine.processCommand(null, null, {
171
+ id: (0, test_engine_factory_1.nextCommandId)('symbols'),
172
+ type: 'GET_SYMBOLS',
173
+ payload: {},
174
+ });
175
+ expect(result.success).toBe(true);
176
+ expect(result.outcome).toBeDefined();
177
+ });
178
+ });
179
+ describe('Invalid Transitions', () => {
180
+ it('should reject SPIN when bonus is pending and nextSpinType is not BASE', async () => {
181
+ const engine = (0, test_engine_factory_1.createEngine)();
182
+ const session = await (0, test_engine_factory_1.initSession)(engine);
183
+ // Force a non-base spin type via debug trigger
184
+ const debugResult = await (0, test_engine_factory_1.debugTriggerBonus)(engine, session.publicState, session.privateState, 'FREE_SPINS');
185
+ if (!debugResult.success)
186
+ return;
187
+ // If the engine sets nextSpinType to something other than BASE_GAME_SPIN,
188
+ // a regular SPIN should fail or be handled differently
189
+ if (debugResult.privateState.nextSpinType !== 'BASE_GAME_SPIN') {
190
+ try {
191
+ const spinResult = await (0, test_engine_factory_1.executeSpin)(engine, debugResult.publicState, debugResult.privateState);
192
+ // Some engines allow spin but redirect; others reject
193
+ expect(spinResult).toBeDefined();
194
+ }
195
+ catch (error) {
196
+ expect(error).toBeDefined();
197
+ }
198
+ }
199
+ });
200
+ it('should reject START_BONUS_ROUND with invalid bonus ID', async () => {
201
+ const engine = (0, test_engine_factory_1.createEngine)();
202
+ const session = await (0, test_engine_factory_1.initSession)(engine);
203
+ try {
204
+ const result = await engine.processCommand(session.publicState, session.privateState, {
205
+ id: (0, test_engine_factory_1.nextCommandId)('bonus'),
206
+ type: 'START_BONUS_ROUND',
207
+ payload: {
208
+ sessionId: 'test',
209
+ bonusId: 'non-existent-id',
210
+ bonusType: 'FREE_SPINS',
211
+ betAmount: 1.0,
212
+ gameId: 'lucky-sharky',
213
+ gameVersion: '1.0.0',
214
+ },
215
+ });
216
+ // Should fail
217
+ if (result.success === false) {
218
+ expect(result.success).toBe(false);
219
+ }
220
+ }
221
+ catch (error) {
222
+ expect(error).toBeDefined();
223
+ }
224
+ });
225
+ it('should reject START_BONUS_ROUND when no bonuses are pending', async () => {
226
+ const engine = (0, test_engine_factory_1.createEngine)();
227
+ const session = await (0, test_engine_factory_1.initSession)(engine);
228
+ try {
229
+ const result = await engine.processCommand(session.publicState, session.privateState, {
230
+ id: (0, test_engine_factory_1.nextCommandId)('bonus'),
231
+ type: 'START_BONUS_ROUND',
232
+ payload: {
233
+ sessionId: 'test',
234
+ bonusId: 'fake-id',
235
+ bonusType: 'FREE_SPINS',
236
+ betAmount: 1.0,
237
+ gameId: 'lucky-sharky',
238
+ gameVersion: '1.0.0',
239
+ },
240
+ });
241
+ expect(result.success).toBe(false);
242
+ }
243
+ catch (error) {
244
+ expect(error).toBeDefined();
245
+ }
246
+ });
247
+ });
248
+ });
249
+ //# sourceMappingURL=state-transitions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-transitions.test.js","sourceRoot":"","sources":["../../src/__tests__/state-transitions.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=symbol-distribution.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-distribution.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/symbol-distribution.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Symbol Distribution Tests — Lucky Sharky
5
+ *
6
+ * Validates that the reel strips produce fair symbol distributions:
7
+ * - All expected symbol types appear
8
+ * - Special symbols (wilds, scatters, bonus) occur at expected rates
9
+ * - No symbol dominates unfairly
10
+ * - Reel strip coverage is complete
11
+ *
12
+ * These tests are EXCLUDED from CI (jest testPathIgnorePatterns).
13
+ * Run manually: npx jest symbol-distribution --no-coverage
14
+ */
15
+ const test_engine_factory_1 = require("./helpers/test-engine-factory");
16
+ const game_test_utils_1 = require("@omnitronix/game-test-utils");
17
+ // Lucky Sharky symbol IDs (from types)
18
+ const SYMBOL_NAMES = {
19
+ 0: 'H1', 1: 'H2', 2: 'H3', 3: 'H4',
20
+ 4: 'M1', 5: 'M2',
21
+ 6: 'L1', 7: 'L2',
22
+ 8: 'WILD',
23
+ 9: 'BOOSTER', 10: 'COLLECT', 11: 'FREE_SPINS', 12: 'GOLD_COIN',
24
+ 13: 'C11', 14: 'C12', 15: 'C13', 16: 'C14', 17: 'C15',
25
+ 18: 'C21', 19: 'C22', 20: 'C23', 21: 'C24', 22: 'C25',
26
+ 23: 'C31', 24: 'C32', 25: 'C33', 26: 'C34', 27: 'C35',
27
+ 28: 'JACKPOT_MINI', 29: 'JACKPOT_MIDI', 30: 'JACKPOT_MAXI', 31: 'JACKPOT_MEGA',
28
+ };
29
+ // ---------------------------------------------------------------------------
30
+ // Tests
31
+ // ---------------------------------------------------------------------------
32
+ describe('Symbol Distribution — Lucky Sharky', () => {
33
+ it('should produce all base symbol types in 10K spins', async () => {
34
+ (0, test_engine_factory_1.resetCommandIdCounter)();
35
+ const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(game_test_utils_1.SEED_DEFAULT);
36
+ const session = await (0, test_engine_factory_1.initSession)(engine);
37
+ const symbolCounts = new Map();
38
+ let pub = session.publicState;
39
+ let priv = session.privateState;
40
+ let spinCount = 0;
41
+ for (let i = 0; i < game_test_utils_1.SYMBOL_DISTRIBUTION_SPIN_COUNT; i++) {
42
+ const result = await (0, test_engine_factory_1.safeExecuteSpin)(engine, pub, priv);
43
+ if (!result)
44
+ break;
45
+ // Count symbols in screen (5 reels × 3 rows)
46
+ // LS outcome has result wrapper: outcome.result.screen
47
+ const screen = result.outcome?.result?.screen
48
+ ?? result.outcome?.screens?.[0]?.screen
49
+ ?? result.publicState?.screen
50
+ ?? result.outcome?.screen;
51
+ if (screen) {
52
+ for (const reel of screen) {
53
+ for (const symbol of reel) {
54
+ symbolCounts.set(symbol, (symbolCounts.get(symbol) || 0) + 1);
55
+ }
56
+ }
57
+ }
58
+ spinCount++;
59
+ pub = result.publicState;
60
+ priv = result.privateState;
61
+ // Skip bonus states
62
+ if (priv.nextSpinType && priv.nextSpinType !== 'BASE_GAME_SPIN')
63
+ break;
64
+ }
65
+ // All base symbols (0-7) should appear with meaningful frequency
66
+ // In 10K spins (150K positions), each base symbol should appear at least 100 times
67
+ const minExpectedCount = Math.floor(spinCount * 0.01); // At least 1% of spins
68
+ for (let id = 0; id < game_test_utils_1.LUCKY_SHARKY_BASE_SYMBOL_COUNT; id++) {
69
+ const count = symbolCounts.get(id) || 0;
70
+ expect(count).toBeGreaterThanOrEqual(minExpectedCount);
71
+ }
72
+ console.log(`Symbol distribution (${spinCount} spins, ${spinCount * game_test_utils_1.LUCKY_SHARKY_GRID_POSITIONS} positions):`);
73
+ const totalPositions = spinCount * game_test_utils_1.LUCKY_SHARKY_GRID_POSITIONS; // 5 reels x 3 rows
74
+ const sorted = [...symbolCounts.entries()].sort((a, b) => b[1] - a[1]);
75
+ for (const [id, count] of sorted) {
76
+ const name = SYMBOL_NAMES[id] ?? `SYM_${id}`;
77
+ const pct = (count / totalPositions * 100).toFixed(2);
78
+ console.log(` ${name} (${id}): ${count} (${pct}%)`);
79
+ }
80
+ // Should have completed a meaningful number of spins (at least 1000)
81
+ expect(spinCount).toBeGreaterThanOrEqual(1000);
82
+ }, game_test_utils_1.TEST_TIMEOUT_STANDARD_MS);
83
+ it('should have wild symbols appear less frequently than base symbols', async () => {
84
+ (0, test_engine_factory_1.resetCommandIdCounter)();
85
+ const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(game_test_utils_1.SEED_STABLE_12345);
86
+ const session = await (0, test_engine_factory_1.initSession)(engine);
87
+ const symbolCounts = new Map();
88
+ let pub = session.publicState;
89
+ let priv = session.privateState;
90
+ let spinCount = 0;
91
+ for (let i = 0; i < game_test_utils_1.SYMBOL_DISTRIBUTION_SPIN_COUNT; i++) {
92
+ const result = await (0, test_engine_factory_1.safeExecuteSpin)(engine, pub, priv);
93
+ if (!result)
94
+ break;
95
+ // LS outcome has result wrapper: outcome.result.screen
96
+ const screen = result.outcome?.result?.screen
97
+ ?? result.outcome?.screens?.[0]?.screen
98
+ ?? result.publicState?.screen
99
+ ?? result.outcome?.screen;
100
+ if (screen) {
101
+ for (const reel of screen) {
102
+ for (const symbol of reel) {
103
+ symbolCounts.set(symbol, (symbolCounts.get(symbol) || 0) + 1);
104
+ }
105
+ }
106
+ }
107
+ spinCount++;
108
+ pub = result.publicState;
109
+ priv = result.privateState;
110
+ if (priv.nextSpinType && priv.nextSpinType !== 'BASE_GAME_SPIN')
111
+ break;
112
+ }
113
+ const wildCount = symbolCounts.get(8) || 0; // WILD
114
+ const baseTotal = Array.from({ length: game_test_utils_1.LUCKY_SHARKY_BASE_SYMBOL_COUNT }, (_, i) => symbolCounts.get(i) || 0)
115
+ .reduce((a, b) => a + b, 0);
116
+ const avgBase = baseTotal / game_test_utils_1.LUCKY_SHARKY_BASE_SYMBOL_COUNT;
117
+ console.log(`Wild frequency analysis (${spinCount} spins):`);
118
+ console.log(` Wild count: ${wildCount}`);
119
+ console.log(` Avg base symbol count: ${avgBase.toFixed(0)}`);
120
+ // Wilds should be rarer than average base symbol but present
121
+ // Lower bound: wilds should appear at least 0.1% of positions
122
+ const minWildCount = Math.floor(spinCount * game_test_utils_1.LUCKY_SHARKY_GRID_POSITIONS * 0.001);
123
+ expect(wildCount).toBeGreaterThanOrEqual(minWildCount);
124
+ // Upper bound: wilds should be less than 3x average base symbol
125
+ expect(wildCount).toBeLessThan(avgBase * 3);
126
+ }, game_test_utils_1.TEST_TIMEOUT_STANDARD_MS);
127
+ it('should have scatter symbols present but rare', async () => {
128
+ (0, test_engine_factory_1.resetCommandIdCounter)();
129
+ const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(game_test_utils_1.SEED_STABLE_54321);
130
+ const session = await (0, test_engine_factory_1.initSession)(engine);
131
+ let scatterCount = 0;
132
+ let totalPositions = 0;
133
+ let pub = session.publicState;
134
+ let priv = session.privateState;
135
+ let spinCount = 0;
136
+ for (let i = 0; i < game_test_utils_1.SYMBOL_DISTRIBUTION_SPIN_COUNT; i++) {
137
+ const result = await (0, test_engine_factory_1.safeExecuteSpin)(engine, pub, priv);
138
+ if (!result)
139
+ break;
140
+ // LS outcome has result wrapper: outcome.result.screen
141
+ const screen = result.outcome?.result?.screen
142
+ ?? result.outcome?.screens?.[0]?.screen
143
+ ?? result.publicState?.screen
144
+ ?? result.outcome?.screen;
145
+ if (screen) {
146
+ for (const reel of screen) {
147
+ for (const symbol of reel) {
148
+ totalPositions++;
149
+ if (symbol === 11)
150
+ scatterCount++; // FREE_SPINS scatter
151
+ }
152
+ }
153
+ }
154
+ spinCount++;
155
+ pub = result.publicState;
156
+ priv = result.privateState;
157
+ if (priv.nextSpinType && priv.nextSpinType !== 'BASE_GAME_SPIN')
158
+ break;
159
+ }
160
+ const scatterRate = totalPositions > 0 ? (scatterCount / totalPositions * 100) : 0;
161
+ console.log(`Scatter frequency (${spinCount} spins):`);
162
+ console.log(` Scatter count: ${scatterCount} / ${totalPositions}`);
163
+ console.log(` Rate: ${scatterRate.toFixed(2)}%`);
164
+ // Scatters should be present (lower bound: at least 0.01% of positions)
165
+ const minScatterRate = 0.01;
166
+ expect(scatterRate).toBeGreaterThanOrEqual(minScatterRate);
167
+ // Scatters should be rare (upper bound: < 10% of all positions)
168
+ expect(scatterRate).toBeLessThan(game_test_utils_1.MAX_SCATTER_RATE_PERCENT);
169
+ }, game_test_utils_1.TEST_TIMEOUT_STANDARD_MS);
170
+ it('should cover multiple unique symbols per spin', async () => {
171
+ (0, test_engine_factory_1.resetCommandIdCounter)();
172
+ const { engine } = (0, test_engine_factory_1.createEngineWithLcgRng)(game_test_utils_1.SEED_STABLE_99999);
173
+ const session = await (0, test_engine_factory_1.initSession)(engine);
174
+ let pub = session.publicState;
175
+ let priv = session.privateState;
176
+ const uniquePerSpin = [];
177
+ for (let i = 0; i < game_test_utils_1.SYMBOL_VARIETY_TEST_SPIN_COUNT; i++) {
178
+ const result = await (0, test_engine_factory_1.safeExecuteSpin)(engine, pub, priv);
179
+ if (!result)
180
+ break;
181
+ // LS outcome has result wrapper: outcome.result.screen
182
+ const screen = result.outcome?.result?.screen
183
+ ?? result.outcome?.screens?.[0]?.screen
184
+ ?? result.publicState?.screen
185
+ ?? result.outcome?.screen;
186
+ if (screen) {
187
+ const unique = new Set();
188
+ for (const reel of screen) {
189
+ for (const symbol of reel) {
190
+ unique.add(symbol);
191
+ }
192
+ }
193
+ uniquePerSpin.push(unique.size);
194
+ }
195
+ pub = result.publicState;
196
+ priv = result.privateState;
197
+ if (priv.nextSpinType && priv.nextSpinType !== 'BASE_GAME_SPIN')
198
+ break;
199
+ }
200
+ const avgUnique = uniquePerSpin.reduce((a, b) => a + b, 0) / uniquePerSpin.length;
201
+ console.log(`Symbol variety per spin (${uniquePerSpin.length} spins):`);
202
+ console.log(` Avg unique symbols: ${avgUnique.toFixed(1)}`);
203
+ console.log(` Min: ${Math.min(...uniquePerSpin)}`);
204
+ console.log(` Max: ${Math.max(...uniquePerSpin)}`);
205
+ // Each spin should have at least MIN_UNIQUE_SYMBOLS_PER_SPIN unique symbols
206
+ expect(Math.min(...uniquePerSpin)).toBeGreaterThanOrEqual(game_test_utils_1.MIN_UNIQUE_SYMBOLS_PER_SPIN);
207
+ expect(avgUnique).toBeGreaterThan(game_test_utils_1.MIN_AVG_UNIQUE_SYMBOLS_5x3);
208
+ }, game_test_utils_1.TEST_TIMEOUT_SHORT_MS);
209
+ });
210
+ //# sourceMappingURL=symbol-distribution.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-distribution.test.js","sourceRoot":"","sources":["../../src/__tests__/symbol-distribution.test.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;GAWG;AACH,uEAMuC;AACvC,iEAcqC;AAErC,uCAAuC;AACvC,MAAM,YAAY,GAA2B;IAC3C,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI;IAClC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI;IAChB,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI;IAChB,CAAC,EAAE,MAAM;IACT,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,WAAW;IAC9D,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK;IACrD,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK;IACrD,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK;IACrD,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc;CAC/E,CAAC;AAEF,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,IAAA,2CAAqB,GAAE,CAAC;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,4CAAsB,EAAC,8BAAY,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC/C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;QAChC,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gDAA8B,EAAE,CAAC,EAAE,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,6CAA6C;YAC7C,uDAAuD;YACvD,MAAM,MAAM,GAAI,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,MAAM;mBACjD,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM;mBACpC,MAAM,CAAC,WAAW,EAAE,MAAM;mBACzB,MAAM,CAAC,OAAe,EAAE,MAAM,CAAC;YAErC,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAC1B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;wBAC1B,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBAChE,CAAC;gBACH,CAAC;YACH,CAAC;YAED,SAAS,EAAE,CAAC;YACZ,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;YACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAE3B,oBAAoB;YACpB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB;gBAAE,MAAM;QACzE,CAAC;QAED,iEAAiE;QACjE,mFAAmF;QACnF,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,uBAAuB;QAC9E,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,gDAA8B,EAAE,EAAE,EAAE,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,SAAS,WAAW,SAAS,GAAG,6CAA2B,cAAc,CAAC,CAAC;QAC/G,MAAM,cAAc,GAAG,SAAS,GAAG,6CAA2B,CAAC,CAAC,mBAAmB;QACnF,MAAM,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,cAAc,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,IAAI,CAAC,CAAC;QACvD,CAAC;QAED,qEAAqE;QACrE,MAAM,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,EAAE,0CAAwB,CAAC,CAAC;IAE7B,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,IAAA,2CAAqB,GAAE,CAAC;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,4CAAsB,EAAC,mCAAiB,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC/C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;QAChC,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gDAA8B,EAAE,CAAC,EAAE,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,uDAAuD;YACvD,MAAM,MAAM,GAAI,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,MAAM;mBACjD,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM;mBACpC,MAAM,CAAC,WAAW,EAAE,MAAM;mBACzB,MAAM,CAAC,OAAe,EAAE,MAAM,CAAC;YAErC,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAC1B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;wBAC1B,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBAChE,CAAC;gBACH,CAAC;YACH,CAAC;YAED,SAAS,EAAE,CAAC;YACZ,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;YACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC3B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB;gBAAE,MAAM;QACzE,CAAC;QAED,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;QACnD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,gDAA8B,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACzG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,SAAS,GAAG,gDAA8B,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,4BAA4B,SAAS,UAAU,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,iBAAiB,SAAS,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,4BAA4B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAE9D,6DAA6D;QAC7D,8DAA8D;QAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,6CAA2B,GAAG,KAAK,CAAC,CAAC;QACjF,MAAM,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACvD,gEAAgE;QAChE,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC,EAAE,0CAAwB,CAAC,CAAC;IAE7B,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,IAAA,2CAAqB,GAAE,CAAC;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,4CAAsB,EAAC,mCAAiB,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;QAChC,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gDAA8B,EAAE,CAAC,EAAE,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,uDAAuD;YACvD,MAAM,MAAM,GAAI,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,MAAM;mBACjD,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM;mBACpC,MAAM,CAAC,WAAW,EAAE,MAAM;mBACzB,MAAM,CAAC,OAAe,EAAE,MAAM,CAAC;YAErC,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAC1B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;wBAC1B,cAAc,EAAE,CAAC;wBACjB,IAAI,MAAM,KAAK,EAAE;4BAAE,YAAY,EAAE,CAAC,CAAC,qBAAqB;oBAC1D,CAAC;gBACH,CAAC;YACH,CAAC;YAED,SAAS,EAAE,CAAC;YACZ,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;YACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC3B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB;gBAAE,MAAM;QACzE,CAAC;QAED,MAAM,WAAW,GAAG,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,cAAc,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,sBAAsB,SAAS,UAAU,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,oBAAoB,YAAY,MAAM,cAAc,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,WAAW,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAElD,wEAAwE;QACxE,MAAM,cAAc,GAAG,IAAI,CAAC;QAC5B,MAAM,CAAC,WAAW,CAAC,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;QAC3D,gEAAgE;QAChE,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,0CAAwB,CAAC,CAAC;IAC7D,CAAC,EAAE,0CAAwB,CAAC,CAAC;IAE7B,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,IAAA,2CAAqB,GAAE,CAAC;QACxB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,4CAAsB,EAAC,mCAAiB,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;QAChC,MAAM,aAAa,GAAa,EAAE,CAAC;QAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gDAA8B,EAAE,CAAC,EAAE,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,uDAAuD;YACvD,MAAM,MAAM,GAAI,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,MAAM;mBACjD,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM;mBACpC,MAAM,CAAC,WAAW,EAAE,MAAM;mBACzB,MAAM,CAAC,OAAe,EAAE,MAAM,CAAC;YAErC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAC1B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;wBAC1B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBACrB,CAAC;gBACH,CAAC;gBACD,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC;YAED,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;YACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC3B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB;gBAAE,MAAM;QACzE,CAAC;QAED,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC;QAClF,OAAO,CAAC,GAAG,CAAC,4BAA4B,aAAa,CAAC,MAAM,UAAU,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,yBAAyB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAEpD,4EAA4E;QAC5E,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,sBAAsB,CAAC,6CAA2B,CAAC,CAAC;QACvF,MAAM,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,4CAA0B,CAAC,CAAC;IAChE,CAAC,EAAE,uCAAqB,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=win-calculator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"win-calculator.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/win-calculator.test.ts"],"names":[],"mappings":""}