@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.
- package/README.md +212 -0
- package/dist/__tests__/bonus-sequence.test.js +337 -0
- package/dist/__tests__/bonus-sequence.test.js.map +1 -0
- package/dist/__tests__/cherry-frequency.test.js +128 -0
- package/dist/__tests__/cherry-frequency.test.js.map +1 -0
- package/dist/__tests__/counter-manager.test.js +316 -0
- package/dist/__tests__/counter-manager.test.js.map +1 -0
- package/dist/__tests__/cpp-parity.test.js +368 -0
- package/dist/__tests__/cpp-parity.test.js.map +1 -0
- package/dist/__tests__/fixtures/cpp-parity-vectors.json +438 -0
- package/dist/__tests__/happy-panda-engine.test.js +367 -0
- package/dist/__tests__/happy-panda-engine.test.js.map +1 -0
- package/dist/__tests__/jackpot-manager.test.js +313 -0
- package/dist/__tests__/jackpot-manager.test.js.map +1 -0
- package/dist/__tests__/jackpot-trigger-trace.test.js +146 -0
- package/dist/__tests__/jackpot-trigger-trace.test.js.map +1 -0
- package/dist/__tests__/rtp-1million.test.js +156 -0
- package/dist/__tests__/rtp-1million.test.js.map +1 -0
- package/dist/__tests__/rtp-analysis.test.js +138 -0
- package/dist/__tests__/rtp-analysis.test.js.map +1 -0
- package/dist/__tests__/rtp-diagnostic.test.js +126 -0
- package/dist/__tests__/rtp-diagnostic.test.js.map +1 -0
- package/dist/__tests__/rtp-simulation.test.js +409 -0
- package/dist/__tests__/rtp-simulation.test.js.map +1 -0
- package/dist/__tests__/special-wins.test.js +179 -0
- package/dist/__tests__/special-wins.test.js.map +1 -0
- package/dist/__tests__/spin-generator.test.js +250 -0
- package/dist/__tests__/spin-generator.test.js.map +1 -0
- package/dist/__tests__/spin-handler.test.js +210 -0
- package/dist/__tests__/spin-handler.test.js.map +1 -0
- package/dist/__tests__/symbol-distribution.test.js +119 -0
- package/dist/__tests__/symbol-distribution.test.js.map +1 -0
- package/dist/__tests__/weighted-random.test.js +165 -0
- package/dist/__tests__/weighted-random.test.js.map +1 -0
- package/dist/__tests__/win-evaluator.test.js +254 -0
- package/dist/__tests__/win-evaluator.test.js.map +1 -0
- package/dist/config/happy-panda.config.js +714 -0
- package/dist/config/happy-panda.config.js.map +1 -0
- package/dist/config/index.js +21 -0
- package/dist/config/index.js.map +1 -0
- package/dist/domain/index.js +21 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/types.js +28 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/engine/happy-panda-engine.js +197 -0
- package/dist/engine/happy-panda-engine.js.map +1 -0
- package/dist/engine/index.js +21 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/logic/handlers/index.js +21 -0
- package/dist/logic/handlers/index.js.map +1 -0
- package/dist/logic/handlers/spin-handler.js +256 -0
- package/dist/logic/handlers/spin-handler.js.map +1 -0
- package/dist/logic/index.js +22 -0
- package/dist/logic/index.js.map +1 -0
- package/dist/logic/services/counter-manager.js +265 -0
- package/dist/logic/services/counter-manager.js.map +1 -0
- package/dist/logic/services/index.js +23 -0
- package/dist/logic/services/index.js.map +1 -0
- package/dist/logic/services/jackpot-manager.js +142 -0
- package/dist/logic/services/jackpot-manager.js.map +1 -0
- package/dist/logic/services/win-evaluator.js +470 -0
- package/dist/logic/services/win-evaluator.js.map +1 -0
- package/dist/rng/index.js +22 -0
- package/dist/rng/index.js.map +1 -0
- package/dist/rng/spin-generator.js +341 -0
- package/dist/rng/spin-generator.js.map +1 -0
- package/dist/rng/weighted-random.js +58 -0
- package/dist/rng/weighted-random.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Weighted Random Tests
|
|
4
|
+
*
|
|
5
|
+
* Tests for weighted random selection utilities.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const weighted_random_1 = require("../rng/weighted-random");
|
|
9
|
+
// Mock RNG that returns specific value
|
|
10
|
+
function createMockRng(returnValue = 0) {
|
|
11
|
+
return {
|
|
12
|
+
async random(max) {
|
|
13
|
+
return returnValue % max;
|
|
14
|
+
},
|
|
15
|
+
async randomBatch(count, max) {
|
|
16
|
+
return Array(count).fill(returnValue % max);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// Mock RNG that returns sequence of values
|
|
21
|
+
function createSequenceRng(values) {
|
|
22
|
+
let index = 0;
|
|
23
|
+
return {
|
|
24
|
+
async random(max) {
|
|
25
|
+
const val = values[index % values.length];
|
|
26
|
+
index++;
|
|
27
|
+
return val % max;
|
|
28
|
+
},
|
|
29
|
+
async randomBatch(count, max) {
|
|
30
|
+
const results = [];
|
|
31
|
+
for (let i = 0; i < count; i++) {
|
|
32
|
+
const val = values[index % values.length];
|
|
33
|
+
index++;
|
|
34
|
+
results.push(val % max);
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
describe('Weighted Random', () => {
|
|
41
|
+
describe('selectWeightedIndex', () => {
|
|
42
|
+
it('should select first index when roll is 0', async () => {
|
|
43
|
+
const rng = createMockRng(0);
|
|
44
|
+
const weights = [10, 20, 30];
|
|
45
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
46
|
+
expect(result).toBe(0);
|
|
47
|
+
});
|
|
48
|
+
it('should select second index when roll falls in second range', async () => {
|
|
49
|
+
const rng = createMockRng(15); // Falls in second weight range (10-29)
|
|
50
|
+
const weights = [10, 20, 30];
|
|
51
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
52
|
+
expect(result).toBe(1);
|
|
53
|
+
});
|
|
54
|
+
it('should select last index when roll falls in last range', async () => {
|
|
55
|
+
const rng = createMockRng(50); // Falls in last weight range (30-59)
|
|
56
|
+
const weights = [10, 20, 30];
|
|
57
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
58
|
+
expect(result).toBe(2);
|
|
59
|
+
});
|
|
60
|
+
it('should throw error when all weights are zero', async () => {
|
|
61
|
+
const rng = createMockRng(0);
|
|
62
|
+
const weights = [0, 0, 0];
|
|
63
|
+
await expect((0, weighted_random_1.selectWeightedIndex)(weights, rng)).rejects.toThrow('All weights are zero');
|
|
64
|
+
});
|
|
65
|
+
it('should handle single weight', async () => {
|
|
66
|
+
const rng = createMockRng(0);
|
|
67
|
+
const weights = [100];
|
|
68
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
69
|
+
expect(result).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
it('should handle weights with some zeros', async () => {
|
|
72
|
+
const rng = createMockRng(0);
|
|
73
|
+
const weights = [0, 10, 0];
|
|
74
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
75
|
+
expect(result).toBe(1);
|
|
76
|
+
});
|
|
77
|
+
it('should select based on cumulative weights', async () => {
|
|
78
|
+
// Total weight = 100, roll 99 should hit last bucket
|
|
79
|
+
const rng = createMockRng(99);
|
|
80
|
+
const weights = [25, 25, 25, 25];
|
|
81
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
82
|
+
expect(result).toBe(3);
|
|
83
|
+
});
|
|
84
|
+
it('should handle edge case at boundary', async () => {
|
|
85
|
+
// Roll 9 should still be in first bucket (0-9)
|
|
86
|
+
const rng = createMockRng(9);
|
|
87
|
+
const weights = [10, 10, 10];
|
|
88
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
89
|
+
expect(result).toBe(0);
|
|
90
|
+
});
|
|
91
|
+
it('should handle edge case just past boundary', async () => {
|
|
92
|
+
// Roll 10 should be in second bucket (10-19)
|
|
93
|
+
const rng = createMockRng(10);
|
|
94
|
+
const weights = [10, 10, 10];
|
|
95
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
96
|
+
expect(result).toBe(1);
|
|
97
|
+
});
|
|
98
|
+
it('should return last index as fallback', async () => {
|
|
99
|
+
// This tests the fallback return at line 35
|
|
100
|
+
// By using a roll value that equals totalWeight-1
|
|
101
|
+
const rng = createMockRng(29); // totalWeight = 30, roll = 29
|
|
102
|
+
const weights = [10, 10, 10];
|
|
103
|
+
const result = await (0, weighted_random_1.selectWeightedIndex)(weights, rng);
|
|
104
|
+
expect(result).toBe(2);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('weightedBoolean', () => {
|
|
108
|
+
it('should return true when first bucket selected', async () => {
|
|
109
|
+
const rng = createMockRng(0);
|
|
110
|
+
const result = await (0, weighted_random_1.weightedBoolean)(10, 90, rng);
|
|
111
|
+
expect(result).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
it('should return false when second bucket selected', async () => {
|
|
114
|
+
const rng = createMockRng(50); // Falls in "no" bucket
|
|
115
|
+
const result = await (0, weighted_random_1.weightedBoolean)(10, 90, rng);
|
|
116
|
+
expect(result).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
it('should handle 50/50 odds', async () => {
|
|
119
|
+
const rng = createMockRng(0);
|
|
120
|
+
const result = await (0, weighted_random_1.weightedBoolean)(50, 50, rng);
|
|
121
|
+
expect(result).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
it('should handle 100/0 odds (always true)', async () => {
|
|
124
|
+
const rng = createMockRng(99);
|
|
125
|
+
const result = await (0, weighted_random_1.weightedBoolean)(100, 0, rng);
|
|
126
|
+
expect(result).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
it('should handle 0/100 odds (always false)', async () => {
|
|
129
|
+
const rng = createMockRng(0);
|
|
130
|
+
const result = await (0, weighted_random_1.weightedBoolean)(0, 100, rng);
|
|
131
|
+
expect(result).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('selectMultipleWeighted', () => {
|
|
135
|
+
it('should select multiple indices', async () => {
|
|
136
|
+
const rng = createSequenceRng([0, 10, 20]);
|
|
137
|
+
const weights = [10, 10, 10];
|
|
138
|
+
const results = await (0, weighted_random_1.selectMultipleWeighted)(weights, 3, rng);
|
|
139
|
+
expect(results).toHaveLength(3);
|
|
140
|
+
expect(results[0]).toBe(0);
|
|
141
|
+
expect(results[1]).toBe(1);
|
|
142
|
+
expect(results[2]).toBe(2);
|
|
143
|
+
});
|
|
144
|
+
it('should return empty array for count 0', async () => {
|
|
145
|
+
const rng = createMockRng(0);
|
|
146
|
+
const weights = [10, 20, 30];
|
|
147
|
+
const results = await (0, weighted_random_1.selectMultipleWeighted)(weights, 0, rng);
|
|
148
|
+
expect(results).toHaveLength(0);
|
|
149
|
+
});
|
|
150
|
+
it('should allow same index to be selected multiple times', async () => {
|
|
151
|
+
const rng = createMockRng(0); // Always returns 0
|
|
152
|
+
const weights = [10, 20, 30];
|
|
153
|
+
const results = await (0, weighted_random_1.selectMultipleWeighted)(weights, 5, rng);
|
|
154
|
+
expect(results).toHaveLength(5);
|
|
155
|
+
expect(results.every(r => r === 0)).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
it('should handle single selection', async () => {
|
|
158
|
+
const rng = createMockRng(0);
|
|
159
|
+
const weights = [10, 20, 30];
|
|
160
|
+
const results = await (0, weighted_random_1.selectMultipleWeighted)(weights, 1, rng);
|
|
161
|
+
expect(results).toHaveLength(1);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=weighted-random.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weighted-random.test.js","sourceRoot":"","sources":["../../src/__tests__/weighted-random.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Win Evaluator Tests
|
|
4
|
+
*
|
|
5
|
+
* Tests for the win evaluation logic against the C++ math model.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const win_evaluator_1 = require("../logic/services/win-evaluator");
|
|
9
|
+
const happy_panda_config_1 = require("../config/happy-panda.config");
|
|
10
|
+
const types_1 = require("../domain/types");
|
|
11
|
+
// Helper to create a grid from a 2D array
|
|
12
|
+
function createGrid(symbols) {
|
|
13
|
+
return symbols;
|
|
14
|
+
}
|
|
15
|
+
// Helper to create a grid filled with one symbol
|
|
16
|
+
function filledGrid(symbol) {
|
|
17
|
+
return [
|
|
18
|
+
[symbol, symbol, symbol],
|
|
19
|
+
[symbol, symbol, symbol],
|
|
20
|
+
[symbol, symbol, symbol],
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
describe('Win Evaluator', () => {
|
|
24
|
+
describe('Wall Wins (3x3)', () => {
|
|
25
|
+
it('should detect BAR3 wall win', () => {
|
|
26
|
+
const grid = filledGrid(happy_panda_config_1.Symbol.BAR3);
|
|
27
|
+
const result = (0, win_evaluator_1.evaluateWallWin)(grid, 8);
|
|
28
|
+
expect(result).not.toBeNull();
|
|
29
|
+
expect(result.payout).toBe(44 * 8); // 44x bet_game (tuned for 96.38% RTP)
|
|
30
|
+
});
|
|
31
|
+
it('should detect Cherry wall win (mixed CH/CH_S)', () => {
|
|
32
|
+
const grid = [
|
|
33
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.SUPER_CHERRY, happy_panda_config_1.Symbol.CHERRY],
|
|
34
|
+
[happy_panda_config_1.Symbol.SUPER_CHERRY, happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.SUPER_CHERRY],
|
|
35
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.SUPER_CHERRY],
|
|
36
|
+
];
|
|
37
|
+
const result = (0, win_evaluator_1.evaluateWallWin)(grid, 8);
|
|
38
|
+
expect(result).not.toBeNull();
|
|
39
|
+
expect(result.payout).toBe(35 * 8); // Cherry wall = 35x (tuned for 96.38% RTP)
|
|
40
|
+
});
|
|
41
|
+
it('should detect Any Bar wall (mixed BAR3/BAR2/BAR1)', () => {
|
|
42
|
+
const grid = [
|
|
43
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.BAR1],
|
|
44
|
+
[happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BAR2],
|
|
45
|
+
[happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.BAR3],
|
|
46
|
+
];
|
|
47
|
+
const result = (0, win_evaluator_1.evaluateWallWin)(grid, 8);
|
|
48
|
+
expect(result).not.toBeNull();
|
|
49
|
+
expect(result.payout).toBe(5 * 8); // Any Bar = 5x (tuned for 96.38% RTP)
|
|
50
|
+
});
|
|
51
|
+
it('should detect All Fruits wall', () => {
|
|
52
|
+
const grid = [
|
|
53
|
+
[happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE],
|
|
54
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.SUPER_CHERRY, happy_panda_config_1.Symbol.MELON],
|
|
55
|
+
[happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE, happy_panda_config_1.Symbol.CHERRY],
|
|
56
|
+
];
|
|
57
|
+
const result = (0, win_evaluator_1.evaluateWallWin)(grid, 8);
|
|
58
|
+
expect(result).not.toBeNull();
|
|
59
|
+
expect(result.payout).toBe(2 * 8); // All Fruits = 2x (tuned for 96.38% RTP)
|
|
60
|
+
});
|
|
61
|
+
it('should return null for non-wall', () => {
|
|
62
|
+
const grid = [
|
|
63
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.MELON],
|
|
64
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE],
|
|
65
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.SUPER_SEVEN],
|
|
66
|
+
];
|
|
67
|
+
const result = (0, win_evaluator_1.evaluateWallWin)(grid, 8);
|
|
68
|
+
expect(result).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('Scatter Wins (Seven)', () => {
|
|
72
|
+
it('should detect 2x Seven scatter', () => {
|
|
73
|
+
const grid = [
|
|
74
|
+
[happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
75
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.ORANGE],
|
|
76
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.BAR2],
|
|
77
|
+
];
|
|
78
|
+
const results = (0, win_evaluator_1.evaluateScatterWins)(grid, 8);
|
|
79
|
+
expect(results.length).toBe(1); // Only mix scatter (2 regular sevens)
|
|
80
|
+
expect(results[0].count).toBe(2);
|
|
81
|
+
expect(results[0].payout).toBe(1 * 8); // 2x = 1x bet_game
|
|
82
|
+
});
|
|
83
|
+
it('should detect 3x Super Seven scatter (doubled)', () => {
|
|
84
|
+
const grid = [
|
|
85
|
+
[happy_panda_config_1.Symbol.SUPER_SEVEN, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
86
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.SUPER_SEVEN, happy_panda_config_1.Symbol.ORANGE],
|
|
87
|
+
[happy_panda_config_1.Symbol.SUPER_SEVEN, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.BAR2],
|
|
88
|
+
];
|
|
89
|
+
const results = (0, win_evaluator_1.evaluateScatterWins)(grid, 8);
|
|
90
|
+
expect(results.length).toBe(1); // Only Super Seven scatter (no regular sevens)
|
|
91
|
+
expect(results[0].count).toBe(3);
|
|
92
|
+
expect(results[0].isSuperSevenOnly).toBe(true);
|
|
93
|
+
expect(results[0].payout).toBe(2 * 8 * 2); // 3x = 2x, doubled for Super Seven only
|
|
94
|
+
});
|
|
95
|
+
it('should detect mixed Seven/Super Seven (TWO wins per C++)', () => {
|
|
96
|
+
const grid = [
|
|
97
|
+
[happy_panda_config_1.Symbol.SUPER_SEVEN, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
98
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.ORANGE],
|
|
99
|
+
[happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.BAR2],
|
|
100
|
+
];
|
|
101
|
+
const results = (0, win_evaluator_1.evaluateScatterWins)(grid, 8);
|
|
102
|
+
// C++ awards TWO scatter wins when both Super Seven AND regular Seven present
|
|
103
|
+
expect(results.length).toBe(1); // 1 Super Seven not enough for separate win
|
|
104
|
+
expect(results[0].count).toBe(3); // Total count
|
|
105
|
+
expect(results[0].isSuperSevenOnly).toBe(false);
|
|
106
|
+
// With exactly 1 Super Seven in mix, add bet_game bonus
|
|
107
|
+
expect(results[0].payout).toBe(2 * 8 + 8); // 3x = 2x + 1x bonus
|
|
108
|
+
});
|
|
109
|
+
it('should return empty array for 1 Seven', () => {
|
|
110
|
+
const grid = [
|
|
111
|
+
[happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
112
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE],
|
|
113
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.BAR1],
|
|
114
|
+
];
|
|
115
|
+
const results = (0, win_evaluator_1.evaluateScatterWins)(grid, 8);
|
|
116
|
+
expect(results.length).toBe(0);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('Line Wins', () => {
|
|
120
|
+
it('should detect 3x BAR3 on line 0 (top row)', () => {
|
|
121
|
+
// Line 0: positions (0,0), (1,0), (2,0) - top row
|
|
122
|
+
// Grid[reel][row] - need BAR3 at top row of each reel
|
|
123
|
+
const grid = [
|
|
124
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY], // reel 0
|
|
125
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE], // reel 1
|
|
126
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.BAR2], // reel 2
|
|
127
|
+
];
|
|
128
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
129
|
+
// This grid has BAR3 on top row (line 0) AND left column (line 3)
|
|
130
|
+
// So we expect 2 wins in 8-line mode
|
|
131
|
+
const bar3Wins = wins.filter(w => w.symbol === happy_panda_config_1.Symbol.BAR3);
|
|
132
|
+
expect(bar3Wins.length).toBeGreaterThanOrEqual(1);
|
|
133
|
+
const topRowWin = bar3Wins.find(w => w.lineIndex === 0);
|
|
134
|
+
expect(topRowWin).toBeDefined();
|
|
135
|
+
expect(topRowWin.payout).toBe(80); // 80x bet_stake
|
|
136
|
+
});
|
|
137
|
+
it('should detect 1x Cherry on line (pays x2)', () => {
|
|
138
|
+
const grid = [
|
|
139
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
140
|
+
[happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE, happy_panda_config_1.Symbol.BELL],
|
|
141
|
+
[happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.SEVEN],
|
|
142
|
+
];
|
|
143
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
144
|
+
const cherryWin = wins.find(w => w.symbol === happy_panda_config_1.Symbol.CHERRY);
|
|
145
|
+
expect(cherryWin).toBeDefined();
|
|
146
|
+
expect(cherryWin.matchLength).toBe(1);
|
|
147
|
+
expect(cherryWin.payout).toBe(2); // 1x cherry = 2x
|
|
148
|
+
});
|
|
149
|
+
it('should detect 2x Cherry on line (pays x5)', () => {
|
|
150
|
+
const grid = [
|
|
151
|
+
[happy_panda_config_1.Symbol.CHERRY, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON],
|
|
152
|
+
[happy_panda_config_1.Symbol.SUPER_CHERRY, happy_panda_config_1.Symbol.ORANGE, happy_panda_config_1.Symbol.BELL],
|
|
153
|
+
[happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.SEVEN],
|
|
154
|
+
];
|
|
155
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
156
|
+
const cherryWin = wins.find(w => w.symbol === happy_panda_config_1.Symbol.CHERRY && w.matchLength === 2);
|
|
157
|
+
expect(cherryWin).toBeDefined();
|
|
158
|
+
expect(cherryWin.payout).toBe(5); // 2x cherry = 5x
|
|
159
|
+
});
|
|
160
|
+
it('should detect bar mix on line (BAR3+BAR2+BAR1)', () => {
|
|
161
|
+
// Bar mix on top row (line 0)
|
|
162
|
+
const grid = [
|
|
163
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY], // reel 0
|
|
164
|
+
[happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE], // reel 1
|
|
165
|
+
[happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.SEVEN], // reel 2
|
|
166
|
+
];
|
|
167
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
168
|
+
// Should have bar mix win on line 0 (top row) and potentially other wins
|
|
169
|
+
const barMixWin = wins.find(w => w.lineIndex === 0);
|
|
170
|
+
expect(barMixWin).toBeDefined();
|
|
171
|
+
expect(barMixWin.payout).toBe(10); // Any Bar = 10x
|
|
172
|
+
});
|
|
173
|
+
it('should detect bar mix including SUPER_BAR', () => {
|
|
174
|
+
// Bar mix with Super Bar on top row (line 0)
|
|
175
|
+
const grid = [
|
|
176
|
+
[happy_panda_config_1.Symbol.SUPER_BAR, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY], // reel 0
|
|
177
|
+
[happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE], // reel 1
|
|
178
|
+
[happy_panda_config_1.Symbol.BAR1, happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.SEVEN], // reel 2
|
|
179
|
+
];
|
|
180
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
181
|
+
// Should have bar mix win on line 0 (top row)
|
|
182
|
+
const barMixWin = wins.find(w => w.lineIndex === 0);
|
|
183
|
+
expect(barMixWin).toBeDefined();
|
|
184
|
+
expect(barMixWin.payout).toBe(10); // Any Bar mix with Super Bar
|
|
185
|
+
});
|
|
186
|
+
it('should evaluate 8 lines in SINGLE mode', () => {
|
|
187
|
+
// 3x Bell on top row (line 0) - this wins on line 0 only (8 lines)
|
|
188
|
+
// Also wins on line 3 (left column) due to grid structure
|
|
189
|
+
const grid = [
|
|
190
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY], // reel 0
|
|
191
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE], // reel 1
|
|
192
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.SEVEN], // reel 2
|
|
193
|
+
];
|
|
194
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.SINGLE, 1);
|
|
195
|
+
// Verify at least line 0 wins with Bell
|
|
196
|
+
const line0Win = wins.find(w => w.lineIndex === 0);
|
|
197
|
+
expect(line0Win).toBeDefined();
|
|
198
|
+
expect(line0Win.symbol).toBe(happy_panda_config_1.Symbol.BELL);
|
|
199
|
+
// In SINGLE mode, only 8 lines are evaluated (0-7)
|
|
200
|
+
expect(wins.every(w => w.lineIndex < 8)).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
it('should evaluate 16 lines in BOTH mode', () => {
|
|
203
|
+
// 3x Bell on top row - wins on both line 0 and line 8 (reversed)
|
|
204
|
+
const grid = [
|
|
205
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY], // reel 0
|
|
206
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE], // reel 1
|
|
207
|
+
[happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.BAR2, happy_panda_config_1.Symbol.SEVEN], // reel 2
|
|
208
|
+
];
|
|
209
|
+
const wins = (0, win_evaluator_1.evaluateLineWins)(grid, types_1.GameDirection.BOTH, 1);
|
|
210
|
+
// In BOTH mode, 16 lines are evaluated (0-15)
|
|
211
|
+
// Line 0 (top row forward) and line 8 (top row reverse) should both win
|
|
212
|
+
const line0Win = wins.find(w => w.lineIndex === 0);
|
|
213
|
+
const line8Win = wins.find(w => w.lineIndex === 8);
|
|
214
|
+
expect(line0Win).toBeDefined();
|
|
215
|
+
expect(line8Win).toBeDefined();
|
|
216
|
+
// Should have more wins in 16-line mode than 8-line mode
|
|
217
|
+
expect(wins.some(w => w.lineIndex >= 8)).toBe(true);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
describe('Win Priority (Wall > Scatter > Lines)', () => {
|
|
221
|
+
it('should suppress line wins when wall win present', () => {
|
|
222
|
+
// Full BAR3 wall - no line wins should be counted
|
|
223
|
+
const grid = filledGrid(happy_panda_config_1.Symbol.BAR3);
|
|
224
|
+
const result = (0, win_evaluator_1.evaluateSpin)(grid, types_1.GameDirection.SINGLE, 1, 8, happy_panda_config_1.SpinType.PAID_SPIN);
|
|
225
|
+
expect(result.wallWin).not.toBeNull();
|
|
226
|
+
expect(result.lineWins.length).toBe(0); // Lines suppressed
|
|
227
|
+
expect(result.totalPayout).toBe(44 * 8); // Only wall payout (tuned for 96.38% RTP)
|
|
228
|
+
});
|
|
229
|
+
it('should suppress line wins when scatter win present', () => {
|
|
230
|
+
// 3x Seven scatter with potential line wins
|
|
231
|
+
const grid = [
|
|
232
|
+
[happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.SEVEN, happy_panda_config_1.Symbol.SEVEN], // Would be line win too
|
|
233
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BAR3], // Would be line win
|
|
234
|
+
[happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE],
|
|
235
|
+
];
|
|
236
|
+
const result = (0, win_evaluator_1.evaluateSpin)(grid, types_1.GameDirection.SINGLE, 1, 8, happy_panda_config_1.SpinType.PAID_SPIN);
|
|
237
|
+
expect(result.scatterWins.length).toBeGreaterThan(0);
|
|
238
|
+
expect(result.scatterWins[0].count).toBe(3);
|
|
239
|
+
expect(result.lineWins.length).toBe(0); // Lines suppressed
|
|
240
|
+
});
|
|
241
|
+
it('should evaluate line wins when no wall or scatter', () => {
|
|
242
|
+
const grid = [
|
|
243
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.MELON, happy_panda_config_1.Symbol.CHERRY],
|
|
244
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.PRUNE, happy_panda_config_1.Symbol.ORANGE],
|
|
245
|
+
[happy_panda_config_1.Symbol.BAR3, happy_panda_config_1.Symbol.BELL, happy_panda_config_1.Symbol.BAR2],
|
|
246
|
+
];
|
|
247
|
+
const result = (0, win_evaluator_1.evaluateSpin)(grid, types_1.GameDirection.SINGLE, 1, 8, happy_panda_config_1.SpinType.PAID_SPIN);
|
|
248
|
+
expect(result.wallWin).toBeNull();
|
|
249
|
+
expect(result.scatterWins.length).toBe(0);
|
|
250
|
+
expect(result.lineWins.length).toBeGreaterThan(0);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
//# sourceMappingURL=win-evaluator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"win-evaluator.test.js","sourceRoot":"","sources":["../../src/__tests__/win-evaluator.test.ts"],"names":[],"mappings":"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"}
|