Files
basic1/MultigameRefactorPlan.md
2026-01-30 21:33:42 -05:00

155 lines
5.6 KiB
Markdown

Multigame Migration Plan
Overview
Refactor the existing monolithic tic-tac-toe implementation into a modular game architecture that allows multiple games to run on the RP2350 platform while preserving the interrupt-driven, dual-core reactive architecture.
Goals
Abstract game logic from hardware/display management
Create reusable input processing system
Enable multiple games to coexist in the codebase
Maintain the efficient reactive architecture (event-driven, dual-core)
Keep hardware-specific code isolated in basic1.cpp
Architecture Components
1. Input Event System
Files: lib/input_event.h
Defines shared input event structures used by both InputManager and Game classes:
InputType enum (NONE, TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP, BUTTON_0, BUTTON_1, GESTURE)
InputEvent struct with coordinates, gesture codes, button IDs, pressure, validity flag
2. Input Manager
Files: lib/input_manager.h, lib/input_manager.cpp
Handles all input processing and debouncing:
Constructor: InputManager(LowLevelTouch* touch, GameConfig* config)
Methods: process_touch_input(uint32_t* last_time), process_button_input()
Returns InputEvent objects to be passed to games
Manages touch debouncing and gesture recognition
Does NOT handle button GPIO setup (stays in basic1.cpp)
3. Abstract Game Base Class
Files: lib/game.h
Defines the interface all games must implement:
Constructor: Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
Protected members: width, height, renderer, gui
Pure virtual methods:
virtual void init() = 0 - Initialize game state
virtual bool update(const InputEvent& event) = 0 - Process input, return true if redraw needed
virtual void draw() = 0 - Render game to buffer
Virtual destructor: virtual ~Game() {}
4. Tic-Tac-Toe Game Implementation
Files: games/tic_tac_toe.h, games/tic_tac_toe.cpp
Concrete implementation of the Game interface:
Private GameState struct with board, current player, winner, statistics
Private method: check_winner()
Private constants: BOARD_SIZE, CELL_SIZE, BOARD_Y, LINE_WIDTH
Overrides: init(), update(const InputEvent& event), draw()
Encapsulates all tic-tac-toe logic extracted from basic1.cpp lines 162-770
5. Main Loop Refactor
File: basic1.cpp
Simplified main program focusing on hardware management:
Keep: Display initialization, dual-core setup, interrupt handlers, GPIO configuration
Remove: Game-specific logic (moves to TicTacToeGame)
Add: InputManager instantiation, Game* pointer instantiation
Modify main loop:
Migration Steps
Step 1: Create Input Event Header
Extract input structures from basic1.cpp (lines 134-156) to new file lib/input_event.h.
Validation:
Compile successfully
No duplicate definitions
Both basic1.cpp and new files include this header
Step 2: Create Input Manager
Move input processing functions (lines 313-442) to new InputManager class.
Validation:
Constructor properly stores touch pointer and config
process_touch_input() returns valid InputEvent on touch
process_button_input() returns valid InputEvent on button press
Debouncing still works correctly
Compile and run - verify touch/button detection unchanged
Step 3: Create Abstract Game Class
Create lib/game.h with base class definition.
Validation:
Header compiles successfully
Pure virtual methods defined correctly
Protected members accessible to derived classes
Step 4: Extract Tic-Tac-Toe Game
Create TicTacToeGame class inheriting from Game.
Validation:
Move GameState struct (lines 162-176) - verify all members present
Move check_winner() (lines 447-495) - verify logic identical
Move game_init() to init() override (lines 505-522)
Move game_update() to update() override (lines 536-668)
Move game_draw() to draw() override (lines 671-770)
Move constants: BOARD_SIZE, CELL_SIZE, BOARD_Y
Compile successfully
Step 5: Refactor Main Loop
Update basic1.cpp to use new architecture.
Validation:
Remove old GameState state variable
Remove old game functions
Instantiate InputManager after hardware init
Instantiate TicTacToeGame as Game*
Update main loop to use polymorphic calls
Compile successfully
Run and verify: Touch input works, buttons work, game plays correctly
Verify dual-core refresh still works (Core 1 handles display)
Test full game: place pieces, win conditions, restart
Step 6: Update Build System
Modify CMakeLists.txt to include new source files.
Validation:
Add lib/input_manager.cpp
Add games/tic_tac_toe.cpp
Clean build succeeds
Binary size reasonable (no major bloat)
Step 7: Final Testing
Comprehensive system test.
Validation:
Touch detection works (tap cells)
Button navigation works (KEY0/KEY1)
Game logic correct (wins, ties, restart)
Display refreshes properly (no artifacts)
Statistics persist across games
Debug output shows correct events
System remains responsive during e-ink refresh
Future Extensions
Adding New Games
To add a new game (e.g., Snake, Pong):
Create games/snake.h and games/snake.cpp
Inherit from Game base class
Implement init(), update(), draw()
Define game-specific state as private members
Add to CMakeLists.txt
Change game selection in basic1.cpp: Game* current_game = new SnakeGame(...)
Game Launcher (Future)
Create GameLauncher class to display menu
Allow runtime game switching
Handle cleanup: delete current_game; current_game = new SnakeGame(...)
Store game selection preference in flash
Key Design Principles
Hardware Isolation: All GPIO, interrupts, hardware config stay in basic1.cpp
State Encapsulation: Each game owns its state completely
Polymorphism: Use Game* pointer for runtime flexibility
Event-Driven: Games respond to InputEvent objects only
Reactive Rendering: Only redraw when update() returns true
Dual-Core Efficiency: Core 0 handles logic, Core 1 handles display refresh