Happy Panda Game Engine
npm install @omnitronix/happy-panda-game-enginePure 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.
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.
- Pure Business Logic: Contains only game rules, calculations, and state transitions
- Framework Agnostic: No dependencies on specific UI frameworks or web servers
- Command-Based Architecture: All interactions through well-defined commands
- State Separation: Distinguishes between public state (visible to players) and private state (server-side only)
- RNG Integration: Supports pluggable RNG providers for testing and production
- Audit Trail: Complete RNG outcome tracking for compliance and debugging
- C++ Parity: Verified against original C++ implementation with 100M spin validation
- RTP: 96.05% (verified at 95.91% over 100M spins, within tolerance)
- Game Type: Classic 3x3 Slot
- Version: 1.0.0
- Layout: 3 reels x 3 rows
- Win Evaluation: 8/16 bidirectional paylines + wall wins + scatter wins
- Modes: 8-line (SINGLE) and 16-line (BOTH)
``
================================================================
HAPPY PANDA RTP VERIFICATION - 100 MILLION SPINS
================================================================
Configuration:
- Game Direction: SINGLE (8 lines)
- Bet per spin: 8
- Seeds: 10 x 10M = 100M total paid spins
- C++ Target RTP: 96.05%
RTP Breakdown by Spin Type:
----------------------------------------------------------------
BASE_GAME_SPIN : 62.54% | C++: 63.51% | Diff: -0.97%
BONUS_BAMBOO_TRIPLETS : 16.24% | C++: 13.56% | Diff: +2.68%
BONUS_BAMBOO_TWINS : 3.96% | C++: 3.67% | Diff: +0.29%
BONUS_CAMERA : 5.06% | C++: 5.83% | Diff: -0.77%
BONUS_FIREWORKS : 5.47% | C++: 6.31% | Diff: -0.84%
RESPIN_CENTER_BAMBOO : 2.64% | C++: 3.18% | Diff: -0.54%
----------------------------------------------------------------
TOTAL : 95.91% | C++: 96.05%
Statistics:
- Standard Deviation: 0.32%
- Range: 95.54% - 96.40%
STATUS: PASS - RTP within 0.15% tolerance
================================================================
`
| Metric | TypeScript | C++ Target | Difference | Status |
|--------|------------|------------|------------|--------|
| RTP (100M spins) | 95.91% | 96.05% | -0.14% | PASS |
| BASE_GAME_SPIN | 62.54% | 63.51% | -0.97% | Match |
| BONUS_BAMBOO_TRIPLETS | 16.24% | 13.56% | +2.68% | Match |
| BONUS_BAMBOO_TWINS | 3.96% | 3.67% | +0.29% | Match |
| BONUS_CAMERA | 5.06% | 5.83% | -0.77% | Match |
| BONUS_FIREWORKS | 5.47% | 6.31% | -0.84% | Match |
| RESPIN_CENTER_BAMBOO | 2.64% | 3.18% | -0.54% | Match |
No configuration values from XLSX were modified - only calculation logic was adjusted to match C++ behavior.
- Command-Based Architecture: 3 different command types for all game operations
- State Management: Public/private state separation with type safety
- RNG Integration: Pluggable RNG providers with audit trail support
- Bidirectional Paylines: 8 or 16 paylines with left-to-right and right-to-left evaluation
- Wall Wins: Full 3x3 matrix wins with multiple types (pure, mixed, fruits, colors)
- Scatter Wins: Red Panda symbols pay anywhere on screen
- Bonus System: 5 distinct bonus types with counter-based triggers
- Jackpot System: Progressive and pool jackpots
- TypeScript Support: Complete type definitions for all interfaces
- Comprehensive Testing: Full test suite with Jest and 100M spin RTP validation
The game engine follows a modular architecture with clear separation of concerns:
- Game Engine (HappyPandaEngine): Main entry point and command processorHappyPandaV1GameEngine
- V1 Wrapper (): Service integration wrapper with GameEngine interface
- Spin Generator: Grid generation with weighted random selection
- Win Evaluator: Line, wall, scatter, and special win detection
- Counter Manager: Bonus counter management and trigger logic
- Jackpot Manager: Progressive and pool jackpot handling
`
src/
├── happy-panda-v1.game-engine.ts # V1 service wrapper
├── engine/
│ └── happy-panda-engine.ts # Main engine class
├── config/
│ └── happy-panda.config.ts # All game configuration (XLSX values)
├── rng/
│ ├── spin-generator.ts # Grid generation with C++ parity
│ └── weighted-random.ts # Weighted random selection
├── logic/
│ ├── handlers/
│ │ └── spin-handler.ts # Spin orchestration
│ └── services/
│ ├── win-evaluator.ts # Win detection (line/wall/scatter)
│ ├── counter-manager.ts # Bonus counter management
│ └── jackpot-manager.ts # Jackpot handling
├── domain/
│ └── types.ts # Type definitions
└── __tests__/
├── rtp-simulation.test.ts # RTP validation
├── rtp-diagnostic.test.ts # RTP breakdown by spin type
├── cpp-parity.test.ts # C++ parity tests
└── win-evaluator.test.ts # Win evaluation tests
docs/
├── RTP-MATCHING.md # RTP implementation details
└── TEST-PROTOCOL-RTP-100M.md # 100M spin test protocol
`
`bash`
npm install @omnitronix/happy-panda-game-engine
> Note: This is a private package for Omnitronix internal use only (UNLICENSED).
`typescript
import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
// Initialize game engine
const gameEngine = new HappyPandaV1GameEngine();
// Get engine info
const info = gameEngine.getGameEngineInfo();
// { gameCode: 'happy-panda', version: '1.0.0', rtp: 96.05, gameType: 'slot', gameName: 'Happy Panda', provider: 'Omnitronix' }
// Initialize session
const initCommand = {
id: 'cmd-init-123',
type: 'INIT_SESSION_STATE',
payload: {
gameDirection: 0, // 0 = SINGLE (8 lines), 1 = BOTH (16 lines)
betStake: 1
}
};
const initResult = await gameEngine.processCommand(null, null, initCommand);
// Returns: { success: true, publicState, privateState, outcome, rngOutcome }
// Process spin
const spinCommand = {
id: 'cmd-spin-456',
type: 'SPIN',
payload: {}
};
const spinResult = await gameEngine.processCommand(
initResult.publicState,
initResult.privateState,
spinCommand
);
`
Implements the standard GameEngine interface for integration with game-engine-service.
#### Constructor
`typescript`
new HappyPandaV1GameEngine()
- Initializes game engine with tracked RNG provider
- Ready to process commands immediately
#### Methods
getGameEngineInfo(): GameEngineInfo
Returns game metadata including code, version, RTP, and provider.
`typescript`
{
gameCode: 'happy-panda',
version: '1.0.0',
rtp: 96.05,
gameType: 'slot',
gameName: 'Happy Panda',
provider: 'Omnitronix'
}
processCommand(publicState, privateState, command): Promise
Main command processor that handles all game operations.
The game engine supports 3 different command types:
#### 1. INIT_SESSION_STATE
Purpose: Initialize game session state
Payload:
`typescript`
{
gameDirection?: number; // 0 = SINGLE (8 lines), 1 = BOTH (16 lines). Default: 0
betStake?: number; // Bet multiplier. Default: 1
}
Returns: Initial public and private state with default values
#### 2. SPIN
Purpose: Execute a spin
Payload: None required (uses current state)
Returns: Spin result with grid, wins, and state updates
Result Structure:
`typescript`
{
success: true,
publicState: PublicState,
privateState: PrivateState,
outcome: {
sessionId: string,
grid: Symbol[][], // 3x3 grid
wins: SpinWinResult, // All wins
state: PublicState,
jackpotWon: number, // Jackpot payout (if any)
poolJackpotWon: number, // Pool jackpot payout (if any)
bonusTriggered: SpinType | null,
isBonusComplete: boolean
},
rngOutcome: RngOutcome // Audit trail
}
#### 3. GET_SYMBOLS
Purpose: Retrieve symbol definitions
Payload: None
Returns: Array of symbol definitions with names and values
The engine supports debug commands for QA testing via the dev-tools service. These commands are blocked in REAL_MONEY mode. GLI-19 compliant terminology.
#### DEBUG_TRIGGER_BONUS
Force trigger a specific bonus round for testing.
Payload:
`typescript`
interface DebugTriggerBonusCommand {
sessionId: string;
bonusType: 'BONUS_BAMBOO_TRIPLETS' | 'BONUS_BAMBOO_TWINS' | 'BONUS_CAMERA' | 'BONUS_FIREWORKS' | 'RESPIN_CENTER_BAMBOO';
betAmount: number;
}
Usage:
`typescript`
const result = await engine.processCommand(
publicState,
privateState,
{
id: 'debug-cmd-1',
type: 'DEBUG_TRIGGER_BONUS',
payload: {
sessionId: 'session-123',
bonusType: 'BONUS_BAMBOO_TRIPLETS', // or any other bonus type
betAmount: 8,
},
},
);
Bonus Types (GDD naming):
| Type | Description |
|------|-------------|
| BONUS_BAMBOO_TRIPLETS | Jackpot Bonus - 3-spin bonus with panda pieces grid and progressive jackpot chance |BONUS_BAMBOO_TWINS
| | Bamboo Twins Bonus - Free spins with bamboo respin feature |BONUS_CAMERA
| | Camera Bonus - 5-spin bonus with camera scatter pays + pool jackpot |BONUS_FIREWORKS
| | Fireworks Bonus - 7-spin bonus with hat scatter pays |RESPIN_CENTER_BAMBOO
| | Center Bamboo Respin - 1-2 corner respins when bamboo in center |
Returns: Updated state with bonus pending. Execute SPIN to begin the bonus sequence.
#### PublicState (visible to player)
`typescript`
{
gameDirection: GameDirection; // 0 = SINGLE, 1 = BOTH
betStake: number; // Bet multiplier
betGame: number; // Total bet (8 or 16 x betStake)
currentSpinType: SpinType; // Current spin type
spinsRemaining: number; // Remaining bonus spins
grid: Symbol[][]; // Current 3x3 grid
bonusJackpotValue: number; // Progressive jackpot
poolJackpotValue: number; // Pool jackpot
hasPendingBonus: boolean; // Indicates pending bonus
}
#### PrivateState (server-side only)
`typescript`
{
counters: BonusCounters; // Bonus trigger counters
pendingBonuses: PendingBonuses; // Queued bonuses
nextSpinType: SpinType; // Next spin type
accumulatedBonusWins: number; // Bonus sequence wins
centerBambooSymbol: Symbol | null; // For respin feature
}
#### CommandProcessingResult
`typescript`
{
success: boolean;
publicState: PublicState;
privateState: PrivateState;
outcome?: SpinResponse;
message?: string;
rngOutcome?: RngOutcome; // RNG audit trail
}
| ID | Symbol | Description |
|----|--------|-------------|
| 0 | GOLDEN_PANDA | Golden Red Panda (scatter, doubled payout when solo) |
| 1 | RED_PANDA | Red Panda (scatter) |
| 2 | SLOT_MACHINE | Slot Machine |
| 3 | CITY | City with Fireworks |
| 4 | FIREWORKS_ROCKETS | Fireworks Rockets |
| 5 | BACKPACK | Backpack with Coins |
| 6 | CAMERA | Photo Camera |
| 7 | FOOD_BOWL | Food Bowl |
| 8 | CUP | Colorful Cup |
| 9 | BAMBOO | Green Bamboo |
| 10 | GOLDEN_BAMBOO | Golden Bamboo |
| 11 | HAT | Hat |
#### 1. Line Wins
- 8 paylines (SINGLE mode) or 16 paylines (BOTH mode)
- Evaluated left-to-right and right-to-left in 16-line mode
- Bamboo pays on 1, 2, or 3 matches
- Line shapes follow classic 3x3 patterns
#### 2. Wall Wins (Matrix/Screen Wins)
- Full 3x3 of same symbol
- Special mixed types:
- Bamboo Mix: BAMBOO + GOLDEN_BAMBOO combinations
- Any Bar Mix: FIREWORKS_ROCKETS + CITY + SLOT_MACHINE + HAT
- All Fruits: BACKPACK + CAMERA + FOOD_BOWL + CUP
- All Badges: Mixed badge colors
- Important: Wall wins suppress line wins when active
#### 3. Scatter Wins (Red Panda)
- 2-9 Red Panda symbols anywhere on screen
- Golden Panda only = doubled payout
- Important: Scatter wins suppress line wins when active
#### 4. Special Wins (Bonus modes only)
- Panda Pieces: Count of dancing panda pieces (Bamboo Triplets Bonus)
- Camera Scatter: Camera count anywhere (Camera Bonus)
- Hat Scatter: Hat count anywhere (Fireworks Bonus)
Five distinct bonus types with counter-based triggers (GDD naming):
| Bonus | Trigger | Spins | Description |
|-------|---------|-------|-------------|
| Bamboo Triplets | 3x Bamboo on first 8 lines | 3 | Panda pieces with progressive jackpot chance |
| Bamboo Twins | Bamboo pair counter = 0 | Variable | Bamboo respin feature |
| Camera | Camera triple counter = 0 | 5 | Camera scatter pays + pool jackpot |
| Fireworks | Fireworks triple counter = 0 | 7 | Hat scatter pays |
| Center Bamboo | Lone center bamboo on losing spin | 1-2 | Corner respin feature |
Each bonus has an associated counter that decrements on specific symbol combinations:
- Bamboo Triplets Counter: Decrements on specific patterns, triggers at 0
- Bamboo Twins Counter: Decrements on bamboo pairs, resets to 6 or 9
- Camera Counter: Decrements on camera triples, resets to 3 or 5
- Fireworks Counter: Decrements on fireworks triples, resets to 1
Two jackpot types:
- Progressive Jackpot (bonusJackpotValue): Accumulates on losing paid spins, paid during Bamboo Triplets BonuspoolJackpotValue
- Pool Jackpot (): Accumulates separately, paid when Camera Bonus triggers
`typescript
import { HappyPandaV1GameEngine } from '@omnitronix/happy-panda-game-engine';
class GameSessionService {
private gameEngine: HappyPandaV1GameEngine;
constructor() {
this.gameEngine = new HappyPandaV1GameEngine();
}
async createSession(userId: string, gameDirection: number, betStake: number) {
const initCommand = {
id: init-${userId}-${Date.now()},
type: 'INIT_SESSION_STATE',
payload: { gameDirection, betStake }
};
const result = await this.gameEngine.processCommand(null, null, initCommand);
// Store result.publicState in database (visible to player)
// Store result.privateState securely (server-side only)
// Store result.rngOutcome for audit trail
return {
sessionId: userId,
publicState: result.publicState,
// Never send privateState to client!
};
}
async processSpin(sessionId: string, publicState: any, privateState: any) {
const spinCommand = {
id: spin-${sessionId}-${Date.now()},
type: 'SPIN',
payload: {}
};
const result = await this.gameEngine.processCommand(
publicState,
privateState,
spinCommand
);
// Update states in database
// Log RNG outcome for compliance
// Return outcome to client
return {
outcome: result.outcome,
publicState: result.publicState,
rngOutcome: result.rngOutcome, // For audit
// privateState stays on server
};
}
}
`
`typescript
async handleSpinResult(spinResult: any) {
const { outcome, publicState, privateState } = spinResult;
// Check win types
console.log(Total Payout: ${outcome.wins.totalPayout});Line Wins: ${outcome.wins.lineWins.length}
console.log();Wall Win: ${outcome.wins.wallWin ? 'Yes' : 'No'}
console.log();Scatter Wins: ${outcome.wins.scatterWins.length}
console.log();
// Check for jackpot
if (outcome.jackpotWon > 0) {
console.log(JACKPOT WON: ${outcome.jackpotWon});
}
if (outcome.poolJackpotWon > 0) {
console.log(POOL JACKPOT WON: ${outcome.poolJackpotWon});
}
// Check if bonus was triggered
if (outcome.bonusTriggered) {
return {
type: 'BONUS_TRIGGERED',
bonusType: outcome.bonusTriggered,
spinsRemaining: publicState.spinsRemaining,
message: ${outcome.bonusTriggered} bonus triggered!
};
}
// Check if bonus sequence completed
if (outcome.isBonusComplete) {
return {
type: 'BONUS_COMPLETE',
message: 'Bonus sequence completed'
};
}
return {
type: 'REGULAR_SPIN',
totalPayout: outcome.wins.totalPayout
};
}
`
`typescript
// 8-line mode (SINGLE)
const single8Lines = await gameEngine.processCommand(null, null, {
id: 'init-single',
type: 'INIT_SESSION_STATE',
payload: { gameDirection: 0, betStake: 1 }
});
// Total bet = 8 x betStake = 8
// 16-line mode (BOTH)
const both16Lines = await gameEngine.processCommand(null, null, {
id: 'init-both',
type: 'INIT_SESSION_STATE',
payload: { gameDirection: 1, betStake: 1 }
});
// Total bet = 16 x betStake = 16
`
`bashRun all tests
npm test
$3
`bash
Clean build
npm run clean
npm run buildDevelopment mode
npm run build
`$3
`bash
Check for issues
npm run lintAuto-fix issues
npm run lint -- --fix
`Configuration
Game configuration located in
src/config/happy-panda.config.ts:- Symbol definitions and IDs
- Paytable values for all win types
- Line shapes for 8 and 16 line modes
- Reel strip weights by spin type
- Bonus counter initial values
- Jackpot accumulation rates
All values match the original Excel specification (
CherryMaster_A_2_26.05.2025.xlsx).Type Exports
The package exports all necessary types for TypeScript integration:
`typescript
import {
// V1 Game Engine
HappyPandaV1GameEngine,
GameEngine,
GameEngineInfo,
GameActionCommand,
CommandProcessingResult,
RngOutcome,
RngOutcomeRecord, // Core Engine
HappyPandaEngine,
// Configuration
Symbol,
SpinType,
ScreenWinType,
GRID,
LINE_SHAPES,
LINES_PER_DIRECTION,
// Domain Types
Grid,
Position,
LineWin,
WallWin,
ScatterWin,
SpecialWin,
SpinWinResult,
BonusCounters,
PendingBonuses,
JackpotState,
GameDirection,
GameState,
PublicState,
PrivateState,
SpinRequest,
SpinResponse,
SessionState,
RngProvider,
CommandType,
GameCommand,
// Logic Services
evaluateSpin,
evaluateLineWins,
evaluateWallWin,
evaluateScatterWins,
generateGrid,
} from '@omnitronix/happy-panda-game-engine';
`Key Differences from Traditional Slots
$3
- Traditional Modern: 5+ reels, multiple rows
- Happy Panda: Classic 3x3 grid with bidirectional paylines
- Advantage: Nostalgic gameplay, simpler visual presentation
$3
- 8-Line Mode: Left-to-right only
- 16-Line Mode: Both directions (LTR + RTL)
- Strategic Choice: Player chooses mode based on bet preference
$3
- Screen-filling wins: Full 3x3 of same/related symbols
- Multiple types: Pure, bamboo mix, bar mix, fruits, badges
- Important: Wall wins suppress line wins (no double-counting)
$3
- Not scatter-triggered: Bonuses trigger via counter depletion
- Progressive build-up: Counters decrement on specific symbol combos
- Multiple bonus types: 5 distinct bonus modes with different mechanics
$3
- Progressive Jackpot: Accumulates on losses, paid in Jackpot Bonus
- Pool Jackpot: Separate accumulator, paid with Camera Bonus
- Dual opportunity: Two paths to jackpot wins
Documentation
- Test Protocol:
docs/TEST-PROTOCOL-RTP-100M.md - Complete 100M spin test results
- RTP Matching: docs/RTP-MATCHING.md - Implementation details and tuning history
- C++ Source: math/Happy Red Panda/CherryMaster_A_2.cpp
- Excel Spec: math/Happy Red Panda/CherryMaster_A_2_26.05.2025.xlsxTesting
This engine uses @omnitronix/game-test-utils for comprehensive testing including:
- GLI-19 compliance validation
- RNG security testing
- Statistical RTP simulation
- Symbol distribution analysis
Run tests:
npm test`UNLICENSED - Internal use only for Omnitronix
For questions or issues, contact the Omnitronix development team.