@omnitronix/happy-panda-game-engine 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,676 +1,722 @@
1
- # Happy Panda Game Engine
2
-
3
- ![Version](https://img.shields.io/badge/version-0.0.2-blue.svg)
4
- ![License](https://img.shields.io/badge/license-UNLICENSED-red.svg)
5
- ![Package](https://img.shields.io/badge/package-%40omnitronix%2Fhappy--panda--game--engine-green.svg)
6
-
7
- Pure business logic library for the Happy Panda (Cherry Master) slot game. A framework-agnostic, TypeScript-based game engine that handles all core game mechanics, bonus systems, and jackpot logic. Achieves C++ parity with the original `CherryMaster_A_2.cpp` implementation.
8
-
9
- ## What is Happy Panda Game Engine?
10
-
11
- The Happy Panda Game Engine is an isolated, framework-agnostic library containing pure business logic for the Happy Panda slot game. It implements a command-based architecture that separates game logic from presentation and infrastructure concerns.
12
-
13
- ### Core Characteristics
14
-
15
- - **Pure Business Logic**: Contains only game rules, calculations, and state transitions
16
- - **Framework Agnostic**: No dependencies on specific UI frameworks or web servers
17
- - **Command-Based Architecture**: All interactions through well-defined commands
18
- - **State Separation**: Distinguishes between public state (visible to players) and private state (server-side only)
19
- - **RNG Integration**: Supports pluggable RNG providers for testing and production
20
- - **Audit Trail**: Complete RNG outcome tracking for compliance and debugging
21
- - **C++ Parity**: Verified against original C++ implementation with 100M spin validation
22
-
23
- ### Game Specifications
24
-
25
- - **RTP**: 96.05% (verified at 95.91% over 100M spins, within tolerance)
26
- - **Game Type**: Classic 3x3 Slot
27
- - **Version**: 1.0.0
28
- - **Layout**: 3 reels x 3 rows
29
- - **Win Evaluation**: 8/16 bidirectional paylines + wall wins + scatter wins
30
- - **Modes**: 8-line (SINGLE) and 16-line (BOTH)
31
-
32
- ## RTP Validation Results
33
-
34
- ### 100 Million Spin Verification
35
-
36
- ```
37
- ================================================================
38
- HAPPY PANDA RTP VERIFICATION - 100 MILLION SPINS
39
- ================================================================
40
-
41
- Configuration:
42
- - Game Direction: SINGLE (8 lines)
43
- - Bet per spin: 8
44
- - Seeds: 10 x 10M = 100M total paid spins
45
- - C++ Target RTP: 96.05%
46
-
47
- RTP Breakdown by Spin Type:
48
- ----------------------------------------------------------------
49
- PAID_SPIN : 62.54% | C++: 63.51% | Diff: -0.97%
50
- BONUS_JACKPOT : 16.24% | C++: 13.56% | Diff: +2.68%
51
- BONUS_CHERRY : 3.96% | C++: 3.67% | Diff: +0.29%
52
- BONUS_BELL : 5.06% | C++: 5.83% | Diff: -0.77%
53
- BONUS_BAR1 : 5.47% | C++: 6.31% | Diff: -0.84%
54
- RESPIN_CHERRY : 2.64% | C++: 3.18% | Diff: -0.54%
55
- ----------------------------------------------------------------
56
- TOTAL : 95.91% | C++: 96.05%
57
-
58
- Statistics:
59
- - Standard Deviation: 0.32%
60
- - Range: 95.54% - 96.40%
61
-
62
- STATUS: PASS - RTP within 0.15% tolerance
63
- ================================================================
64
- ```
65
-
66
- | Metric | TypeScript | C++ Target | Difference | Status |
67
- |--------|------------|------------|------------|--------|
68
- | **RTP (100M spins)** | 95.91% | 96.05% | -0.14% | **PASS** |
69
- | PAID_SPIN | 62.54% | 63.51% | -0.97% | Match |
70
- | BONUS_JACKPOT | 16.24% | 13.56% | +2.68% | Match |
71
- | BONUS_CHERRY | 3.96% | 3.67% | +0.29% | Match |
72
- | BONUS_BELL | 5.06% | 5.83% | -0.77% | Match |
73
- | BONUS_BAR1 | 5.47% | 6.31% | -0.84% | Match |
74
- | RESPIN_CHERRY | 2.64% | 3.18% | -0.54% | Match |
75
-
76
- **No configuration values from XLSX were modified** - only calculation logic was adjusted to match C++ behavior.
77
-
78
- ## Features
79
-
80
- - **Command-Based Architecture**: 3 different command types for all game operations
81
- - **State Management**: Public/private state separation with type safety
82
- - **RNG Integration**: Pluggable RNG providers with audit trail support
83
- - **Bidirectional Paylines**: 8 or 16 paylines with left-to-right and right-to-left evaluation
84
- - **Wall Wins**: Full 3x3 matrix wins with multiple types (pure, mixed, fruits, colors)
85
- - **Scatter Wins**: Seven symbols pay anywhere on screen
86
- - **Bonus System**: 5 distinct bonus types with counter-based triggers
87
- - **Jackpot System**: Progressive and pool jackpots
88
- - **TypeScript Support**: Complete type definitions for all interfaces
89
- - **Comprehensive Testing**: Full test suite with Jest and 100M spin RTP validation
90
-
91
- ## Architecture Overview
92
-
93
- The game engine follows a modular architecture with clear separation of concerns:
94
-
95
- ### Core Components
96
-
97
- - **Game Engine** (`HappyPandaEngine`): Main entry point and command processor
98
- - **V1 Wrapper** (`HappyPandaV1GameEngine`): Service integration wrapper with GameEngine interface
99
- - **Spin Generator**: Grid generation with weighted random selection
100
- - **Win Evaluator**: Line, wall, scatter, and special win detection
101
- - **Counter Manager**: Bonus counter management and trigger logic
102
- - **Jackpot Manager**: Progressive and pool jackpot handling
103
-
104
- ### Directory Structure
105
-
106
- ```
107
- src/
108
- ├── happy-panda-v1.game-engine.ts # V1 service wrapper
109
- ├── engine/
110
- │ └── happy-panda-engine.ts # Main engine class
111
- ├── config/
112
- │ └── happy-panda.config.ts # All game configuration (XLSX values)
113
- ├── rng/
114
- │ ├── spin-generator.ts # Grid generation with C++ parity
115
- │ └── weighted-random.ts # Weighted random selection
116
- ├── logic/
117
- │ ├── handlers/
118
- │ │ └── spin-handler.ts # Spin orchestration
119
- │ └── services/
120
- │ ├── win-evaluator.ts # Win detection (line/wall/scatter)
121
- │ ├── counter-manager.ts # Bonus counter management
122
- │ └── jackpot-manager.ts # Jackpot handling
123
- ├── domain/
124
- │ └── types.ts # Type definitions
125
- └── __tests__/
126
- ├── rtp-simulation.test.ts # RTP validation
127
- ├── rtp-diagnostic.test.ts # RTP breakdown by spin type
128
- ├── cpp-parity.test.ts # C++ parity tests
129
- └── win-evaluator.test.ts # Win evaluation tests
130
-
131
- docs/
132
- ├── RTP-MATCHING.md # RTP implementation details
133
- └── TEST-PROTOCOL-RTP-100M.md # 100M spin test protocol
134
- ```
135
-
136
- ## Installation
137
-
138
- ```bash
139
- npm install @omnitronix/happy-panda-game-engine
140
- ```
141
-
142
- > **Note**: This is a private package for Omnitronix internal use only (UNLICENSED).
143
-
144
- ## Quick Start
145
-
146
- ```typescript
147
- import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
148
-
149
- // Initialize game engine
150
- const gameEngine = new HappyPandaV1GameEngine();
151
-
152
- // Get engine info
153
- const info = gameEngine.getGameEngineInfo();
154
- // { gameCode: 'happy-panda', version: '1.0.0', rtp: 96.05, gameType: 'slot', gameName: 'Happy Panda', provider: 'Omnitronix' }
155
-
156
- // Initialize session
157
- const initCommand = {
158
- id: 'cmd-init-123',
159
- type: 'INIT_SESSION_STATE',
160
- payload: {
161
- gameDirection: 0, // 0 = SINGLE (8 lines), 1 = BOTH (16 lines)
162
- betStake: 1
163
- }
164
- };
165
-
166
- const initResult = await gameEngine.processCommand(null, null, initCommand);
167
- // Returns: { success: true, publicState, privateState, outcome, rngOutcome }
168
-
169
- // Process spin
170
- const spinCommand = {
171
- id: 'cmd-spin-456',
172
- type: 'SPIN',
173
- payload: {}
174
- };
175
-
176
- const spinResult = await gameEngine.processCommand(
177
- initResult.publicState,
178
- initResult.privateState,
179
- spinCommand
180
- );
181
- ```
182
-
183
- ## API Reference
184
-
185
- ### Main Class: `HappyPandaV1GameEngine`
186
-
187
- Implements the standard `GameEngine` interface for integration with game-engine-service.
188
-
189
- #### Constructor
190
-
191
- ```typescript
192
- new HappyPandaV1GameEngine()
193
- ```
194
-
195
- - Initializes game engine with tracked RNG provider
196
- - Ready to process commands immediately
197
-
198
- #### Methods
199
-
200
- **`getGameEngineInfo(): GameEngineInfo`**
201
- Returns game metadata including code, version, RTP, and provider.
202
-
203
- ```typescript
204
- {
205
- gameCode: 'happy-panda',
206
- version: '1.0.0',
207
- rtp: 96.05,
208
- gameType: 'slot',
209
- gameName: 'Happy Panda',
210
- provider: 'Omnitronix'
211
- }
212
- ```
213
-
214
- **`processCommand(publicState, privateState, command): Promise<CommandProcessingResult>`**
215
- Main command processor that handles all game operations.
216
-
217
- ### Commands
218
-
219
- The game engine supports 3 different command types:
220
-
221
- #### 1. INIT_SESSION_STATE
222
-
223
- **Purpose**: Initialize game session state
224
-
225
- **Payload**:
226
- ```typescript
227
- {
228
- gameDirection?: number; // 0 = SINGLE (8 lines), 1 = BOTH (16 lines). Default: 0
229
- betStake?: number; // Bet multiplier. Default: 1
230
- }
231
- ```
232
-
233
- **Returns**: Initial public and private state with default values
234
-
235
- #### 2. SPIN
236
-
237
- **Purpose**: Execute a spin
238
-
239
- **Payload**: None required (uses current state)
240
-
241
- **Returns**: Spin result with grid, wins, and state updates
242
-
243
- **Result Structure**:
244
- ```typescript
245
- {
246
- success: true,
247
- publicState: PublicState,
248
- privateState: PrivateState,
249
- outcome: {
250
- sessionId: string,
251
- grid: Symbol[][], // 3x3 grid
252
- wins: SpinWinResult, // All wins
253
- state: PublicState,
254
- jackpotWon: number, // Jackpot payout (if any)
255
- poolJackpotWon: number, // Pool jackpot payout (if any)
256
- bonusTriggered: SpinType | null,
257
- isBonusComplete: boolean
258
- },
259
- rngOutcome: RngOutcome // Audit trail
260
- }
261
- ```
262
-
263
- #### 3. GET_SYMBOLS
264
-
265
- **Purpose**: Retrieve symbol definitions
266
-
267
- **Payload**: None
268
-
269
- **Returns**: Array of symbol definitions with names and values
270
-
271
- ### State Types
272
-
273
- #### PublicState (visible to player)
274
-
275
- ```typescript
276
- {
277
- gameDirection: GameDirection; // 0 = SINGLE, 1 = BOTH
278
- betStake: number; // Bet multiplier
279
- betGame: number; // Total bet (8 or 16 x betStake)
280
- currentSpinType: SpinType; // Current spin type
281
- spinsRemaining: number; // Remaining bonus spins
282
- grid: Symbol[][]; // Current 3x3 grid
283
- bonusJackpotValue: number; // Progressive jackpot
284
- poolJackpotValue: number; // Pool jackpot
285
- hasPendingBonus: boolean; // Indicates pending bonus
286
- }
287
- ```
288
-
289
- #### PrivateState (server-side only)
290
-
291
- ```typescript
292
- {
293
- counters: BonusCounters; // Bonus trigger counters
294
- pendingBonuses: PendingBonuses; // Queued bonuses
295
- nextSpinType: SpinType; // Next spin type
296
- accumulatedBonusWins: number; // Bonus sequence wins
297
- centerCherrySymbol: Symbol | null; // For respin feature
298
- }
299
- ```
300
-
301
- #### CommandProcessingResult
302
-
303
- ```typescript
304
- {
305
- success: boolean;
306
- publicState: PublicState;
307
- privateState: PrivateState;
308
- outcome?: SpinResponse;
309
- message?: string;
310
- rngOutcome?: RngOutcome; // RNG audit trail
311
- }
312
- ```
313
-
314
- ## Game Mechanics
315
-
316
- ### Symbol Set
317
-
318
- | ID | Symbol | Description |
319
- |----|--------|-------------|
320
- | 0 | SEV_S | Super Seven (scatter, doubled payout when solo) |
321
- | 1 | SEV | Seven (scatter) |
322
- | 2 | BA3 | Bar 3 |
323
- | 3 | BA2 | Bar 2 |
324
- | 4 | BA1 | Bar 1 |
325
- | 5 | ME | Melon |
326
- | 6 | BE | Bell |
327
- | 7 | PR | Prune |
328
- | 8 | OR | Orange |
329
- | 9 | CH | Cherry |
330
- | 10 | CH_S | Cherry Special |
331
- | 11 | BA_S | Super Bar |
332
-
333
- ### Win Types
334
-
335
- #### 1. Line Wins
336
-
337
- - 8 paylines (SINGLE mode) or 16 paylines (BOTH mode)
338
- - Evaluated left-to-right and right-to-left in 16-line mode
339
- - Cherry pays on 1, 2, or 3 matches
340
- - Line shapes follow classic 3x3 patterns
341
-
342
- #### 2. Wall Wins (Matrix/Screen Wins)
343
-
344
- - Full 3x3 of same symbol
345
- - Special mixed types:
346
- - **Cherry Mix**: CH + CH_S combinations
347
- - **Any Bar Mix**: BA1 + BA2 + BA3 + BA_S
348
- - **All Fruits**: ME + BE + PR + OR
349
- - **All Colors**: Mixed symbol colors
350
- - **Important**: Wall wins suppress line wins when active
351
-
352
- #### 3. Scatter Wins (Seven)
353
-
354
- - 2-9 Seven symbols anywhere on screen
355
- - Super Seven only = doubled payout
356
- - **Important**: Scatter wins suppress line wins when active
357
-
358
- #### 4. Special Wins (Bonus modes only)
359
-
360
- - **Cherry Pieces**: Count of cherry pieces (Jackpot Bonus)
361
- - **Bell Scatter**: Bell count anywhere (Bell Bonus)
362
- - **Super Bar Scatter**: Super Bar count anywhere (Bar1 Bonus)
363
-
364
- ### Bonus System
365
-
366
- Five distinct bonus types with counter-based triggers:
367
-
368
- | Bonus | Trigger | Spins | Description |
369
- |-------|---------|-------|-------------|
370
- | **Jackpot** | 3x Cherry on first 8 lines | 3 | Cherry pieces with progressive jackpot chance |
371
- | **Cherry** | Cherry pair counter = 0 | Variable | Cherry respin feature |
372
- | **Bell** | Bell triple counter = 0 | 5 | Bell scatter pays + pool jackpot |
373
- | **Bar1** | Bar1 triple counter = 0 | 7 | Super Bar scatter pays |
374
- | **Respin** | Lone center cherry on losing spin | 1-2 | Corner respin feature |
375
-
376
- ### Counter System
377
-
378
- Each bonus has an associated counter that decrements on specific symbol combinations:
379
-
380
- - **Jackpot Counter**: Decrements on specific patterns, triggers at 0
381
- - **Cherry Counter**: Decrements on cherry pairs, resets to 6 or 9
382
- - **Bell Counter**: Decrements on bell triples, resets to 3 or 5
383
- - **Bar1 Counter**: Decrements on bar1 triples, resets to 1
384
-
385
- ### Jackpot System
386
-
387
- Two jackpot types:
388
-
389
- - **Progressive Jackpot** (`bonusJackpotValue`): Accumulates on losing paid spins, paid during Jackpot Bonus
390
- - **Pool Jackpot** (`poolJackpotValue`): Accumulates separately, paid when Bell Bonus triggers
391
-
392
- ## Integration Examples
393
-
394
- ### Example 1: Basic RGS Integration
395
-
396
- ```typescript
397
- import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
398
-
399
- class GameSessionService {
400
- private gameEngine: HappyPandaV1GameEngine;
401
-
402
- constructor() {
403
- this.gameEngine = new HappyPandaV1GameEngine();
404
- }
405
-
406
- async createSession(userId: string, gameDirection: number, betStake: number) {
407
- const initCommand = {
408
- id: `init-${userId}-${Date.now()}`,
409
- type: 'INIT_SESSION_STATE',
410
- payload: { gameDirection, betStake }
411
- };
412
-
413
- const result = await this.gameEngine.processCommand(null, null, initCommand);
414
-
415
- // Store result.publicState in database (visible to player)
416
- // Store result.privateState securely (server-side only)
417
- // Store result.rngOutcome for audit trail
418
-
419
- return {
420
- sessionId: userId,
421
- publicState: result.publicState,
422
- // Never send privateState to client!
423
- };
424
- }
425
-
426
- async processSpin(sessionId: string, publicState: any, privateState: any) {
427
- const spinCommand = {
428
- id: `spin-${sessionId}-${Date.now()}`,
429
- type: 'SPIN',
430
- payload: {}
431
- };
432
-
433
- const result = await this.gameEngine.processCommand(
434
- publicState,
435
- privateState,
436
- spinCommand
437
- );
438
-
439
- // Update states in database
440
- // Log RNG outcome for compliance
441
- // Return outcome to client
442
-
443
- return {
444
- outcome: result.outcome,
445
- publicState: result.publicState,
446
- rngOutcome: result.rngOutcome, // For audit
447
- // privateState stays on server
448
- };
449
- }
450
- }
451
- ```
452
-
453
- ### Example 2: Handling Bonus Triggers
454
-
455
- ```typescript
456
- async handleSpinResult(spinResult: any) {
457
- const { outcome, publicState, privateState } = spinResult;
458
-
459
- // Check win types
460
- console.log(`Total Payout: ${outcome.wins.totalPayout}`);
461
- console.log(`Line Wins: ${outcome.wins.lineWins.length}`);
462
- console.log(`Wall Win: ${outcome.wins.wallWin ? 'Yes' : 'No'}`);
463
- console.log(`Scatter Wins: ${outcome.wins.scatterWins.length}`);
464
-
465
- // Check for jackpot
466
- if (outcome.jackpotWon > 0) {
467
- console.log(`JACKPOT WON: ${outcome.jackpotWon}`);
468
- }
469
-
470
- if (outcome.poolJackpotWon > 0) {
471
- console.log(`POOL JACKPOT WON: ${outcome.poolJackpotWon}`);
472
- }
473
-
474
- // Check if bonus was triggered
475
- if (outcome.bonusTriggered) {
476
- return {
477
- type: 'BONUS_TRIGGERED',
478
- bonusType: outcome.bonusTriggered,
479
- spinsRemaining: publicState.spinsRemaining,
480
- message: `${outcome.bonusTriggered} bonus triggered!`
481
- };
482
- }
483
-
484
- // Check if bonus sequence completed
485
- if (outcome.isBonusComplete) {
486
- return {
487
- type: 'BONUS_COMPLETE',
488
- message: 'Bonus sequence completed'
489
- };
490
- }
491
-
492
- return {
493
- type: 'REGULAR_SPIN',
494
- totalPayout: outcome.wins.totalPayout
495
- };
496
- }
497
- ```
498
-
499
- ### Example 3: Game Direction Modes
500
-
501
- ```typescript
502
- // 8-line mode (SINGLE)
503
- const single8Lines = await gameEngine.processCommand(null, null, {
504
- id: 'init-single',
505
- type: 'INIT_SESSION_STATE',
506
- payload: { gameDirection: 0, betStake: 1 }
507
- });
508
- // Total bet = 8 x betStake = 8
509
-
510
- // 16-line mode (BOTH)
511
- const both16Lines = await gameEngine.processCommand(null, null, {
512
- id: 'init-both',
513
- type: 'INIT_SESSION_STATE',
514
- payload: { gameDirection: 1, betStake: 1 }
515
- });
516
- // Total bet = 16 x betStake = 16
517
- ```
518
-
519
- ## Development
520
-
521
- ### Running Tests
522
-
523
- ```bash
524
- # Run all tests
525
- npm test
526
-
527
- # Run tests in watch mode
528
- npm run test:watch
529
-
530
- # Run with coverage
531
- npm run test:cov
532
-
533
- # Run RTP diagnostic (100K spins)
534
- npm test -- --testNamePattern="RTP Diagnostic"
535
-
536
- # Run C++ parity tests
537
- npm test -- --testPathPattern="cpp-parity"
538
- ```
539
-
540
- ### Building
541
-
542
- ```bash
543
- # Clean build
544
- npm run clean
545
- npm run build
546
-
547
- # Development mode
548
- npm run build
549
- ```
550
-
551
- ### Linting
552
-
553
- ```bash
554
- # Check for issues
555
- npm run lint
556
-
557
- # Auto-fix issues
558
- npm run lint -- --fix
559
- ```
560
-
561
- ## Configuration
562
-
563
- Game configuration located in `src/config/happy-panda.config.ts`:
564
-
565
- - Symbol definitions and IDs
566
- - Paytable values for all win types
567
- - Line shapes for 8 and 16 line modes
568
- - Reel strip weights by spin type
569
- - Bonus counter initial values
570
- - Jackpot accumulation rates
571
-
572
- All values match the original Excel specification (`CherryMaster_A_2_26.05.2025.xlsx`).
573
-
574
- ## Type Exports
575
-
576
- The package exports all necessary types for TypeScript integration:
577
-
578
- ```typescript
579
- import {
580
- // V1 Game Engine
581
- HappyPandaV1GameEngine,
582
- GameEngine,
583
- GameEngineInfo,
584
- GameActionCommand,
585
- CommandProcessingResult,
586
- RngOutcome,
587
- RngOutcomeRecord,
588
-
589
- // Core Engine
590
- HappyPandaEngine,
591
-
592
- // Configuration
593
- Symbol,
594
- SpinType,
595
- ScreenWinType,
596
- GRID,
597
- LINE_SHAPES,
598
- LINES_PER_DIRECTION,
599
-
600
- // Domain Types
601
- Grid,
602
- Position,
603
- LineWin,
604
- WallWin,
605
- ScatterWin,
606
- SpecialWin,
607
- SpinWinResult,
608
- BonusCounters,
609
- PendingBonuses,
610
- JackpotState,
611
- GameDirection,
612
- GameState,
613
- PublicState,
614
- PrivateState,
615
- SpinRequest,
616
- SpinResponse,
617
- SessionState,
618
- RngProvider,
619
- CommandType,
620
- GameCommand,
621
-
622
- // Logic Services
623
- evaluateSpin,
624
- evaluateLineWins,
625
- evaluateWallWin,
626
- evaluateScatterWins,
627
- generateGrid,
628
- } from '@omnitronix/happy-panda-game-engine';
629
- ```
630
-
631
- ## Key Differences from Traditional Slots
632
-
633
- ### Classic 3x3 Layout
634
-
635
- - **Traditional Modern**: 5+ reels, multiple rows
636
- - **Happy Panda**: Classic 3x3 grid with bidirectional paylines
637
- - **Advantage**: Nostalgic gameplay, simpler visual presentation
638
-
639
- ### Bidirectional Paylines
640
-
641
- - **8-Line Mode**: Left-to-right only
642
- - **16-Line Mode**: Both directions (LTR + RTL)
643
- - **Strategic Choice**: Player chooses mode based on bet preference
644
-
645
- ### Wall Wins (Matrix Wins)
646
-
647
- - **Screen-filling wins**: Full 3x3 of same/related symbols
648
- - **Multiple types**: Pure, cherry mix, bar mix, fruits, colors
649
- - **Important**: Wall wins suppress line wins (no double-counting)
650
-
651
- ### Counter-Based Bonuses
652
-
653
- - **Not scatter-triggered**: Bonuses trigger via counter depletion
654
- - **Progressive build-up**: Counters decrement on specific symbol combos
655
- - **Multiple bonus types**: 5 distinct bonus modes with different mechanics
656
-
657
- ### Dual Jackpot System
658
-
659
- - **Progressive Jackpot**: Accumulates on losses, paid in Jackpot Bonus
660
- - **Pool Jackpot**: Separate accumulator, paid with Bell Bonus
661
- - **Dual opportunity**: Two paths to jackpot wins
662
-
663
- ## Documentation
664
-
665
- - **Test Protocol**: `docs/TEST-PROTOCOL-RTP-100M.md` - Complete 100M spin test results
666
- - **RTP Matching**: `docs/RTP-MATCHING.md` - Implementation details and tuning history
667
- - **C++ Source**: `math/Happy Red Panda/CherryMaster_A_2.cpp`
668
- - **Excel Spec**: `math/Happy Red Panda/CherryMaster_A_2_26.05.2025.xlsx`
669
-
670
- ## License
671
-
672
- UNLICENSED - Internal use only for Omnitronix
673
-
674
- ## Support
675
-
676
- For questions or issues, contact the Omnitronix development team.
1
+ # Happy Panda Game Engine
2
+
3
+ ![Version](https://img.shields.io/badge/version-0.0.2-blue.svg)
4
+ ![License](https://img.shields.io/badge/license-UNLICENSED-red.svg)
5
+ ![Package](https://img.shields.io/badge/package-%40omnitronix%2Fhappy--panda--game--engine-green.svg)
6
+
7
+ Pure business logic library for the Happy Panda (Cherry Master) slot game. A framework-agnostic, TypeScript-based game engine that handles all core game mechanics, bonus systems, and jackpot logic. Achieves C++ parity with the original `CherryMaster_A_2.cpp` implementation.
8
+
9
+ ## What is Happy Panda Game Engine?
10
+
11
+ The Happy Panda Game Engine is an isolated, framework-agnostic library containing pure business logic for the Happy Panda slot game. It implements a command-based architecture that separates game logic from presentation and infrastructure concerns.
12
+
13
+ ### Core Characteristics
14
+
15
+ - **Pure Business Logic**: Contains only game rules, calculations, and state transitions
16
+ - **Framework Agnostic**: No dependencies on specific UI frameworks or web servers
17
+ - **Command-Based Architecture**: All interactions through well-defined commands
18
+ - **State Separation**: Distinguishes between public state (visible to players) and private state (server-side only)
19
+ - **RNG Integration**: Supports pluggable RNG providers for testing and production
20
+ - **Audit Trail**: Complete RNG outcome tracking for compliance and debugging
21
+ - **C++ Parity**: Verified against original C++ implementation with 100M spin validation
22
+
23
+ ### Game Specifications
24
+
25
+ - **RTP**: 96.05% (verified at 95.91% over 100M spins, within tolerance)
26
+ - **Game Type**: Classic 3x3 Slot
27
+ - **Version**: 1.0.0
28
+ - **Layout**: 3 reels x 3 rows
29
+ - **Win Evaluation**: 8/16 bidirectional paylines + wall wins + scatter wins
30
+ - **Modes**: 8-line (SINGLE) and 16-line (BOTH)
31
+
32
+ ## RTP Validation Results
33
+
34
+ ### 100 Million Spin Verification
35
+
36
+ ```
37
+ ================================================================
38
+ HAPPY PANDA RTP VERIFICATION - 100 MILLION SPINS
39
+ ================================================================
40
+
41
+ Configuration:
42
+ - Game Direction: SINGLE (8 lines)
43
+ - Bet per spin: 8
44
+ - Seeds: 10 x 10M = 100M total paid spins
45
+ - C++ Target RTP: 96.05%
46
+
47
+ RTP Breakdown by Spin Type:
48
+ ----------------------------------------------------------------
49
+ PAID_SPIN : 62.54% | C++: 63.51% | Diff: -0.97%
50
+ BONUS_JACKPOT : 16.24% | C++: 13.56% | Diff: +2.68%
51
+ BONUS_CHERRY : 3.96% | C++: 3.67% | Diff: +0.29%
52
+ BONUS_BELL : 5.06% | C++: 5.83% | Diff: -0.77%
53
+ BONUS_BAR1 : 5.47% | C++: 6.31% | Diff: -0.84%
54
+ RESPIN_CHERRY : 2.64% | C++: 3.18% | Diff: -0.54%
55
+ ----------------------------------------------------------------
56
+ TOTAL : 95.91% | C++: 96.05%
57
+
58
+ Statistics:
59
+ - Standard Deviation: 0.32%
60
+ - Range: 95.54% - 96.40%
61
+
62
+ STATUS: PASS - RTP within 0.15% tolerance
63
+ ================================================================
64
+ ```
65
+
66
+ | Metric | TypeScript | C++ Target | Difference | Status |
67
+ |--------|------------|------------|------------|--------|
68
+ | **RTP (100M spins)** | 95.91% | 96.05% | -0.14% | **PASS** |
69
+ | PAID_SPIN | 62.54% | 63.51% | -0.97% | Match |
70
+ | BONUS_JACKPOT | 16.24% | 13.56% | +2.68% | Match |
71
+ | BONUS_CHERRY | 3.96% | 3.67% | +0.29% | Match |
72
+ | BONUS_BELL | 5.06% | 5.83% | -0.77% | Match |
73
+ | BONUS_BAR1 | 5.47% | 6.31% | -0.84% | Match |
74
+ | RESPIN_CHERRY | 2.64% | 3.18% | -0.54% | Match |
75
+
76
+ **No configuration values from XLSX were modified** - only calculation logic was adjusted to match C++ behavior.
77
+
78
+ ## Features
79
+
80
+ - **Command-Based Architecture**: 3 different command types for all game operations
81
+ - **State Management**: Public/private state separation with type safety
82
+ - **RNG Integration**: Pluggable RNG providers with audit trail support
83
+ - **Bidirectional Paylines**: 8 or 16 paylines with left-to-right and right-to-left evaluation
84
+ - **Wall Wins**: Full 3x3 matrix wins with multiple types (pure, mixed, fruits, colors)
85
+ - **Scatter Wins**: Seven symbols pay anywhere on screen
86
+ - **Bonus System**: 5 distinct bonus types with counter-based triggers
87
+ - **Jackpot System**: Progressive and pool jackpots
88
+ - **TypeScript Support**: Complete type definitions for all interfaces
89
+ - **Comprehensive Testing**: Full test suite with Jest and 100M spin RTP validation
90
+
91
+ ## Architecture Overview
92
+
93
+ The game engine follows a modular architecture with clear separation of concerns:
94
+
95
+ ### Core Components
96
+
97
+ - **Game Engine** (`HappyPandaEngine`): Main entry point and command processor
98
+ - **V1 Wrapper** (`HappyPandaV1GameEngine`): Service integration wrapper with GameEngine interface
99
+ - **Spin Generator**: Grid generation with weighted random selection
100
+ - **Win Evaluator**: Line, wall, scatter, and special win detection
101
+ - **Counter Manager**: Bonus counter management and trigger logic
102
+ - **Jackpot Manager**: Progressive and pool jackpot handling
103
+
104
+ ### Directory Structure
105
+
106
+ ```
107
+ src/
108
+ ├── happy-panda-v1.game-engine.ts # V1 service wrapper
109
+ ├── engine/
110
+ │ └── happy-panda-engine.ts # Main engine class
111
+ ├── config/
112
+ │ └── happy-panda.config.ts # All game configuration (XLSX values)
113
+ ├── rng/
114
+ │ ├── spin-generator.ts # Grid generation with C++ parity
115
+ │ └── weighted-random.ts # Weighted random selection
116
+ ├── logic/
117
+ │ ├── handlers/
118
+ │ │ └── spin-handler.ts # Spin orchestration
119
+ │ └── services/
120
+ │ ├── win-evaluator.ts # Win detection (line/wall/scatter)
121
+ │ ├── counter-manager.ts # Bonus counter management
122
+ │ └── jackpot-manager.ts # Jackpot handling
123
+ ├── domain/
124
+ │ └── types.ts # Type definitions
125
+ └── __tests__/
126
+ ├── rtp-simulation.test.ts # RTP validation
127
+ ├── rtp-diagnostic.test.ts # RTP breakdown by spin type
128
+ ├── cpp-parity.test.ts # C++ parity tests
129
+ └── win-evaluator.test.ts # Win evaluation tests
130
+
131
+ docs/
132
+ ├── RTP-MATCHING.md # RTP implementation details
133
+ └── TEST-PROTOCOL-RTP-100M.md # 100M spin test protocol
134
+ ```
135
+
136
+ ## Installation
137
+
138
+ ```bash
139
+ npm install @omnitronix/happy-panda-game-engine
140
+ ```
141
+
142
+ > **Note**: This is a private package for Omnitronix internal use only (UNLICENSED).
143
+
144
+ ## Quick Start
145
+
146
+ ```typescript
147
+ import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
148
+
149
+ // Initialize game engine
150
+ const gameEngine = new HappyPandaV1GameEngine();
151
+
152
+ // Get engine info
153
+ const info = gameEngine.getGameEngineInfo();
154
+ // { gameCode: 'happy-panda', version: '1.0.0', rtp: 96.05, gameType: 'slot', gameName: 'Happy Panda', provider: 'Omnitronix' }
155
+
156
+ // Initialize session
157
+ const initCommand = {
158
+ id: 'cmd-init-123',
159
+ type: 'INIT_SESSION_STATE',
160
+ payload: {
161
+ gameDirection: 0, // 0 = SINGLE (8 lines), 1 = BOTH (16 lines)
162
+ betStake: 1
163
+ }
164
+ };
165
+
166
+ const initResult = await gameEngine.processCommand(null, null, initCommand);
167
+ // Returns: { success: true, publicState, privateState, outcome, rngOutcome }
168
+
169
+ // Process spin
170
+ const spinCommand = {
171
+ id: 'cmd-spin-456',
172
+ type: 'SPIN',
173
+ payload: {}
174
+ };
175
+
176
+ const spinResult = await gameEngine.processCommand(
177
+ initResult.publicState,
178
+ initResult.privateState,
179
+ spinCommand
180
+ );
181
+ ```
182
+
183
+ ## API Reference
184
+
185
+ ### Main Class: `HappyPandaV1GameEngine`
186
+
187
+ Implements the standard `GameEngine` interface for integration with game-engine-service.
188
+
189
+ #### Constructor
190
+
191
+ ```typescript
192
+ new HappyPandaV1GameEngine()
193
+ ```
194
+
195
+ - Initializes game engine with tracked RNG provider
196
+ - Ready to process commands immediately
197
+
198
+ #### Methods
199
+
200
+ **`getGameEngineInfo(): GameEngineInfo`**
201
+ Returns game metadata including code, version, RTP, and provider.
202
+
203
+ ```typescript
204
+ {
205
+ gameCode: 'happy-panda',
206
+ version: '1.0.0',
207
+ rtp: 96.05,
208
+ gameType: 'slot',
209
+ gameName: 'Happy Panda',
210
+ provider: 'Omnitronix'
211
+ }
212
+ ```
213
+
214
+ **`processCommand(publicState, privateState, command): Promise<CommandProcessingResult>`**
215
+ Main command processor that handles all game operations.
216
+
217
+ ### Commands
218
+
219
+ The game engine supports 3 different command types:
220
+
221
+ #### 1. INIT_SESSION_STATE
222
+
223
+ **Purpose**: Initialize game session state
224
+
225
+ **Payload**:
226
+ ```typescript
227
+ {
228
+ gameDirection?: number; // 0 = SINGLE (8 lines), 1 = BOTH (16 lines). Default: 0
229
+ betStake?: number; // Bet multiplier. Default: 1
230
+ }
231
+ ```
232
+
233
+ **Returns**: Initial public and private state with default values
234
+
235
+ #### 2. SPIN
236
+
237
+ **Purpose**: Execute a spin
238
+
239
+ **Payload**: None required (uses current state)
240
+
241
+ **Returns**: Spin result with grid, wins, and state updates
242
+
243
+ **Result Structure**:
244
+ ```typescript
245
+ {
246
+ success: true,
247
+ publicState: PublicState,
248
+ privateState: PrivateState,
249
+ outcome: {
250
+ sessionId: string,
251
+ grid: Symbol[][], // 3x3 grid
252
+ wins: SpinWinResult, // All wins
253
+ state: PublicState,
254
+ jackpotWon: number, // Jackpot payout (if any)
255
+ poolJackpotWon: number, // Pool jackpot payout (if any)
256
+ bonusTriggered: SpinType | null,
257
+ isBonusComplete: boolean
258
+ },
259
+ rngOutcome: RngOutcome // Audit trail
260
+ }
261
+ ```
262
+
263
+ #### 3. GET_SYMBOLS
264
+
265
+ **Purpose**: Retrieve symbol definitions
266
+
267
+ **Payload**: None
268
+
269
+ **Returns**: Array of symbol definitions with names and values
270
+
271
+ ### Debug/Cheat Commands (Testing/Admin)
272
+
273
+ The engine supports debug commands for QA testing via the dev-tools service. These commands are **blocked in REAL_MONEY mode**.
274
+
275
+ #### CHEAT_TRIGGER_BONUS
276
+
277
+ Force trigger a specific bonus round for testing.
278
+
279
+ **Payload**:
280
+ ```typescript
281
+ interface CheatTriggerBonusCommand {
282
+ sessionId: string;
283
+ bonusType: 'BONUS_JACKPOT' | 'BONUS_CHERRY' | 'BONUS_BELL' | 'BONUS_BAR1' | 'RESPIN_CHERRY';
284
+ betAmount: number;
285
+ }
286
+ ```
287
+
288
+ **Usage**:
289
+ ```typescript
290
+ const result = await engine.processCommand(
291
+ publicState,
292
+ privateState,
293
+ {
294
+ id: 'cheat-cmd-1',
295
+ type: 'CHEAT_TRIGGER_BONUS',
296
+ payload: {
297
+ sessionId: 'session-123',
298
+ bonusType: 'BONUS_JACKPOT', // or any other bonus type
299
+ betAmount: 8,
300
+ },
301
+ },
302
+ );
303
+ ```
304
+
305
+ **Bonus Types**:
306
+
307
+ | Type | Description |
308
+ |------|-------------|
309
+ | `BONUS_JACKPOT` | Triggers 3-spin Jackpot bonus with cherry pieces grid and progressive jackpot chance |
310
+ | `BONUS_CHERRY` | Triggers Cherry free spins bonus with cherry respin feature |
311
+ | `BONUS_BELL` | Triggers 5-spin Bell bonus with bell scatter pays + pool jackpot |
312
+ | `BONUS_BAR1` | Triggers 7-spin Bar1 bonus with Super Bar scatter pays |
313
+ | `RESPIN_CHERRY` | Triggers center cherry respin (1-2 corner respins) |
314
+
315
+ **Returns**: Updated state with bonus pending. Execute `SPIN` to begin the bonus sequence.
316
+
317
+ ### State Types
318
+
319
+ #### PublicState (visible to player)
320
+
321
+ ```typescript
322
+ {
323
+ gameDirection: GameDirection; // 0 = SINGLE, 1 = BOTH
324
+ betStake: number; // Bet multiplier
325
+ betGame: number; // Total bet (8 or 16 x betStake)
326
+ currentSpinType: SpinType; // Current spin type
327
+ spinsRemaining: number; // Remaining bonus spins
328
+ grid: Symbol[][]; // Current 3x3 grid
329
+ bonusJackpotValue: number; // Progressive jackpot
330
+ poolJackpotValue: number; // Pool jackpot
331
+ hasPendingBonus: boolean; // Indicates pending bonus
332
+ }
333
+ ```
334
+
335
+ #### PrivateState (server-side only)
336
+
337
+ ```typescript
338
+ {
339
+ counters: BonusCounters; // Bonus trigger counters
340
+ pendingBonuses: PendingBonuses; // Queued bonuses
341
+ nextSpinType: SpinType; // Next spin type
342
+ accumulatedBonusWins: number; // Bonus sequence wins
343
+ centerCherrySymbol: Symbol | null; // For respin feature
344
+ }
345
+ ```
346
+
347
+ #### CommandProcessingResult
348
+
349
+ ```typescript
350
+ {
351
+ success: boolean;
352
+ publicState: PublicState;
353
+ privateState: PrivateState;
354
+ outcome?: SpinResponse;
355
+ message?: string;
356
+ rngOutcome?: RngOutcome; // RNG audit trail
357
+ }
358
+ ```
359
+
360
+ ## Game Mechanics
361
+
362
+ ### Symbol Set
363
+
364
+ | ID | Symbol | Description |
365
+ |----|--------|-------------|
366
+ | 0 | SEV_S | Super Seven (scatter, doubled payout when solo) |
367
+ | 1 | SEV | Seven (scatter) |
368
+ | 2 | BA3 | Bar 3 |
369
+ | 3 | BA2 | Bar 2 |
370
+ | 4 | BA1 | Bar 1 |
371
+ | 5 | ME | Melon |
372
+ | 6 | BE | Bell |
373
+ | 7 | PR | Prune |
374
+ | 8 | OR | Orange |
375
+ | 9 | CH | Cherry |
376
+ | 10 | CH_S | Cherry Special |
377
+ | 11 | BA_S | Super Bar |
378
+
379
+ ### Win Types
380
+
381
+ #### 1. Line Wins
382
+
383
+ - 8 paylines (SINGLE mode) or 16 paylines (BOTH mode)
384
+ - Evaluated left-to-right and right-to-left in 16-line mode
385
+ - Cherry pays on 1, 2, or 3 matches
386
+ - Line shapes follow classic 3x3 patterns
387
+
388
+ #### 2. Wall Wins (Matrix/Screen Wins)
389
+
390
+ - Full 3x3 of same symbol
391
+ - Special mixed types:
392
+ - **Cherry Mix**: CH + CH_S combinations
393
+ - **Any Bar Mix**: BA1 + BA2 + BA3 + BA_S
394
+ - **All Fruits**: ME + BE + PR + OR
395
+ - **All Colors**: Mixed symbol colors
396
+ - **Important**: Wall wins suppress line wins when active
397
+
398
+ #### 3. Scatter Wins (Seven)
399
+
400
+ - 2-9 Seven symbols anywhere on screen
401
+ - Super Seven only = doubled payout
402
+ - **Important**: Scatter wins suppress line wins when active
403
+
404
+ #### 4. Special Wins (Bonus modes only)
405
+
406
+ - **Cherry Pieces**: Count of cherry pieces (Jackpot Bonus)
407
+ - **Bell Scatter**: Bell count anywhere (Bell Bonus)
408
+ - **Super Bar Scatter**: Super Bar count anywhere (Bar1 Bonus)
409
+
410
+ ### Bonus System
411
+
412
+ Five distinct bonus types with counter-based triggers:
413
+
414
+ | Bonus | Trigger | Spins | Description |
415
+ |-------|---------|-------|-------------|
416
+ | **Jackpot** | 3x Cherry on first 8 lines | 3 | Cherry pieces with progressive jackpot chance |
417
+ | **Cherry** | Cherry pair counter = 0 | Variable | Cherry respin feature |
418
+ | **Bell** | Bell triple counter = 0 | 5 | Bell scatter pays + pool jackpot |
419
+ | **Bar1** | Bar1 triple counter = 0 | 7 | Super Bar scatter pays |
420
+ | **Respin** | Lone center cherry on losing spin | 1-2 | Corner respin feature |
421
+
422
+ ### Counter System
423
+
424
+ Each bonus has an associated counter that decrements on specific symbol combinations:
425
+
426
+ - **Jackpot Counter**: Decrements on specific patterns, triggers at 0
427
+ - **Cherry Counter**: Decrements on cherry pairs, resets to 6 or 9
428
+ - **Bell Counter**: Decrements on bell triples, resets to 3 or 5
429
+ - **Bar1 Counter**: Decrements on bar1 triples, resets to 1
430
+
431
+ ### Jackpot System
432
+
433
+ Two jackpot types:
434
+
435
+ - **Progressive Jackpot** (`bonusJackpotValue`): Accumulates on losing paid spins, paid during Jackpot Bonus
436
+ - **Pool Jackpot** (`poolJackpotValue`): Accumulates separately, paid when Bell Bonus triggers
437
+
438
+ ## Integration Examples
439
+
440
+ ### Example 1: Basic RGS Integration
441
+
442
+ ```typescript
443
+ import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
444
+
445
+ class GameSessionService {
446
+ private gameEngine: HappyPandaV1GameEngine;
447
+
448
+ constructor() {
449
+ this.gameEngine = new HappyPandaV1GameEngine();
450
+ }
451
+
452
+ async createSession(userId: string, gameDirection: number, betStake: number) {
453
+ const initCommand = {
454
+ id: `init-${userId}-${Date.now()}`,
455
+ type: 'INIT_SESSION_STATE',
456
+ payload: { gameDirection, betStake }
457
+ };
458
+
459
+ const result = await this.gameEngine.processCommand(null, null, initCommand);
460
+
461
+ // Store result.publicState in database (visible to player)
462
+ // Store result.privateState securely (server-side only)
463
+ // Store result.rngOutcome for audit trail
464
+
465
+ return {
466
+ sessionId: userId,
467
+ publicState: result.publicState,
468
+ // Never send privateState to client!
469
+ };
470
+ }
471
+
472
+ async processSpin(sessionId: string, publicState: any, privateState: any) {
473
+ const spinCommand = {
474
+ id: `spin-${sessionId}-${Date.now()}`,
475
+ type: 'SPIN',
476
+ payload: {}
477
+ };
478
+
479
+ const result = await this.gameEngine.processCommand(
480
+ publicState,
481
+ privateState,
482
+ spinCommand
483
+ );
484
+
485
+ // Update states in database
486
+ // Log RNG outcome for compliance
487
+ // Return outcome to client
488
+
489
+ return {
490
+ outcome: result.outcome,
491
+ publicState: result.publicState,
492
+ rngOutcome: result.rngOutcome, // For audit
493
+ // privateState stays on server
494
+ };
495
+ }
496
+ }
497
+ ```
498
+
499
+ ### Example 2: Handling Bonus Triggers
500
+
501
+ ```typescript
502
+ async handleSpinResult(spinResult: any) {
503
+ const { outcome, publicState, privateState } = spinResult;
504
+
505
+ // Check win types
506
+ console.log(`Total Payout: ${outcome.wins.totalPayout}`);
507
+ console.log(`Line Wins: ${outcome.wins.lineWins.length}`);
508
+ console.log(`Wall Win: ${outcome.wins.wallWin ? 'Yes' : 'No'}`);
509
+ console.log(`Scatter Wins: ${outcome.wins.scatterWins.length}`);
510
+
511
+ // Check for jackpot
512
+ if (outcome.jackpotWon > 0) {
513
+ console.log(`JACKPOT WON: ${outcome.jackpotWon}`);
514
+ }
515
+
516
+ if (outcome.poolJackpotWon > 0) {
517
+ console.log(`POOL JACKPOT WON: ${outcome.poolJackpotWon}`);
518
+ }
519
+
520
+ // Check if bonus was triggered
521
+ if (outcome.bonusTriggered) {
522
+ return {
523
+ type: 'BONUS_TRIGGERED',
524
+ bonusType: outcome.bonusTriggered,
525
+ spinsRemaining: publicState.spinsRemaining,
526
+ message: `${outcome.bonusTriggered} bonus triggered!`
527
+ };
528
+ }
529
+
530
+ // Check if bonus sequence completed
531
+ if (outcome.isBonusComplete) {
532
+ return {
533
+ type: 'BONUS_COMPLETE',
534
+ message: 'Bonus sequence completed'
535
+ };
536
+ }
537
+
538
+ return {
539
+ type: 'REGULAR_SPIN',
540
+ totalPayout: outcome.wins.totalPayout
541
+ };
542
+ }
543
+ ```
544
+
545
+ ### Example 3: Game Direction Modes
546
+
547
+ ```typescript
548
+ // 8-line mode (SINGLE)
549
+ const single8Lines = await gameEngine.processCommand(null, null, {
550
+ id: 'init-single',
551
+ type: 'INIT_SESSION_STATE',
552
+ payload: { gameDirection: 0, betStake: 1 }
553
+ });
554
+ // Total bet = 8 x betStake = 8
555
+
556
+ // 16-line mode (BOTH)
557
+ const both16Lines = await gameEngine.processCommand(null, null, {
558
+ id: 'init-both',
559
+ type: 'INIT_SESSION_STATE',
560
+ payload: { gameDirection: 1, betStake: 1 }
561
+ });
562
+ // Total bet = 16 x betStake = 16
563
+ ```
564
+
565
+ ## Development
566
+
567
+ ### Running Tests
568
+
569
+ ```bash
570
+ # Run all tests
571
+ npm test
572
+
573
+ # Run tests in watch mode
574
+ npm run test:watch
575
+
576
+ # Run with coverage
577
+ npm run test:cov
578
+
579
+ # Run RTP diagnostic (100K spins)
580
+ npm test -- --testNamePattern="RTP Diagnostic"
581
+
582
+ # Run C++ parity tests
583
+ npm test -- --testPathPattern="cpp-parity"
584
+ ```
585
+
586
+ ### Building
587
+
588
+ ```bash
589
+ # Clean build
590
+ npm run clean
591
+ npm run build
592
+
593
+ # Development mode
594
+ npm run build
595
+ ```
596
+
597
+ ### Linting
598
+
599
+ ```bash
600
+ # Check for issues
601
+ npm run lint
602
+
603
+ # Auto-fix issues
604
+ npm run lint -- --fix
605
+ ```
606
+
607
+ ## Configuration
608
+
609
+ Game configuration located in `src/config/happy-panda.config.ts`:
610
+
611
+ - Symbol definitions and IDs
612
+ - Paytable values for all win types
613
+ - Line shapes for 8 and 16 line modes
614
+ - Reel strip weights by spin type
615
+ - Bonus counter initial values
616
+ - Jackpot accumulation rates
617
+
618
+ All values match the original Excel specification (`CherryMaster_A_2_26.05.2025.xlsx`).
619
+
620
+ ## Type Exports
621
+
622
+ The package exports all necessary types for TypeScript integration:
623
+
624
+ ```typescript
625
+ import {
626
+ // V1 Game Engine
627
+ HappyPandaV1GameEngine,
628
+ GameEngine,
629
+ GameEngineInfo,
630
+ GameActionCommand,
631
+ CommandProcessingResult,
632
+ RngOutcome,
633
+ RngOutcomeRecord,
634
+
635
+ // Core Engine
636
+ HappyPandaEngine,
637
+
638
+ // Configuration
639
+ Symbol,
640
+ SpinType,
641
+ ScreenWinType,
642
+ GRID,
643
+ LINE_SHAPES,
644
+ LINES_PER_DIRECTION,
645
+
646
+ // Domain Types
647
+ Grid,
648
+ Position,
649
+ LineWin,
650
+ WallWin,
651
+ ScatterWin,
652
+ SpecialWin,
653
+ SpinWinResult,
654
+ BonusCounters,
655
+ PendingBonuses,
656
+ JackpotState,
657
+ GameDirection,
658
+ GameState,
659
+ PublicState,
660
+ PrivateState,
661
+ SpinRequest,
662
+ SpinResponse,
663
+ SessionState,
664
+ RngProvider,
665
+ CommandType,
666
+ GameCommand,
667
+
668
+ // Logic Services
669
+ evaluateSpin,
670
+ evaluateLineWins,
671
+ evaluateWallWin,
672
+ evaluateScatterWins,
673
+ generateGrid,
674
+ } from '@omnitronix/happy-panda-game-engine';
675
+ ```
676
+
677
+ ## Key Differences from Traditional Slots
678
+
679
+ ### Classic 3x3 Layout
680
+
681
+ - **Traditional Modern**: 5+ reels, multiple rows
682
+ - **Happy Panda**: Classic 3x3 grid with bidirectional paylines
683
+ - **Advantage**: Nostalgic gameplay, simpler visual presentation
684
+
685
+ ### Bidirectional Paylines
686
+
687
+ - **8-Line Mode**: Left-to-right only
688
+ - **16-Line Mode**: Both directions (LTR + RTL)
689
+ - **Strategic Choice**: Player chooses mode based on bet preference
690
+
691
+ ### Wall Wins (Matrix Wins)
692
+
693
+ - **Screen-filling wins**: Full 3x3 of same/related symbols
694
+ - **Multiple types**: Pure, cherry mix, bar mix, fruits, colors
695
+ - **Important**: Wall wins suppress line wins (no double-counting)
696
+
697
+ ### Counter-Based Bonuses
698
+
699
+ - **Not scatter-triggered**: Bonuses trigger via counter depletion
700
+ - **Progressive build-up**: Counters decrement on specific symbol combos
701
+ - **Multiple bonus types**: 5 distinct bonus modes with different mechanics
702
+
703
+ ### Dual Jackpot System
704
+
705
+ - **Progressive Jackpot**: Accumulates on losses, paid in Jackpot Bonus
706
+ - **Pool Jackpot**: Separate accumulator, paid with Bell Bonus
707
+ - **Dual opportunity**: Two paths to jackpot wins
708
+
709
+ ## Documentation
710
+
711
+ - **Test Protocol**: `docs/TEST-PROTOCOL-RTP-100M.md` - Complete 100M spin test results
712
+ - **RTP Matching**: `docs/RTP-MATCHING.md` - Implementation details and tuning history
713
+ - **C++ Source**: `math/Happy Red Panda/CherryMaster_A_2.cpp`
714
+ - **Excel Spec**: `math/Happy Red Panda/CherryMaster_A_2_26.05.2025.xlsx`
715
+
716
+ ## License
717
+
718
+ UNLICENSED - Internal use only for Omnitronix
719
+
720
+ ## Support
721
+
722
+ For questions or issues, contact the Omnitronix development team.