219 lines
6.4 KiB
Markdown
219 lines
6.4 KiB
Markdown
# 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 directory
|
|
- `loadFromFiles()`: Loads Pokemon data from specific JSON files
|
|
- `getPokemon(uint16_t id)`: O(1) lookup by Pokemon ID
|
|
- `getPokemonByName(std::string_view name)`: O(1) lookup by Pokemon name
|
|
- `hasPokemon(uint16_t id)`: Check if a Pokemon ID exists
|
|
- `size()`: Get the total number of loaded Pokemon
|
|
- `validate()`: 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 name
|
|
- `base_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:
|
|
|
|
```cpp
|
|
#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:
|
|
|
|
1. **Vector storage**: Pokemon species are stored in a `std::vector<PokemonSpecies>` indexed by ID
|
|
2. **Hash map**: Name-to-ID mapping using `std::unordered_map` for fast name lookups
|
|
3. **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
|
|
|
|
```cpp
|
|
#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
|
|
|
|
```cpp
|
|
// 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.json` through `generation-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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
```bash
|
|
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:
|
|
|
|
1. **Lazy loading**: Load Pokemon data on-demand to reduce startup time
|
|
2. **Compressed storage**: Use compression to reduce memory footprint
|
|
3. **Multi-threading**: Parallel loading of Pokemon data
|
|
4. **Caching**: Implement LRU cache for frequently accessed Pokemon
|
|
5. **Serialization**: Save/load compiled Pokemon data for faster startup
|