codebase refactor

This commit is contained in:
cdemeyer-teachx
2025-08-15 12:38:44 +09:00
parent bbfe64b604
commit ee337f001a
27 changed files with 396 additions and 591 deletions

View File

@@ -30,11 +30,11 @@ target_link_libraries(pokemon_battle_sim
)
# Create an alias for consistency
add_library(PokemonSim::pokemon_battle_sim ALIAS pokemon_battle_sim)
add_library(PokEng::pokemon_battle_sim ALIAS pokemon_battle_sim)
# Export the target
install(TARGETS pokemon_battle_sim
EXPORT PokemonSimTargets
EXPORT PokEngTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}

View File

@@ -1,38 +0,0 @@
# Source Directory (`src/`)
This directory contains all C++ source files (.cpp) for the Pokemon battle simulator.
## Planned Structure
```
src/
├── core/ # Core battle engine
│ ├── battle.cpp # Main battle logic
│ ├── pokemon.cpp # Pokemon class implementation
│ ├── move.cpp # Move system
│ └── type.cpp # Type effectiveness
├── data/ # Data loading and management
│ ├── loader.cpp # Data file loading
│ └── validator.cpp # Data validation
├── ai/ # AI battle strategies
│ ├── random_ai.cpp # Random move selection
│ └── minimax_ai.cpp # Minimax algorithm
├── utils/ # Utility functions
│ ├── random.cpp # Random number generation
│ └── stats.cpp # Stat calculations
└── main.cpp # Entry point (if building executable)
```
## Design Principles
- **Performance First**: Optimized for speed and memory efficiency
- **Modular Design**: Clear separation of concerns
- **Data-Driven**: Pokemon data loaded from external files
- **Testable**: Each component designed for unit testing
## Key Components
- **Battle Engine**: Core simulation logic
- **Pokemon System**: Stats, types, moves, status effects
- **AI Framework**: Pluggable AI strategies
- **Data Management**: Efficient loading and caching

View File

@@ -1,4 +1,4 @@
#include "types.h"
#include "pokemon_battle_sim.h"
#include "../thirdParty/rapidjson/document.h"
#include "../thirdParty/rapidjson/filereadstream.h"
#include <cstdio>
@@ -6,18 +6,18 @@
#include <algorithm>
#include <cctype>
namespace PokemonSim {
namespace PokEng {
// Static type chart storage initialization
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_1>::CHART_SIZE> TypeUtils::s_gen1Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_2>::CHART_SIZE> TypeUtils::s_gen2Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_3>::CHART_SIZE> TypeUtils::s_gen3Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_4>::CHART_SIZE> TypeUtils::s_gen4Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_5>::CHART_SIZE> TypeUtils::s_gen5Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_6>::CHART_SIZE> TypeUtils::s_gen6Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_7>::CHART_SIZE> TypeUtils::s_gen7Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_8>::CHART_SIZE> TypeUtils::s_gen8Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_9>::CHART_SIZE> TypeUtils::s_gen9Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE> TypeUtils::s_gen1Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE> TypeUtils::s_gen2Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE> TypeUtils::s_gen3Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE> TypeUtils::s_gen4Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE> TypeUtils::s_gen5Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE> TypeUtils::s_gen6Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE> TypeUtils::s_gen7Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE> TypeUtils::s_gen8Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE> TypeUtils::s_gen9Chart;
// String to type mapping
static const std::unordered_map<std::string_view, Type> s_stringToTypeMap = {
@@ -148,25 +148,25 @@ uint32_t TypeUtils::calculateDamageMultiplier(Type attackType, const PokemonType
}
// Explicit template instantiations for all generations
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_2>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_3>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_4>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_5>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_6>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_7>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_8>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::GENERATION_9>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::I>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::II>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::III>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::IV>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::V>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VI>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VII>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VIII>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::IX>(Type, Type);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_2>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_3>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_4>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_5>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_6>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_7>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_8>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::GENERATION_9>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::I>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::II>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::III>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::IV>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::V>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VI>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VII>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VIII>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::IX>(Type, const PokemonTypes&);
// Convert float damage factor to TypeMultiplier
static TypeMultiplier floatToTypeMultiplier(double factor) {
@@ -199,23 +199,23 @@ bool TypeUtils::loadTypeChartFromFile(const std::string& filename) {
// Initialize the chart with neutral values
// Note: We access the static members directly since getTypeChart() returns const reference
if constexpr (Gen == Generation::GENERATION_1) {
if constexpr (Gen == Generation::I) {
std::fill(TypeUtils::s_gen1Chart.begin(), TypeUtils::s_gen1Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_2) {
} else if constexpr (Gen == Generation::II) {
std::fill(TypeUtils::s_gen2Chart.begin(), TypeUtils::s_gen2Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_3) {
} else if constexpr (Gen == Generation::III) {
std::fill(TypeUtils::s_gen3Chart.begin(), TypeUtils::s_gen3Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_4) {
} else if constexpr (Gen == Generation::IV) {
std::fill(TypeUtils::s_gen4Chart.begin(), TypeUtils::s_gen4Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_5) {
} else if constexpr (Gen == Generation::V) {
std::fill(TypeUtils::s_gen5Chart.begin(), TypeUtils::s_gen5Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_6) {
} else if constexpr (Gen == Generation::VI) {
std::fill(TypeUtils::s_gen6Chart.begin(), TypeUtils::s_gen6Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_7) {
} else if constexpr (Gen == Generation::VII) {
std::fill(TypeUtils::s_gen7Chart.begin(), TypeUtils::s_gen7Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_8) {
} else if constexpr (Gen == Generation::VIII) {
std::fill(TypeUtils::s_gen8Chart.begin(), TypeUtils::s_gen8Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::GENERATION_9) {
} else if constexpr (Gen == Generation::IX) {
std::fill(TypeUtils::s_gen9Chart.begin(), TypeUtils::s_gen9Chart.end(), TypeMultiplier::NEUTRAL);
}
@@ -250,23 +250,23 @@ bool TypeUtils::loadTypeChartFromFile(const std::string& filename) {
if (index < chartSize) {
// Direct assignment to static members
if constexpr (Gen == Generation::GENERATION_1) {
if constexpr (Gen == Generation::I) {
TypeUtils::s_gen1Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_2) {
} else if constexpr (Gen == Generation::II) {
TypeUtils::s_gen2Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_3) {
} else if constexpr (Gen == Generation::III) {
TypeUtils::s_gen3Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_4) {
} else if constexpr (Gen == Generation::IV) {
TypeUtils::s_gen4Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_5) {
} else if constexpr (Gen == Generation::V) {
TypeUtils::s_gen5Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_6) {
} else if constexpr (Gen == Generation::VI) {
TypeUtils::s_gen6Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_7) {
} else if constexpr (Gen == Generation::VII) {
TypeUtils::s_gen7Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_8) {
} else if constexpr (Gen == Generation::VIII) {
TypeUtils::s_gen8Chart[index] = multiplier;
} else if constexpr (Gen == Generation::GENERATION_9) {
} else if constexpr (Gen == Generation::IX) {
TypeUtils::s_gen9Chart[index] = multiplier;
}
}
@@ -276,33 +276,33 @@ bool TypeUtils::loadTypeChartFromFile(const std::string& filename) {
}
// Explicit template instantiations for loading
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_1>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_2>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_3>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_4>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_5>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_6>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_7>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_8>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::GENERATION_9>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::I>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::II>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::III>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::IV>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::V>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VI>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VII>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VIII>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::IX>(const std::string&);
// Initialize type charts on startup
struct TypeChartInitializer {
TypeChartInitializer() {
// Load type charts for each generation
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_1>("data/type_effectiveness_generation-i.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_2>("data/type_effectiveness_generation-ii.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_3>("data/type_effectiveness_generation-iii.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_4>("data/type_effectiveness_generation-iv.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_5>("data/type_effectiveness_generation-v.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_6>("data/type_effectiveness_generation-vi.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_7>("data/type_effectiveness_generation-vii.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_8>("data/type_effectiveness_generation-viii.json");
TypeUtils::loadTypeChartFromFile<Generation::GENERATION_9>("data/type_effectiveness_generation-ix.json");
TypeUtils::loadTypeChartFromFile<Generation::I>("../data/type_effectiveness_generation-i.json");
TypeUtils::loadTypeChartFromFile<Generation::II>("../data/type_effectiveness_generation-ii.json");
TypeUtils::loadTypeChartFromFile<Generation::III>("../data/type_effectiveness_generation-iii.json");
TypeUtils::loadTypeChartFromFile<Generation::IV>("../data/type_effectiveness_generation-iv.json");
TypeUtils::loadTypeChartFromFile<Generation::V>("../data/type_effectiveness_generation-v.json");
TypeUtils::loadTypeChartFromFile<Generation::VI>("../data/type_effectiveness_generation-vi.json");
TypeUtils::loadTypeChartFromFile<Generation::VII>("../data/type_effectiveness_generation-vii.json");
TypeUtils::loadTypeChartFromFile<Generation::VIII>("../data/type_effectiveness_generation-viii.json");
TypeUtils::loadTypeChartFromFile<Generation::IX>("../data/type_effectiveness_generation-ix.json");
}
};
// Static initializer to load type charts at program startup
static TypeChartInitializer s_initializer;
} // namespace PokemonSim
} // namespace PokEng

View File

@@ -1,89 +0,0 @@
// Pokemon Battle Engine Implementation with Type System
// High-performance implementation with full type support
#include "pokemon_battle_sim.h"
#include <string>
#include <iostream>
#include <algorithm>
namespace PokemonSim {
// Pokemon class method implementations
Pokemon::Pokemon(const std::string& name, int health)
: name_(name), health_(health), types_(Type::NORMAL) {}
Pokemon::Pokemon(const std::string& name, int health, Type primaryType)
: name_(name), health_(health), types_(primaryType) {}
Pokemon::Pokemon(const std::string& name, int health, Type primaryType, Type secondaryType)
: name_(name), health_(health), types_(primaryType, secondaryType) {}
std::string Pokemon::getName() const {
return name_;
}
int Pokemon::getHealth() const {
return health_;
}
const PokemonTypes& Pokemon::getTypes() const {
return types_;
}
void Pokemon::setHealth(int health) {
health_ = health;
}
void Pokemon::setTypes(Type primary) {
types_.setPrimary(primary);
types_.setSecondary(Type::NONE);
}
void Pokemon::setTypes(Type primary, Type secondary) {
types_.setPrimary(primary);
types_.setSecondary(secondary);
}
// Enhanced battle function with type system
bool simulateBattle(Pokemon& pokemon1, Pokemon& pokemon2) {
const int maxTurns = 1000; // Prevent infinite battles
int turn = 0;
// Simple type-based damage calculation for demonstration
auto calculateAttackDamage = [](const Pokemon& attacker, const Pokemon& defender) -> uint32_t {
// Use a basic type matchup for now (can be expanded with move types)
Type attackType = attacker.getTypes().getPrimary();
const auto& defenderTypes = defender.getTypes();
// Calculate type multiplier and apply base damage
uint32_t baseDamage = 20; // Base attack damage
uint32_t typeDamage = calculateTypeDamage(baseDamage, attackType, defenderTypes);
// Add some randomness (±10%)
uint32_t variance = typeDamage / 10;
return typeDamage + (variance > 0 ? variance : 1);
};
while (pokemon1.getHealth() > 0 && pokemon2.getHealth() > 0 && turn < maxTurns) {
// Pokemon 1 attacks Pokemon 2
uint32_t damage1 = calculateAttackDamage(pokemon1, pokemon2);
int newHealth2 = pokemon2.getHealth() - static_cast<int>(damage1);
pokemon2.setHealth(std::max(0, newHealth2));
if (pokemon2.getHealth() <= 0) {
return true; // Pokemon 1 wins
}
// Pokemon 2 attacks Pokemon 1
uint32_t damage2 = calculateAttackDamage(pokemon2, pokemon1);
int newHealth1 = pokemon1.getHealth() - static_cast<int>(damage2);
pokemon1.setHealth(std::max(0, newHealth1));
turn++;
}
// If we hit max turns, the Pokemon with more health wins
return pokemon1.getHealth() > pokemon2.getHealth();
}
} // namespace PokemonSim