6.4 KiB
Pokemon Table Implementation
This document describes the high-performance Pokemon data table implementation for the Pokemon Battle Simulator.
Overview
The Pokemon Table is a high-performance data structure that provides O(1) lookup access to all Pokemon species data. It loads Pokemon data from JSON files and stores them in memory for fast runtime access.
Features
- O(1) ID-based lookup: Access any Pokemon by its ID in constant time
- O(1) Name-based lookup: Access any Pokemon by its name using a hash map
- Automatic data loading: Loads all Pokemon data from JSON files at startup
- Memory efficient: Uses contiguous memory storage for optimal cache performance
- Type safety: Strongly typed with comprehensive error handling
- Validation: Built-in data validation to ensure integrity
Architecture
Core Classes
PokemonTable
The main class that manages the Pokemon data table.
Key Methods:
loadFromDataDirectory(): Loads Pokemon data from the standard data directoryloadFromFiles(): Loads Pokemon data from specific JSON filesgetPokemon(uint16_t id): O(1) lookup by Pokemon IDgetPokemonByName(std::string_view name): O(1) lookup by Pokemon namehasPokemon(uint16_t id): Check if a Pokemon ID existssize(): Get the total number of loaded Pokemonvalidate(): Validate the integrity of loaded data
PokemonSpecies
Struct containing all the data for a single Pokemon species.
Fields:
id: Pokemon ID (1-based)name: Pokemon namebase_stats: Base stats (HP, Attack, Defense, SpAttack, SpDefense, Speed)types: Primary and secondary types
Global Access
The implementation provides a global Pokemon table instance for convenient access:
#include "core/pokemon_table.h"
// Initialize the global table (call once at startup)
bool success = PokEng::initializePokemonTable();
// Use the global table
const auto* bulbasaur = PokEng::g_pokemonTable->getPokemon(1);
const auto* charizard = PokEng::g_pokemonTable->getPokemonByName("charizard");
// Clean up (call at shutdown)
PokEng::shutdownPokemonTable();
Performance
Benchmarks
Based on the example program, the Pokemon table demonstrates excellent performance:
- Initialization: ~89ms to load 1025 Pokemon species
- ID Lookups: ~33,333 lookups per millisecond (100,000 lookups in 3ms)
- Memory Usage: Minimal memory footprint with contiguous storage
Storage Strategy
The table uses a hybrid storage approach for optimal performance:
- Vector storage: Pokemon species are stored in a
std::vector<PokemonSpecies>indexed by ID - Hash map: Name-to-ID mapping using
std::unordered_mapfor fast name lookups - Index 0 unused: Vector index 0 is unused, so Pokemon with ID 1 is at index 1
This approach provides:
- O(1) ID lookups via direct vector indexing
- O(1) average case name lookups via hash table
- Excellent cache locality for ID-based access patterns
Usage Examples
Basic Usage
#include "core/pokemon_table.h"
int main() {
// Initialize the Pokemon table
if (!PokEng::initializePokemonTable()) {
std::cerr << "Failed to load Pokemon data!" << std::endl;
return 1;
}
// Look up Pokemon by ID
const auto* pikachu = PokEng::g_pokemonTable->getPokemon(25);
if (pikachu) {
std::cout << "Pikachu's speed: " << pikachu->base_stats.speed << std::endl;
std::cout << "Pikachu's type: " << PokEng::TypeUtils::typeToString(pikachu->types.getPrimary()) << std::endl;
}
// Look up Pokemon by name
const auto* charizard = PokEng::g_pokemonTable->getPokemonByName("charizard");
if (charizard) {
std::cout << "Charizard ID: " << charizard->id << std::endl;
}
// Clean up
PokEng::shutdownPokemonTable();
return 0;
}
Advanced Usage
// Check if Pokemon exists
if (PokEng::g_pokemonTable->hasPokemon(150)) {
const auto* mewtwo = PokEng::g_pokemonTable->getPokemon(150);
// Use mewtwo data...
}
// Iterate through all Pokemon
for (uint16_t id = 1; id <= PokEng::g_pokemonTable->getMaxId(); ++id) {
const auto* pokemon = PokEng::g_pokemonTable->getPokemon(id);
if (pokemon) {
// Process pokemon...
}
}
// Get all Pokemon at once (for bulk operations)
const auto& allPokemon = PokEng::g_pokemonTable->getAllPokemon();
for (const auto& pokemon : allPokemon) {
if (pokemon.id != 0) { // Skip empty entries
// Process pokemon...
}
}
Data Loading
The Pokemon table automatically loads data from JSON files in the data/pokemon/ directory:
generation-i.jsonthroughgeneration-ix.json- Each file contains Pokemon from a specific generation
- Data is validated during loading
JSON Format
Each Pokemon entry in the JSON files has the following structure:
{
"id": 1,
"name": "bulbasaur",
"height": 7,
"weight": 69,
"base_experience": 64,
"types": ["grass", "poison"],
"stats": {
"hp": 45,
"attack": 49,
"defense": 49,
"special-attack": 65,
"special-defense": 65,
"speed": 45
},
"abilities": [...],
"species": {...}
}
Error Handling
The implementation includes comprehensive error handling:
- File loading errors: Graceful handling of missing or corrupted JSON files
- JSON parsing errors: Detailed error messages for malformed JSON
- Data validation: Built-in validation to ensure data integrity
- Memory safety: Proper resource management with RAII
Testing
The implementation includes comprehensive unit tests covering:
- Data loading and initialization
- ID-based and name-based lookups
- Error handling for invalid inputs
- Performance validation
- Data integrity validation
Run tests with:
cd build
make test
Integration
The Pokemon table is designed to integrate seamlessly with other components:
- Pokemon creation: Use table data to create Pokemon instances
- Battle calculations: Fast access to base stats and types
- Type effectiveness: Integration with type system for damage calculations
- Stat calculations: Base stats for battle stat computations
Future Enhancements
Potential improvements for the Pokemon table:
- Lazy loading: Load Pokemon data on-demand to reduce startup time
- Compressed storage: Use compression to reduce memory footprint
- Multi-threading: Parallel loading of Pokemon data
- Caching: Implement LRU cache for frequently accessed Pokemon
- Serialization: Save/load compiled Pokemon data for faster startup