# Hardcoded Magic Numbers Analysis Report ## Overview This report identifies hardcoded magic numbers in the Loveca card game engine (Rust codebase) that could be converted to enums for better code maintainability and type safety. ## Summary of Findings The analysis found **numerous hardcoded magic numbers** across multiple files that are candidates for enum conversion. The codebase already has a good foundation with `core/enums.rs` and `core/generated_constants.rs`, but many game-specific constants remain scattered as magic numbers. --- ## Candidate Magic Numbers for Enum Conversion ### 1. Stage Slot Constants **Current State:** Hardcoded `3` used throughout the codebase for stage slots. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/rules.rs`](engine_rust_src/src/core/logic/rules.rs) - [`engine_rust_src/src/core/logic/game.rs`](engine_rust_src/src/core/logic/game.rs) - [`engine_rust_src/src/core/logic/player.rs`](engine_rust_src/src/core/logic/player.rs) - [`engine_rust_src/src/core/logic/performance.rs`](engine_rust_src/src/core/logic/performance.rs) - [`engine_rust_src/src/core/logic/interpreter/handlers/state.rs`](engine_rust_src/src/core/logic/interpreter/handlers/state.rs) **Examples:** ```rust // Current usage for slot in 0..3 { ... } if slot_idx >= 0 && slot_idx < 3 { ... } stage: [i32; 3], // In player.rs ``` **Recommended Enum:** ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum StageSlot { Left = 0, Center = 1, Right = 2, } impl StageSlot { pub const COUNT: usize = 3; pub fn all() -> impl Iterator { ... } } ``` --- ### 2. Color Constants (Card Colors) **Current State:** Colors 0-6 used extensively with magic numbers like `color < 7`, `color == 7` (wildcard). **Files with magic numbers:** - [`engine_rust_src/src/core/logic/rules.rs`](engine_rust_src/src/core/logic/rules.rs) (lines 251-256, 301-306) - [`engine_rust_src/src/core/logic/performance.rs`](engine_rust_src/src/core/logic/performance.rs) (lines 85-133) - [`engine_rust_src/src/core/logic/hearts.rs`](engine_rust_src/src/core/hearts.rs) - [`engine_rust_src/src/core/logic/interpreter/handlers/state.rs`](engine_rust_src/src/core/logic/interpreter/handlers/state.rs) (lines 976-1025) **Examples:** ```rust if color < 7 { ... } if color == 7 { color = ctx.selected_color as usize; } // attr 1-7 = colors 0-6. attr 0 = Generic/Any (index 6). let idx = if attr == 0 || attr == 7 { 6 } else if attr <= 6 { attr - 1 } else { 99 }; ``` **Recommended Enum:** ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[repr(u8)] pub enum Color { #[default] Smile = 0, // Red Pure = 1, // Green Cool = 2, // Blue Active = 3, Natural = 4, Elegant = 5, All = 6, // Wildcard/Any color } impl Color { pub const COUNT: usize = 7; pub fn is_valid(idx: usize) -> bool { idx < Self::COUNT } } ``` --- ### 3. Choice Index Constants **Current State:** Special choice indices like `99` (Done/Cancel) and `999` (All) used throughout. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/constants.rs`](engine_rust_src/src/core/logic/constants.rs) (lines 56-59) - [`engine_rust_src/src/core/logic/interpreter/handlers/state.rs`](engine_rust_src/src/core/logic/interpreter/handlers/state.rs) (lines 76, 89, 366, 474, etc.) - [`engine_rust_src/src/core/logic/interpreter/handlers/flow.rs`](engine_rust_src/src/core/logic/interpreter/handlers/flow.rs) **Examples:** ```rust pub const CHOICE_DONE: i16 = 99; pub const CHOICE_ALL: i16 = 999; // Usage if ctx.choice_index == 99 { ... } ``` **Recommendation:** These are already defined in `constants.rs` as `CHOICE_DONE` and `CHOICE_ALL`. Consider converting to an enum for stronger typing. --- ### 4. Depth Limits (Recursion Guards) **Current State:** Magic numbers `5`, `10` used for recursion depth limits. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/rules.rs`](engine_rust_src/src/core/logic/rules.rs) (lines 35, 183, 359) - [`engine_rust_src/src/core/logic/interpreter/conditions.rs`](engine_rust_src/src/core/logic/interpreter/conditions.rs) (line 42) **Examples:** ```rust if depth > 5 { return 0; } if depth > 10 { return false; } ``` **Recommended Enum:** ```rust #[derive(Debug, Clone, Copy)] pub enum RecursionDepth { BladeCalculation = 5, ConditionCheck = 10, Interpreter = 8, // MAX_DEPTH in interpreter/mod.rs } ``` --- ### 5. Action ID Base Ranges **Current State:** Already partially defined in `generated_constants.rs` but some ranges used directly as magic numbers. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/action_factory.rs`](engine_rust_src/src/core/logic/action_factory.rs) - [`engine_rust_src/src/core/logic/handlers.rs`](engine_rust_src/src/core/logic/handlers.rs) **Examples:** ```rust // Already defined but used directly ACTION_BASE_HAND + (h_idx as i32) * 10 + (slot as i32) action >= 600 && action <= 602 // Live slot selection action >= 100 && action < 200 // Discard index action >= 200 && action < 300 // Hand index ``` **Recommendation:** The constants in `generated_constants.rs` are good. Ensure all code uses these constants instead of magic numbers. --- ### 6. Interpreter Limits **Current State:** Magic numbers for interpreter step limits. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/interpreter/mod.rs`](engine_rust_src/src/core/logic/interpreter/mod.rs) (lines 41-42, 95-98) **Examples:** ```rust pub const MAX_DEPTH: usize = 8; pub const MAX_BYTECODE_LOG_SIZE: usize = 500; if executor.steps >= 1000 { println!("[ERROR] Interpreter infinite loop detected (1000 steps)"); } ``` **Recommendation:** Already well-defined. Consider adding `MAX_INTERPRETER_STEPS = 1000` to constants. --- ### 7. Target Slot Encoding **Current State:** Magic numbers for special slot values like `0`, `4`, `10`, `-1`. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/interpreter/suspension.rs`](engine_rust_src/src/core/logic/interpreter/suspension.rs) (lines 116-131) - [`engine_rust_src/src/core/logic/rules.rs`](engine_rust_src/src/core/logic/rules.rs) (lines 87-93, 232-238) **Examples:** ```rust // From suspension.rs pub fn resolve_target_slot(target_slot: i32, ctx: &AbilityContext) -> usize { if target_slot == 0 && ctx.target_slot >= 0 { return ctx.target_slot as usize; } if target_slot == 4 && ctx.area_idx >= 0 { ctx.area_idx as usize } else if target_slot == -1 || target_slot == 4 { // Fallback to 0 } } // From rules.rs - target area encoding let target_area = s & 0xFF; if target_area == 1 { targets_us = true; } else if (target_area == 4 || target_area == 0) && other_slot == slot_idx { ... } else if target_area == 10 && slot_idx as i16 == ctx.target_slot { ... } ``` **Recommended Enum:** ```rust #[derive(Debug, Clone, Copy)] pub enum TargetSlot { ThisSlot = 0, AllSlots = 1, OpponentSlot = 2, AreaIndex = 4, // Use context.area_idx TargetSlot = 10, // Use context.target_slot None = -1, } ``` --- ### 8. Card Type Values **Current State:** Magic numbers `1` (Member), `2` (Live) used in filter checks. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/filter.rs`](engine_rust_src/src/core/logic/filter.rs) (lines 116-127) **Examples:** ```rust if self.card_type == 1 { // Member if !db.members.contains_key(&cid) { return false; } } else if self.card_type == 2 { // Live if !db.lives.contains_key(&cid) { return false; } } ``` **Recommendation:** These should use the existing `TargetType` enum or create a `CardType` enum. --- ### 9. Zone Values **Current State:** Magic numbers for zones like `6` (Hand), `7` (Discard), `4` (Stage), etc. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/interpreter/handlers/movement.rs`](engine_rust_src/src/core/logic/interpreter/handlers/movement.rs) - [`engine_rust_src/src/core/logic/interpreter/conditions.rs`](engine_rust_src/src/core/logic/interpreter/conditions.rs) **Examples:** ```rust // Zone encoding source_zone == 6 || source_zone == 7 // Hand or Discard source_zone == 15 // Yell if dest_slot == 6 { ... } // Hand else if dest_slot == 7 { ... } // Discard ``` **Recommendation:** The `Zone` enum already exists in `enums.rs`. Ensure all code uses it instead of magic numbers. --- ### 10. RPS (Rock-Paper-Scissors) Values **Current State:** Magic numbers `0`, `1`, `2` for RPS choices. **Files with magic numbers:** - [`engine_rust_src/src/core/logic/handlers.rs`](engine_rust_src/src/core/logic/handlers.rs) - [`engine_rust_src/src/core/logic/game.rs`](engine_rust_src/src/core/logic/game.rs) **Examples:** ```rust let p0_wins = (p0 == 0 && p1 == 2) || (p0 == 1 && p1 == 0) || (p0 == 2 && p1 == 1); ``` **Recommended Enum:** ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum RpsChoice { Rock = 0, Paper = 1, Scissors = 2, } ``` --- ### 11. Special Card ID Values **Current State:** Magic numbers like `-1` (empty/no card), special card IDs. **Files with magic numbers:** - Multiple files **Examples:** ```rust if cid == -1 { return false; } stage[slot] = -1; // Clear slot ``` **Recommendation:** Define constants for special card IDs: ```rust pub const NO_CARD_ID: i32 = -1; pub const INVALID_CARD_ID: i32 = 0; ``` --- ## Priority Recommendations ### High Priority (Most Impactful) 1. **StageSlot Enum** - Used in 50+ locations 2. **Color Enum** - Central to game mechanics, heart/blade system 3. **Recursion Depth Constants** - Safety-critical ### Medium Priority 4. **TargetSlot Encoding** - Used in interpreter extensively 5. **Card Type Filter Values** - Used in filtering logic 6. **Zone Constants** - Ensure consistent usage with existing enum ### Low Priority (Nice to Have) 7. **RPS Choice Enum** - Limited usage 8. **Special Choice Indices** - Already partially defined --- ## Implementation Strategy 1. **Create new enum definitions** in `core/enums.rs` or a new `core/logic/game_enums.rs` 2. **Add constants** for special values in `core/logic/constants.rs` 3. **Systematically replace magic numbers** with enum variants or constants 4. **Add tests** to verify behavior matches previous magic number behavior 5. **Update documentation** to reflect the new type-safe constants --- ## Existing Good Patterns The codebase already has good patterns in place: - `Phase` enum in [`core/enums.rs`](engine_rust_src/src/core/enums.rs) - `Zone` enum in [`core/enums.rs`](engine_rust_src/src/core/enums.rs) - `TriggerType`, `EffectType`, `ConditionType` enums - `generated_constants.rs` for opcode and action ID bases - `constants.rs` for interpreter constants The task is to extend this pattern to the remaining magic numbers found in this analysis.