5d20e43f-cfcc-4489-bd25-9c8b412f3386
This commit is contained in:
218
POKEMON_TABLE_README.md
Normal file
218
POKEMON_TABLE_README.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user