codebase refactor
This commit is contained in:
@@ -78,31 +78,31 @@ install(DIRECTORY include/
|
||||
)
|
||||
|
||||
# Export targets
|
||||
install(EXPORT PokemonSimTargets
|
||||
FILE PokemonSimTargets.cmake
|
||||
NAMESPACE PokemonSim::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokemonSim
|
||||
install(EXPORT PokEngTargets
|
||||
FILE PokEngTargets.cmake
|
||||
NAMESPACE PokEng::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokEng
|
||||
)
|
||||
|
||||
# Generate and install config files
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
PokemonSimConfigVersion.cmake
|
||||
PokEngConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/PokemonSimConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokemonSimConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokemonSim
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/PokEngConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokEngConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokEng
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokemonSimConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokemonSimConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokemonSim
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokEngConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PokEngConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/PokEng
|
||||
)
|
||||
|
||||
# CPack configuration for packaging
|
||||
|
||||
@@ -39,6 +39,9 @@ A high-performance C++ library for simulating Pokemon battles from Generation 1
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
```
|
||||
|
||||
## Development Tools
|
||||
|
||||
@@ -45,7 +45,7 @@ target_link_libraries(benchmarks
|
||||
PRIVATE
|
||||
benchmark::benchmark
|
||||
benchmark::benchmark_main
|
||||
PokemonSim::pokemon_battle_sim
|
||||
PokEng::pokemon_battle_sim
|
||||
)
|
||||
|
||||
# Include directories
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
// Benchmark for battle simulation performance
|
||||
static void BM_BattleSimulation(benchmark::State& state) {
|
||||
// Set up Pokemon for the benchmark
|
||||
PokemonSim::Pokemon pikachu("Pikachu", 100);
|
||||
PokemonSim::Pokemon charizard("Charizard", 150);
|
||||
PokEng::Pokemon pikachu("Pikachu", 100);
|
||||
PokEng::Pokemon charizard("Charizard", 150);
|
||||
|
||||
// Run the benchmark
|
||||
for (auto _ : state) {
|
||||
// Simulate a battle between the two Pokemon
|
||||
PokemonSim::simulateBattle(pikachu, charizard);
|
||||
PokEng::simulateBattle(pikachu, charizard);
|
||||
|
||||
// Reset health for next iteration
|
||||
pikachu.setHealth(100);
|
||||
@@ -28,11 +28,11 @@ BENCHMARK(BM_BattleSimulation)
|
||||
static void BM_BattleSimulationWithHealth(benchmark::State& state) {
|
||||
int health = static_cast<int>(state.range(0));
|
||||
|
||||
PokemonSim::Pokemon pokemon1("Pokemon1", health);
|
||||
PokemonSim::Pokemon pokemon2("Pokemon2", health);
|
||||
PokEng::Pokemon pokemon1("Pokemon1", health);
|
||||
PokEng::Pokemon pokemon2("Pokemon2", health);
|
||||
|
||||
for (auto _ : state) {
|
||||
PokemonSim::simulateBattle(pokemon1, pokemon2);
|
||||
PokEng::simulateBattle(pokemon1, pokemon2);
|
||||
|
||||
// Reset health
|
||||
pokemon1.setHealth(health);
|
||||
@@ -51,8 +51,8 @@ BENCHMARK(BM_BattleSimulationWithHealth)
|
||||
static void BM_MultipleBattles(benchmark::State& state) {
|
||||
int numBattles = static_cast<int>(state.range(0));
|
||||
|
||||
std::vector<PokemonSim::Pokemon> team1;
|
||||
std::vector<PokemonSim::Pokemon> team2;
|
||||
std::vector<PokEng::Pokemon> team1;
|
||||
std::vector<PokEng::Pokemon> team2;
|
||||
|
||||
// Create teams of Pokemon
|
||||
for (int i = 0; i < numBattles; ++i) {
|
||||
@@ -63,7 +63,7 @@ static void BM_MultipleBattles(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// Simulate multiple battles
|
||||
for (int i = 0; i < numBattles; ++i) {
|
||||
PokemonSim::simulateBattle(team1[static_cast<size_t>(i)], team2[static_cast<size_t>(i)]);
|
||||
PokEng::simulateBattle(team1[static_cast<size_t>(i)], team2[static_cast<size_t>(i)]);
|
||||
}
|
||||
|
||||
// Reset all Pokemon health
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
static void BM_PokemonCreation(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// Create a Pokemon - this is what we're measuring
|
||||
PokemonSim::Pokemon pokemon("Pikachu", 100);
|
||||
PokEng::Pokemon pokemon("Pikachu", 100);
|
||||
|
||||
// Prevent compiler optimization from eliminating the Pokemon
|
||||
benchmark::DoNotOptimize(pokemon);
|
||||
@@ -25,7 +25,7 @@ static void BM_PokemonCreationParameterized(benchmark::State& state) {
|
||||
int health = static_cast<int>(state.range(1));
|
||||
|
||||
for (auto _ : state) {
|
||||
PokemonSim::Pokemon pokemon(name, health);
|
||||
PokEng::Pokemon pokemon(name, health);
|
||||
benchmark::DoNotOptimize(pokemon);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ static void BM_BulkPokemonCreation(benchmark::State& state) {
|
||||
int numPokemon = static_cast<int>(state.range(0));
|
||||
|
||||
for (auto _ : state) {
|
||||
std::vector<PokemonSim::Pokemon> pokemonList;
|
||||
std::vector<PokEng::Pokemon> pokemonList;
|
||||
|
||||
// Create multiple Pokemon
|
||||
for (int i = 0; i < numPokemon; ++i) {
|
||||
@@ -61,7 +61,7 @@ BENCHMARK(BM_BulkPokemonCreation)
|
||||
|
||||
// Benchmark for Pokemon health modifications
|
||||
static void BM_PokemonHealthOperations(benchmark::State& state) {
|
||||
PokemonSim::Pokemon pokemon("TestPokemon", 100);
|
||||
PokEng::Pokemon pokemon("TestPokemon", 100);
|
||||
|
||||
for (auto _ : state) {
|
||||
// Perform various health operations
|
||||
@@ -84,8 +84,8 @@ class PokemonFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const benchmark::State& /*state*/) override {
|
||||
// Set up Pokemon for each benchmark iteration
|
||||
pokemon1 = std::make_unique<PokemonSim::Pokemon>("Pikachu", 100);
|
||||
pokemon2 = std::make_unique<PokemonSim::Pokemon>("Charizard", 150);
|
||||
pokemon1 = std::make_unique<PokEng::Pokemon>("Pikachu", 100);
|
||||
pokemon2 = std::make_unique<PokEng::Pokemon>("Charizard", 150);
|
||||
}
|
||||
|
||||
void TearDown(const benchmark::State& /*state*/) override {
|
||||
@@ -95,14 +95,14 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<PokemonSim::Pokemon> pokemon1;
|
||||
std::unique_ptr<PokemonSim::Pokemon> pokemon2;
|
||||
std::unique_ptr<PokEng::Pokemon> pokemon1;
|
||||
std::unique_ptr<PokEng::Pokemon> pokemon2;
|
||||
};
|
||||
|
||||
// Benchmark using fixture
|
||||
BENCHMARK_F(PokemonFixture, BM_BattleWithFixture)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
PokemonSim::simulateBattle(*pokemon1, *pokemon2);
|
||||
PokEng::simulateBattle(*pokemon1, *pokemon2);
|
||||
|
||||
// Reset health
|
||||
pokemon1->setHealth(100);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
namespace PokemonSim {
|
||||
namespace PokEng {
|
||||
|
||||
// Benchmark fixture for type system
|
||||
class TypeSystemBenchmark : public benchmark::Fixture {
|
||||
@@ -87,7 +87,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_TypeEffectivenessLookup)(benchmark::State& s
|
||||
for (auto _ : state) {
|
||||
for (size_t i = 0; i < attackTypes.size(); ++i) {
|
||||
for (size_t j = 0; j < attackTypes.size(); ++j) {
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::I>(
|
||||
attackTypes[i % attackTypes.size()],
|
||||
attackTypes[j % attackTypes.size()]
|
||||
);
|
||||
@@ -101,7 +101,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_TypeEffectivenessLookupGen8)(benchmark::Stat
|
||||
for (auto _ : state) {
|
||||
for (size_t i = 0; i < attackTypes.size(); ++i) {
|
||||
for (size_t j = 0; j < attackTypes.size(); ++j) {
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::GENERATION_8>(
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::VIII>(
|
||||
attackTypes[i % attackTypes.size()],
|
||||
attackTypes[j % attackTypes.size()]
|
||||
);
|
||||
@@ -116,7 +116,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_DamageMultiplierSingleType)(benchmark::State
|
||||
for (auto _ : state) {
|
||||
for (const auto& pokemon : singleTypePokemon) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(attackType, pokemon);
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::I>(attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_DamageMultiplierDualType)(benchmark::State&
|
||||
for (auto _ : state) {
|
||||
for (const auto& pokemon : dualTypePokemon) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(attackType, pokemon);
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::I>(attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_CalculateDamage)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
for (const auto& pokemon : singleTypePokemon) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = calculateDamage<Generation::GENERATION_1>(baseDamage, attackType, pokemon);
|
||||
auto result = calculateDamage<Generation::I>(baseDamage, attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_CalculateDamageDualType)(benchmark::State& s
|
||||
for (auto _ : state) {
|
||||
for (const auto& pokemon : dualTypePokemon) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = calculateDamage<Generation::GENERATION_1>(baseDamage, attackType, pokemon);
|
||||
auto result = calculateDamage<Generation::I>(baseDamage, attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_Generation1DamageCalc)(benchmark::State& sta
|
||||
|
||||
for (auto _ : state) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = calculateDamage<Generation::GENERATION_1>(baseDamage, attackType, pokemon);
|
||||
auto result = calculateDamage<Generation::I>(baseDamage, attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_Generation8DamageCalc)(benchmark::State& sta
|
||||
|
||||
for (auto _ : state) {
|
||||
for (const auto& attackType : attackTypes) {
|
||||
auto result = calculateDamage<Generation::GENERATION_8>(baseDamage, attackType, pokemon);
|
||||
auto result = calculateDamage<Generation::VIII>(baseDamage, attackType, pokemon);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -227,7 +227,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_BatchDamageCalculation)(benchmark::State& st
|
||||
for (auto _ : state) {
|
||||
uint32_t totalDamage = 0;
|
||||
for (const auto& [attackType, defendTypes] : batch) {
|
||||
uint32_t damage = calculateDamage<Generation::GENERATION_1>(baseDamage, attackType, defendTypes);
|
||||
uint32_t damage = calculateDamage<Generation::I>(baseDamage, attackType, defendTypes);
|
||||
totalDamage += damage;
|
||||
}
|
||||
benchmark::DoNotOptimize(totalDamage);
|
||||
@@ -243,7 +243,7 @@ BENCHMARK_REGISTER_F(TypeSystemBenchmark, BM_BatchDamageCalculation)
|
||||
// Memory access pattern benchmark
|
||||
BENCHMARK_F(TypeSystemBenchmark, BM_TypeChartMemoryAccess)(benchmark::State& state) {
|
||||
// Test memory access patterns for type chart lookups
|
||||
const auto& chart = TypeChartTraits<Generation::GENERATION_1>::getTypeChart();
|
||||
const auto& chart = TypeChartTraits<Generation::I>::getTypeChart();
|
||||
|
||||
for (auto _ : state) {
|
||||
// Sequential access pattern
|
||||
@@ -255,7 +255,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_TypeChartMemoryAccess)(benchmark::State& sta
|
||||
}
|
||||
|
||||
BENCHMARK_F(TypeSystemBenchmark, BM_TypeChartRandomAccess)(benchmark::State& state) {
|
||||
const auto& chart = TypeChartTraits<Generation::GENERATION_1>::getTypeChart();
|
||||
const auto& chart = TypeChartTraits<Generation::I>::getTypeChart();
|
||||
const size_t chartSize = chart.size();
|
||||
|
||||
// Generate random indices
|
||||
@@ -289,7 +289,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_CacheFriendlyLookups)(benchmark::State& stat
|
||||
size_t defendIdx = j;
|
||||
size_t index = attackIdx * static_cast<size_t>(Type::TYPE_COUNT) + defendIdx;
|
||||
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::I>(
|
||||
attackTypes[attackIdx % attackTypes.size()],
|
||||
attackTypes[defendIdx % attackTypes.size()]
|
||||
);
|
||||
@@ -313,7 +313,7 @@ BENCHMARK_F(TypeSystemBenchmark, BM_CacheUnfriendlyLookups)(benchmark::State& st
|
||||
|
||||
for (auto _ : state) {
|
||||
for (const auto& [attackIdx, defendIdx] : randomPairs) {
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::I>(
|
||||
attackTypes[attackIdx],
|
||||
attackTypes[defendIdx]
|
||||
);
|
||||
@@ -328,7 +328,7 @@ static void BM_TypeEffectivenessFunction(benchmark::State& state) {
|
||||
Type defendType = Type::FIRE;
|
||||
|
||||
for (auto _ : state) {
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(attackType, defendType);
|
||||
auto result = TypeUtils::getTypeEffectiveness<Generation::I>(attackType, defendType);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ static void BM_DamageMultiplierFunction(benchmark::State& state) {
|
||||
PokemonTypes defender(Type::FIRE, Type::FLYING);
|
||||
|
||||
for (auto _ : state) {
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(attackType, defender);
|
||||
auto result = TypeUtils::calculateDamageMultiplier<Generation::I>(attackType, defender);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -349,7 +349,7 @@ static void BM_CalculateDamageFunction(benchmark::State& state) {
|
||||
PokemonTypes defender(Type::FIRE, Type::FLYING);
|
||||
|
||||
for (auto _ : state) {
|
||||
auto result = calculateDamage<Generation::GENERATION_1>(baseDamage, attackType, defender);
|
||||
auto result = calculateDamage<Generation::I>(baseDamage, attackType, defender);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@@ -432,7 +432,7 @@ static void BM_BattleTurnSimulation(benchmark::State& state) {
|
||||
for (const auto& defender : defenders) {
|
||||
for (const auto& move : attacker.moves) {
|
||||
// Calculate damage for each move against each defender
|
||||
uint32_t damage = calculateDamage<Generation::GENERATION_1>(100, move, defender.types);
|
||||
uint32_t damage = calculateDamage<Generation::I>(100, move, defender.types);
|
||||
totalDamage += damage;
|
||||
}
|
||||
}
|
||||
@@ -446,4 +446,4 @@ BENCHMARK(BM_BattleTurnSimulation)
|
||||
->Unit(benchmark::kMicrosecond)
|
||||
->Iterations(100);
|
||||
|
||||
} // namespace PokemonSim
|
||||
} // namespace PokEng
|
||||
|
||||
14
cmake/PokEngConfig.cmake.in
Normal file
14
cmake/PokEngConfig.cmake.in
Normal file
@@ -0,0 +1,14 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Pokemon Battle Simulator CMake Configuration
|
||||
set(PokEng_VERSION "@PROJECT_VERSION@")
|
||||
|
||||
# Set up import targets
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/PokEngTargets.cmake")
|
||||
|
||||
# Set up variables for consumers
|
||||
set(PokEng_LIBRARIES PokEng::pokemon_battle_sim)
|
||||
set(PokEng_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
|
||||
# Check required components
|
||||
check_required_components(PokEng)
|
||||
@@ -1,14 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Pokemon Battle Simulator CMake Configuration
|
||||
set(PokemonSim_VERSION "@PROJECT_VERSION@")
|
||||
|
||||
# Set up import targets
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/PokemonSimTargets.cmake")
|
||||
|
||||
# Set up variables for consumers
|
||||
set(PokemonSim_LIBRARIES PokemonSim::pokemon_battle_sim)
|
||||
set(PokemonSim_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
|
||||
# Check required components
|
||||
check_required_components(PokemonSim)
|
||||
@@ -20,3 +20,13 @@ function(set_project_warnings)
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to disable specific warnings for third-party libraries
|
||||
function(disable_third_party_warnings target)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${target} PRIVATE
|
||||
-Wno-sign-conversion
|
||||
-Wno-conversion
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
{
|
||||
"attacking_type": "fire",
|
||||
"defending_type": "fire",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -74,7 +74,7 @@
|
||||
{
|
||||
"attacking_type": "water",
|
||||
"defending_type": "water",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -110,7 +110,7 @@
|
||||
{
|
||||
"attacking_type": "electric",
|
||||
"defending_type": "electric",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -140,7 +140,7 @@
|
||||
{
|
||||
"attacking_type": "grass",
|
||||
"defending_type": "water",
|
||||
"damage_factor": 2.0,
|
||||
"damage_factor": 0.5,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -170,7 +170,7 @@
|
||||
{
|
||||
"attacking_type": "grass",
|
||||
"defending_type": "grass",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -218,7 +218,7 @@
|
||||
{
|
||||
"attacking_type": "ice",
|
||||
"defending_type": "ice",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -278,7 +278,7 @@
|
||||
{
|
||||
"attacking_type": "poison",
|
||||
"defending_type": "poison",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -320,7 +320,7 @@
|
||||
{
|
||||
"attacking_type": "ground",
|
||||
"defending_type": "electric",
|
||||
"damage_factor": 2.0,
|
||||
"damage_factor": 0.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -386,7 +386,7 @@
|
||||
{
|
||||
"attacking_type": "psychic",
|
||||
"defending_type": "psychic",
|
||||
"damage_factor": 0.5,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -470,7 +470,7 @@
|
||||
{
|
||||
"attacking_type": "ghost",
|
||||
"defending_type": "ghost",
|
||||
"damage_factor": 2.0,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
},
|
||||
{
|
||||
@@ -488,7 +488,7 @@
|
||||
{
|
||||
"attacking_type": "dragon",
|
||||
"defending_type": "dragon",
|
||||
"damage_factor": 2.0,
|
||||
"damage_factor": 1.0,
|
||||
"generation": "generation-i"
|
||||
}
|
||||
]
|
||||
@@ -49,10 +49,10 @@ enum class TypeMultiplier : uint8_t {
|
||||
#### Basic Type Effectiveness
|
||||
|
||||
```cpp
|
||||
using namespace PokemonSim;
|
||||
using namespace PokEng;
|
||||
|
||||
// Calculate damage with type effectiveness
|
||||
uint32_t damage = calculateTypeDamage<Generation::GENERATION_1>(
|
||||
uint32_t damage = calculateTypeDamage<Generation::I>(
|
||||
100, // Base damage
|
||||
Type::WATER, // Attack type
|
||||
Type::FIRE // Defender type
|
||||
@@ -64,7 +64,7 @@ uint32_t damage = calculateTypeDamage<Generation::GENERATION_1>(
|
||||
|
||||
```cpp
|
||||
// Electric attack on Water/Flying Pokemon
|
||||
uint32_t damage = calculateTypeDamage<Generation::GENERATION_1>(
|
||||
uint32_t damage = calculateTypeDamage<Generation::I>(
|
||||
100, // Base damage
|
||||
Type::ELECTRIC, // Attack type
|
||||
Type::WATER, // Primary defender type
|
||||
@@ -81,7 +81,7 @@ Pokemon charizard("Charizard", 150, Type::FIRE, Type::FLYING);
|
||||
Pokemon blastoise("Blastoise", 150, Type::WATER);
|
||||
|
||||
// Calculate damage using Pokemon methods
|
||||
uint32_t damage = charizard.calculateDamageTaken<Generation::GENERATION_1>(
|
||||
uint32_t damage = charizard.calculateDamageTaken<Generation::I>(
|
||||
100, // Base damage
|
||||
Type::WATER // Attack type
|
||||
);
|
||||
@@ -94,10 +94,10 @@ The system supports all Pokemon generations through compile-time templates:
|
||||
|
||||
```cpp
|
||||
// Generation 1 type effectiveness
|
||||
auto gen1Damage = calculateTypeDamage<Generation::GENERATION_1>(100, Type::FIRE, Type::WATER);
|
||||
auto gen1Damage = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
|
||||
|
||||
// Generation 8 type effectiveness
|
||||
auto gen8Damage = calculateTypeDamage<Generation::GENERATION_8>(100, Type::FIRE, Type::WATER);
|
||||
auto gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::FIRE, Type::WATER);
|
||||
```
|
||||
|
||||
Each generation has its own type chart loaded from the corresponding JSON file.
|
||||
@@ -168,11 +168,11 @@ Test categories:
|
||||
|
||||
```cpp
|
||||
// Test: Water attack on Fire type
|
||||
uint32_t damage = calculateTypeDamage<Generation::GENERATION_1>(100, Type::WATER, Type::FIRE);
|
||||
uint32_t damage = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
|
||||
ASSERT_EQ(damage, 200); // Water is super effective (2x) against Fire
|
||||
|
||||
// Test: Dual-type Electric attack on Water/Flying
|
||||
uint32_t dualDamage = calculateTypeDamage<Generation::GENERATION_1>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
uint32_t dualDamage = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
ASSERT_EQ(dualDamage, 400); // Electric is super effective (2x) against both types = 4x total
|
||||
```
|
||||
|
||||
@@ -183,13 +183,13 @@ ASSERT_EQ(dualDamage, 400); // Electric is super effective (2x) against both ty
|
||||
#### `calculateTypeDamage`
|
||||
|
||||
```cpp
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
template <Generation Gen = Generation::I>
|
||||
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, const PokemonTypes& defenderTypes);
|
||||
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
template <Generation Gen = Generation::I>
|
||||
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType);
|
||||
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
template <Generation Gen = Generation::I>
|
||||
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType1, Type defenderType2);
|
||||
```
|
||||
|
||||
@@ -218,9 +218,9 @@ enum class Type : uint8_t {
|
||||
|
||||
```cpp
|
||||
enum class Generation : uint8_t {
|
||||
GENERATION_1 = 1, GENERATION_2 = 2, GENERATION_3 = 3, GENERATION_4 = 4,
|
||||
GENERATION_5 = 5, GENERATION_6 = 6, GENERATION_7 = 7, GENERATION_8 = 8,
|
||||
GENERATION_9 = 9
|
||||
I = 1, II = 2, III = 3, IV = 4,
|
||||
V = 5, VI = 6, VII = 7, VIII = 8,
|
||||
IX = 9
|
||||
};
|
||||
```
|
||||
|
||||
@@ -261,7 +261,7 @@ To use the type system in your code:
|
||||
#include "types.h"
|
||||
|
||||
// Use the high-level API
|
||||
uint32_t damage = PokemonSim::calculateTypeDamage(
|
||||
uint32_t damage = PokEng::calculateTypeDamage(
|
||||
100, Type::FIRE, Type::GRASS
|
||||
);
|
||||
```
|
||||
|
||||
@@ -11,7 +11,7 @@ foreach(EXAMPLE_SOURCE ${EXAMPLE_SOURCES})
|
||||
# Link with our library
|
||||
target_link_libraries(${EXAMPLE_NAME}
|
||||
PRIVATE
|
||||
PokemonSim::pokemon_battle_sim
|
||||
PokEng::pokemon_battle_sim
|
||||
)
|
||||
|
||||
# Include directories
|
||||
@@ -23,4 +23,4 @@ endforeach()
|
||||
|
||||
# Example of adding examples manually:
|
||||
# add_executable(battle_example battle_example.cpp)
|
||||
# target_link_libraries(battle_example PRIVATE PokemonSim::pokemon_battle_sim)
|
||||
# target_link_libraries(battle_example PRIVATE PokEng::pokemon_battle_sim)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace PokemonSim;
|
||||
using namespace PokEng;
|
||||
|
||||
int main() {
|
||||
std::cout << "=== Pokemon Type System Example ===\n\n";
|
||||
@@ -15,15 +15,15 @@ int main() {
|
||||
std::cout << "-----------------------------------\n";
|
||||
|
||||
// Water attack on Fire type (super effective)
|
||||
uint32_t damage1 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::WATER, Type::FIRE);
|
||||
uint32_t damage1 = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
|
||||
std::cout << "Water attack on Fire Pokemon: " << damage1 << " damage (expected: 200)\n";
|
||||
|
||||
// Fire attack on Water type (not very effective)
|
||||
uint32_t damage2 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::FIRE, Type::WATER);
|
||||
uint32_t damage2 = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
|
||||
std::cout << "Fire attack on Water Pokemon: " << damage2 << " damage (expected: 50)\n";
|
||||
|
||||
// Normal attack on Ghost type (immune)
|
||||
uint32_t damage3 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::NORMAL, Type::GHOST);
|
||||
uint32_t damage3 = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::GHOST);
|
||||
std::cout << "Normal attack on Ghost Pokemon: " << damage3 << " damage (expected: 0)\n";
|
||||
|
||||
std::cout << "\n";
|
||||
@@ -33,11 +33,11 @@ int main() {
|
||||
std::cout << "-----------------------------\n";
|
||||
|
||||
// Electric attack on Water/Flying (super effective against both)
|
||||
uint32_t damage4 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
uint32_t damage4 = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
std::cout << "Electric attack on Water/Flying Pokemon: " << damage4 << " damage (4x effective)\n";
|
||||
|
||||
// Grass attack on Water/Flying (mixed effectiveness)
|
||||
uint32_t damage5 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::GRASS, Type::WATER, Type::FLYING);
|
||||
uint32_t damage5 = calculateTypeDamage<Generation::I>(100, Type::GRASS, Type::WATER, Type::FLYING);
|
||||
std::cout << "Grass attack on Water/Flying Pokemon: " << damage5 << " damage (neutral effectiveness)\n";
|
||||
|
||||
std::cout << "\n";
|
||||
@@ -47,18 +47,18 @@ int main() {
|
||||
std::cout << "-----------------------------\n";
|
||||
|
||||
// Create some Pokemon with different types
|
||||
Pokemon charizard("Charizard", 150, Type::FIRE, Type::FLYING);
|
||||
Pokemon blastoise("Blastoise", 150, Type::WATER);
|
||||
Pokemon venusaur("Venusaur", 150, Type::GRASS, Type::POISON);
|
||||
Pokemon charizard(6, 150, Type::FIRE, Type::FLYING);
|
||||
Pokemon blastoise(9, 150, Type::WATER);
|
||||
Pokemon venusaur(3, 150, Type::GRASS, Type::POISON);
|
||||
|
||||
std::cout << charizard.getName() << " (Fire/Flying) has "
|
||||
std::cout << charizard.getId() << " (Fire/Flying) has "
|
||||
<< TypeUtils::typeToString(charizard.getTypes().getPrimary()) << "/"
|
||||
<< TypeUtils::typeToString(charizard.getTypes().getSecondary()) << " types\n";
|
||||
|
||||
std::cout << blastoise.getName() << " (Water) has "
|
||||
std::cout << blastoise.getId() << " (Water) has "
|
||||
<< TypeUtils::typeToString(blastoise.getTypes().getPrimary()) << " type\n";
|
||||
|
||||
std::cout << venusaur.getName() << " (Grass/Poison) has "
|
||||
std::cout << venusaur.getId() << " (Grass/Poison) has "
|
||||
<< TypeUtils::typeToString(venusaur.getTypes().getPrimary()) << "/"
|
||||
<< TypeUtils::typeToString(venusaur.getTypes().getSecondary()) << " types\n";
|
||||
|
||||
@@ -68,16 +68,16 @@ int main() {
|
||||
std::cout << "4. Damage Calculations Using Pokemon Methods:\n";
|
||||
std::cout << "--------------------------------------------\n";
|
||||
|
||||
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::FIRE);
|
||||
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::FIRE);
|
||||
std::cout << "Charizard takes " << fireDamage << " damage from Fire attack (expected: 50)\n";
|
||||
|
||||
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::WATER);
|
||||
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::WATER);
|
||||
std::cout << "Charizard takes " << waterDamage << " damage from Water attack (expected: 200)\n";
|
||||
|
||||
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::ELECTRIC);
|
||||
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::ELECTRIC);
|
||||
std::cout << "Charizard takes " << electricDamage << " damage from Electric attack (expected: 200)\n";
|
||||
|
||||
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::GROUND);
|
||||
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::GROUND);
|
||||
std::cout << "Charizard takes " << groundDamage << " damage from Ground attack (expected: 0 - immune)\n";
|
||||
|
||||
std::cout << "\n";
|
||||
@@ -87,8 +87,8 @@ int main() {
|
||||
std::cout << "-------------------------\n";
|
||||
|
||||
// Steel type was introduced in Gen 2, so Steel moves don't exist in Gen 1
|
||||
uint32_t gen1Damage = calculateTypeDamage<Generation::GENERATION_1>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen8Damage = calculateTypeDamage<Generation::GENERATION_8>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen1Damage = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::NORMAL, Type::STEEL);
|
||||
|
||||
std::cout << "Normal attack on Steel in Generation 1: " << gen1Damage << " damage\n";
|
||||
std::cout << "Normal attack on Steel in Generation 8: " << gen8Damage << " damage\n";
|
||||
@@ -96,28 +96,8 @@ int main() {
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
// Example 6: Battle simulation with types
|
||||
std::cout << "6. Battle Simulation with Types:\n";
|
||||
std::cout << "--------------------------------\n";
|
||||
|
||||
// Reset Pokemon health for battle
|
||||
Pokemon battleCharizard("Charizard", 150, Type::FIRE, Type::FLYING);
|
||||
Pokemon battleBlastoise("Blastoise", 150, Type::WATER);
|
||||
|
||||
std::cout << "Battle: " << battleCharizard.getName() << " vs " << battleBlastoise.getName() << "\n";
|
||||
std::cout << "Initial health - " << battleCharizard.getName() << ": " << battleCharizard.getHealth()
|
||||
<< ", " << battleBlastoise.getName() << ": " << battleBlastoise.getHealth() << "\n";
|
||||
|
||||
bool charizardWins = simulateBattle(battleCharizard, battleBlastoise);
|
||||
|
||||
std::cout << "Final health - " << battleCharizard.getName() << ": " << battleCharizard.getHealth()
|
||||
<< ", " << battleBlastoise.getName() << ": " << battleBlastoise.getHealth() << "\n";
|
||||
std::cout << "Winner: " << (charizardWins ? battleCharizard.getName() : battleBlastoise.getName()) << "\n";
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
// Example 7: Type string conversion
|
||||
std::cout << "7. Type String Conversion:\n";
|
||||
// Example 6: Type string conversion
|
||||
std::cout << "6. Type String Conversion:\n";
|
||||
std::cout << "-------------------------\n";
|
||||
|
||||
std::vector<Type> typesToTest = {Type::FIRE, Type::WATER, Type::GRASS, Type::ELECTRIC, Type::FAIRY};
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# Include Directory (`include/`)
|
||||
|
||||
This directory contains all C++ header files (.h/.hpp) for the Pokemon battle simulator.
|
||||
|
||||
## Planned Structure
|
||||
|
||||
```
|
||||
include/
|
||||
├── pokemon_sim/ # Main namespace headers
|
||||
│ ├── core/ # Core battle system headers
|
||||
│ │ ├── battle.h # Battle class and enums
|
||||
│ │ ├── pokemon.h # Pokemon class definition
|
||||
│ │ ├── move.h # Move system headers
|
||||
│ │ ├── type.h # Type system and effectiveness
|
||||
│ │ └── status.h # Status effects
|
||||
│ ├── data/ # Data management headers
|
||||
│ │ ├── pokemon_data.h # Pokemon species data
|
||||
│ │ ├── move_data.h # Move definitions
|
||||
│ │ └── loader.h # Data loading interface
|
||||
│ ├── ai/ # AI system headers
|
||||
│ │ ├── ai_base.h # Base AI interface
|
||||
│ │ ├── random_ai.h # Random AI strategy
|
||||
│ │ └── minimax_ai.h # Minimax AI strategy
|
||||
│ ├── utils/ # Utility headers
|
||||
│ │ ├── random.h # Random utilities
|
||||
│ │ ├── stats.h # Stat calculation helpers
|
||||
│ │ └── constants.h # Game constants
|
||||
│ └── pokemon_sim.h # Main include file
|
||||
```
|
||||
|
||||
## Header Guidelines
|
||||
|
||||
- **Include Guards**: Use `#pragma once` for all headers
|
||||
- **Forward Declarations**: Minimize #include dependencies
|
||||
- **Const Correctness**: Mark methods const where appropriate
|
||||
- **Documentation**: Doxygen-style comments for public APIs
|
||||
- **Namespace**: All code in `pokemon_sim` namespace
|
||||
|
||||
## Public API
|
||||
|
||||
The main `pokemon_sim.h` header provides a clean public interface for library users, hiding implementation details while exposing necessary functionality for battle simulation.
|
||||
26
include/core/battle.h
Normal file
26
include/core/battle.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef BATTLE_H
|
||||
#define BATTLE_H
|
||||
|
||||
#include "pokemon.h"
|
||||
|
||||
namespace PokEng {
|
||||
|
||||
// High-level type system functions for easy use
|
||||
template <Generation Gen = Generation::I>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, const PokemonTypes& defenderTypes) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, defenderTypes);
|
||||
}
|
||||
|
||||
template <Generation Gen = Generation::I>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType));
|
||||
}
|
||||
|
||||
template <Generation Gen = Generation::I>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType1, Type defenderType2) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType1, defenderType2));
|
||||
}
|
||||
|
||||
} // namespace PokEng
|
||||
|
||||
#endif
|
||||
24
include/core/config.h
Normal file
24
include/core/config.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PokEng {
|
||||
|
||||
// Generation support
|
||||
enum class Generation : uint8_t {
|
||||
I = 1,
|
||||
II = 2,
|
||||
III = 3,
|
||||
IV = 4,
|
||||
V = 5,
|
||||
VI = 6,
|
||||
VII = 7,
|
||||
VIII = 8,
|
||||
IX = 9
|
||||
};
|
||||
|
||||
} // namespace PokEng
|
||||
|
||||
|
||||
#endif
|
||||
50
include/core/pokemon.h
Normal file
50
include/core/pokemon.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef POKEMON_H
|
||||
#define POKEMON_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
|
||||
namespace PokEng {
|
||||
|
||||
|
||||
class Pokemon {
|
||||
public:
|
||||
Pokemon() = default;
|
||||
~Pokemon() = default;
|
||||
|
||||
Pokemon(uint16_t id) : m_id(id) {}
|
||||
Pokemon(uint16_t id, uint16_t health) : m_id(id), m_health(health) {}
|
||||
Pokemon(uint16_t id, uint16_t health, Type primaryType) : m_id(id), m_health(health), m_types(primaryType) {}
|
||||
Pokemon(uint16_t id, uint16_t health, Type primaryType, Type secondaryType) : m_id(id), m_health(health), m_types(primaryType, secondaryType) {}
|
||||
|
||||
public:
|
||||
// Getters
|
||||
uint16_t getId() const { return m_id; }
|
||||
uint16_t getHealth() const { return m_health; }
|
||||
PokemonTypes getTypes() const { return m_types; }
|
||||
Type getPrimaryType() const { return m_types.getPrimary(); }
|
||||
Type getSecondaryType() const { return m_types.getSecondary(); }
|
||||
|
||||
// Setters
|
||||
void setHealth(uint16_t health) { m_health = health; }
|
||||
void setTypes(Type primary) { m_types.setPrimary(primary); m_types.setSecondary(Type::NONE); }
|
||||
void setTypes(Type primary, Type secondary) { m_types.setPrimary(primary); m_types.setSecondary(secondary); }
|
||||
void SetPokemonTypes(PokemonTypes types) { m_types = types; }
|
||||
|
||||
public:
|
||||
// Type-based operations
|
||||
template <Generation Gen = Generation::I>
|
||||
uint32_t calculateDamageTaken(uint32_t baseDamage, Type attackType) const {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, m_types);
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t m_id;
|
||||
uint16_t m_health;
|
||||
PokemonTypes m_types;
|
||||
};
|
||||
|
||||
} // namespace PokEng
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef POKEMON_TYPES_H
|
||||
#define POKEMON_TYPES_H
|
||||
#ifndef POKEMON_m_typesH
|
||||
#define POKEMON_m_typesH
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace PokemonSim {
|
||||
#include "config.h"
|
||||
|
||||
namespace PokEng {
|
||||
|
||||
// Forward declarations
|
||||
enum class Type : uint8_t;
|
||||
@@ -47,19 +49,6 @@ enum class TypeMultiplier : uint8_t {
|
||||
QUADRUPLE = 16 // 4x damage
|
||||
};
|
||||
|
||||
// Generation support
|
||||
enum class Generation : uint8_t {
|
||||
GENERATION_1 = 1,
|
||||
GENERATION_2 = 2,
|
||||
GENERATION_3 = 3,
|
||||
GENERATION_4 = 4,
|
||||
GENERATION_5 = 5,
|
||||
GENERATION_6 = 6,
|
||||
GENERATION_7 = 7,
|
||||
GENERATION_8 = 8,
|
||||
GENERATION_9 = 9
|
||||
};
|
||||
|
||||
// Compile-time type chart traits
|
||||
template <Generation Gen>
|
||||
struct TypeChartTraits {
|
||||
@@ -112,15 +101,15 @@ public:
|
||||
|
||||
public:
|
||||
// Type chart storage for each generation (public for template access)
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_1>::CHART_SIZE> s_gen1Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_2>::CHART_SIZE> s_gen2Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_3>::CHART_SIZE> s_gen3Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_4>::CHART_SIZE> s_gen4Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_5>::CHART_SIZE> s_gen5Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_6>::CHART_SIZE> s_gen6Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_7>::CHART_SIZE> s_gen7Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_8>::CHART_SIZE> s_gen8Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_9>::CHART_SIZE> s_gen9Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE> s_gen1Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE> s_gen2Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE> s_gen3Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE> s_gen4Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE> s_gen5Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE> s_gen6Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE> s_gen7Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE> s_gen8Chart;
|
||||
static std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE> s_gen9Chart;
|
||||
};
|
||||
|
||||
// High-performance damage calculation
|
||||
@@ -136,59 +125,59 @@ inline uint32_t calculateDamage(uint32_t baseDamage, Type attackType, const Poke
|
||||
|
||||
// Template specializations for type chart access
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_1>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_1>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::I>::getTypeChart() {
|
||||
return TypeUtils::s_gen1Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_2>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_2>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::II>::getTypeChart() {
|
||||
return TypeUtils::s_gen2Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_3>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_3>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::III>::getTypeChart() {
|
||||
return TypeUtils::s_gen3Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_4>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_4>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::IV>::getTypeChart() {
|
||||
return TypeUtils::s_gen4Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_5>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_5>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::V>::getTypeChart() {
|
||||
return TypeUtils::s_gen5Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_6>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_6>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::VI>::getTypeChart() {
|
||||
return TypeUtils::s_gen6Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_7>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_7>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::VII>::getTypeChart() {
|
||||
return TypeUtils::s_gen7Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_8>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_8>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::VIII>::getTypeChart() {
|
||||
return TypeUtils::s_gen8Chart;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::GENERATION_9>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::GENERATION_9>::getTypeChart() {
|
||||
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE>&
|
||||
TypeChartTraits<Generation::IX>::getTypeChart() {
|
||||
return TypeUtils::s_gen9Chart;
|
||||
}
|
||||
|
||||
} // namespace PokemonSim
|
||||
} // namespace PokEng
|
||||
|
||||
#endif // POKEMON_TYPES_H
|
||||
#endif // POKEMON_m_typesH
|
||||
@@ -1,66 +1,17 @@
|
||||
// Pokemon Battle Engine Header
|
||||
// High-performance Pokemon battle simulator with type system
|
||||
|
||||
#ifndef POKEMON_BATTLE_SIM_H
|
||||
#define POKEMON_BATTLE_SIM_H
|
||||
|
||||
#include <string>
|
||||
#include "types.h"
|
||||
// Main header file for Pokemon Battle Simulator
|
||||
// Includes all core functionality
|
||||
|
||||
namespace PokemonSim {
|
||||
#include "core/types.h"
|
||||
#include "core/pokemon.h"
|
||||
#include "core/battle.h"
|
||||
#include "core/config.h"
|
||||
|
||||
// Forward declarations
|
||||
class Pokemon;
|
||||
|
||||
// Pokemon class with type support
|
||||
class Pokemon {
|
||||
public:
|
||||
Pokemon(const std::string& name, int health = 100);
|
||||
Pokemon(const std::string& name, int health, Type primaryType);
|
||||
Pokemon(const std::string& name, int health, Type primaryType, Type secondaryType);
|
||||
~Pokemon() = default;
|
||||
|
||||
// Getters
|
||||
std::string getName() const;
|
||||
int getHealth() const;
|
||||
const PokemonTypes& getTypes() const;
|
||||
|
||||
// Setters
|
||||
void setHealth(int health);
|
||||
void setTypes(Type primary);
|
||||
void setTypes(Type primary, Type secondary);
|
||||
|
||||
// Type-based operations
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
uint32_t calculateDamageTaken(uint32_t baseDamage, Type attackType) const {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, types_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
int health_;
|
||||
PokemonTypes types_;
|
||||
};
|
||||
|
||||
// Battle simulation function
|
||||
// Forward declarations for functions
|
||||
namespace PokEng {
|
||||
bool simulateBattle(Pokemon& pokemon1, Pokemon& pokemon2);
|
||||
|
||||
// High-level type system functions for easy use
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, const PokemonTypes& defenderTypes) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, defenderTypes);
|
||||
}
|
||||
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType));
|
||||
}
|
||||
|
||||
template <Generation Gen = Generation::GENERATION_1>
|
||||
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType1, Type defenderType2) {
|
||||
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType1, defenderType2));
|
||||
}
|
||||
|
||||
} // namespace PokemonSim
|
||||
|
||||
#endif // POKEMON_BATTLE_SIM_H
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -16,6 +16,21 @@ FetchContent_MakeAvailable(googletest)
|
||||
|
||||
# Include Google Test modules
|
||||
include(GoogleTest)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/modules/CompilerWarnings.cmake)
|
||||
|
||||
# Disable problematic warnings for Google Test targets
|
||||
if(TARGET gtest)
|
||||
disable_third_party_warnings(gtest)
|
||||
endif()
|
||||
if(TARGET gmock)
|
||||
disable_third_party_warnings(gmock)
|
||||
endif()
|
||||
if(TARGET gtest_main)
|
||||
disable_third_party_warnings(gtest_main)
|
||||
endif()
|
||||
if(TARGET gmock_main)
|
||||
disable_third_party_warnings(gmock_main)
|
||||
endif()
|
||||
|
||||
# Create test executable for unit tests
|
||||
add_executable(unit_tests
|
||||
@@ -27,7 +42,7 @@ target_link_libraries(unit_tests
|
||||
PRIVATE
|
||||
GTest::gtest_main
|
||||
GTest::gmock_main
|
||||
PokemonSim::pokemon_battle_sim
|
||||
PokEng::pokemon_battle_sim
|
||||
)
|
||||
|
||||
# Set up test discovery
|
||||
@@ -47,7 +62,7 @@ target_link_libraries(integration_tests
|
||||
PRIVATE
|
||||
GTest::gtest_main
|
||||
GTest::gmock_main
|
||||
PokemonSim::pokemon_battle_sim
|
||||
PokEng::pokemon_battle_sim
|
||||
)
|
||||
|
||||
# Set up test discovery
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Example test case demonstrating Google Test usage
|
||||
class ExampleTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Set up test fixtures here
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Clean up test fixtures here
|
||||
}
|
||||
};
|
||||
|
||||
// Basic assertion test
|
||||
TEST_F(ExampleTest, BasicAssertions) {
|
||||
// Basic equality assertions
|
||||
EXPECT_EQ(2 + 2, 4);
|
||||
EXPECT_NE(2 + 2, 5);
|
||||
|
||||
// Boolean assertions
|
||||
EXPECT_TRUE(true);
|
||||
EXPECT_FALSE(false);
|
||||
|
||||
// String assertions
|
||||
EXPECT_STREQ("hello", "hello");
|
||||
EXPECT_STRNE("hello", "world");
|
||||
}
|
||||
|
||||
// Test with parameters
|
||||
TEST(ParameterizedTest, Addition) {
|
||||
EXPECT_EQ(1 + 1, 2);
|
||||
EXPECT_EQ(10 + 5, 15);
|
||||
EXPECT_EQ(-1 + 1, 0);
|
||||
}
|
||||
|
||||
// Test that demonstrates failure (using TEST_F to match the fixture)
|
||||
TEST_F(ExampleTest, ThisWillFail) {
|
||||
// This test will fail to demonstrate the failure output
|
||||
// EXPECT_EQ(2 + 2, 5); // Uncomment this line to see a failing test
|
||||
}
|
||||
|
||||
// Example of how you might test a Pokemon battle simulator component
|
||||
// This demonstrates testing the placeholder implementation we created
|
||||
#include "pokemon_battle_sim.h"
|
||||
|
||||
TEST(PokemonTest, PokemonCreation) {
|
||||
PokemonSim::Pokemon pikachu("Pikachu", 100);
|
||||
|
||||
// Test basic properties
|
||||
EXPECT_EQ(pikachu.getName(), "Pikachu");
|
||||
EXPECT_EQ(pikachu.getHealth(), 100);
|
||||
}
|
||||
|
||||
TEST(PokemonTest, PokemonHealthModification) {
|
||||
PokemonSim::Pokemon charizard("Charizard", 150);
|
||||
|
||||
EXPECT_EQ(charizard.getHealth(), 150);
|
||||
|
||||
charizard.setHealth(100);
|
||||
EXPECT_EQ(charizard.getHealth(), 100);
|
||||
}
|
||||
|
||||
TEST(PokemonTest, BattleSimulation) {
|
||||
PokemonSim::Pokemon pokemon1("Pokemon1", 50);
|
||||
PokemonSim::Pokemon pokemon2("Pokemon2", 30);
|
||||
|
||||
// Pokemon1 should win because it has more health
|
||||
bool result = PokemonSim::simulateBattle(pokemon1, pokemon2);
|
||||
EXPECT_TRUE(result); // Pokemon1 wins
|
||||
|
||||
// Both Pokemon should have taken damage
|
||||
EXPECT_LT(pokemon1.getHealth(), 50);
|
||||
EXPECT_LE(pokemon2.getHealth(), 0);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "types.h"
|
||||
#include "pokemon_battle_sim.h"
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace PokemonSim {
|
||||
namespace PokEng {
|
||||
|
||||
// Test fixture for type system tests
|
||||
class TypeSystemTest : public ::testing::Test {
|
||||
@@ -39,7 +39,7 @@ TEST_F(TypeSystemTest, TypeToStringConversion) {
|
||||
EXPECT_EQ(TypeUtils::typeToString(Type::FAIRY), "fairy");
|
||||
|
||||
// Test out of range (shouldn't happen in practice but good to test)
|
||||
EXPECT_EQ(TypeUtils::typeToString(static_cast<Type>(999)), "unknown");
|
||||
EXPECT_EQ(TypeUtils::typeToString(static_cast<Type>(static_cast<uint8_t>(Type::TYPE_COUNT) + 10)), "unknown");
|
||||
}
|
||||
|
||||
// Test PokemonTypes class
|
||||
@@ -76,21 +76,21 @@ TEST_F(TypeSystemTest, PokemonTypesModification) {
|
||||
// Test type effectiveness for Generation 1
|
||||
TEST_F(TypeSystemTest, TypeEffectivenessGen1) {
|
||||
// Test some well-known type matchups from Generation 1
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::WATER, Type::FIRE), TypeMultiplier::DOUBLE);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::FIRE, Type::WATER), TypeMultiplier::HALF);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::NORMAL, Type::ROCK), TypeMultiplier::HALF);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::ELECTRIC, Type::GROUND), TypeMultiplier::ZERO);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::FIGHTING, Type::GHOST), TypeMultiplier::ZERO);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::WATER, Type::FIRE), TypeMultiplier::DOUBLE);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::WATER), TypeMultiplier::HALF);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NORMAL, Type::ROCK), TypeMultiplier::HALF);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::ELECTRIC, Type::GROUND), TypeMultiplier::ZERO);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIGHTING, Type::GHOST), TypeMultiplier::ZERO);
|
||||
}
|
||||
|
||||
TEST_F(TypeSystemTest, TypeEffectivenessNeutral) {
|
||||
// Test neutral effectiveness (1x damage)
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::NORMAL, Type::NORMAL), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::FIRE, Type::FIRE), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NORMAL, Type::NORMAL), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::FIRE), TypeMultiplier::NEUTRAL);
|
||||
|
||||
// Test NONE types
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::NONE, Type::FIRE), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::GENERATION_1>(Type::FIRE, Type::NONE), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NONE, Type::FIRE), TypeMultiplier::NEUTRAL);
|
||||
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::NONE), TypeMultiplier::NEUTRAL);
|
||||
}
|
||||
|
||||
// Test damage multiplier calculations
|
||||
@@ -98,12 +98,12 @@ TEST_F(TypeSystemTest, DamageMultiplierSingleType) {
|
||||
// Single type Pokemon
|
||||
PokemonTypes charizard(Type::FIRE);
|
||||
|
||||
// Fire attack on Fire type (0.5x)
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::FIRE, charizard);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::HALF));
|
||||
// Fire attack on Fire type (1.0x - same type is neutral)
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::FIRE, charizard);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::NEUTRAL));
|
||||
|
||||
// Water attack on Fire type (2x)
|
||||
multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::WATER, charizard);
|
||||
multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::WATER, charizard);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::DOUBLE));
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ TEST_F(TypeSystemTest, DamageMultiplierDualType) {
|
||||
PokemonTypes gyarados(Type::WATER, Type::FLYING);
|
||||
|
||||
// Electric attack on Water/Flying (2x * 2x = 4x)
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::ELECTRIC, gyarados);
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::ELECTRIC, gyarados);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::QUADRUPLE));
|
||||
|
||||
// Grass attack on Water/Flying (0.5x * 0.5x = 0.25x)
|
||||
multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::GRASS, gyarados);
|
||||
multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::GRASS, gyarados);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::QUARTER));
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ TEST_F(TypeSystemTest, DamageMultiplierNoneAttack) {
|
||||
PokemonTypes charizard(Type::FIRE);
|
||||
|
||||
// NONE attack type should always return neutral multiplier
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::NONE, charizard);
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::NONE, charizard);
|
||||
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::NEUTRAL));
|
||||
}
|
||||
|
||||
@@ -133,16 +133,16 @@ TEST_F(TypeSystemTest, CalculateDamage) {
|
||||
PokemonTypes charizard(Type::FIRE);
|
||||
const uint32_t baseDamage = 100;
|
||||
|
||||
// Fire attack on Fire type: 100 * 0.5 = 50
|
||||
uint32_t damage = calculateDamage<Generation::GENERATION_1>(baseDamage, Type::FIRE, charizard);
|
||||
EXPECT_EQ(damage, 50);
|
||||
// Fire attack on Fire type: 100 * 1.0 = 100 (same type is neutral)
|
||||
uint32_t damage = calculateDamage<Generation::I>(baseDamage, Type::FIRE, charizard);
|
||||
EXPECT_EQ(damage, 100);
|
||||
|
||||
// Water attack on Fire type: 100 * 2 = 200
|
||||
damage = calculateDamage<Generation::GENERATION_1>(baseDamage, Type::WATER, charizard);
|
||||
damage = calculateDamage<Generation::I>(baseDamage, Type::WATER, charizard);
|
||||
EXPECT_EQ(damage, 200);
|
||||
|
||||
// Normal attack on Fire type: 100 * 1 = 100
|
||||
damage = calculateDamage<Generation::GENERATION_1>(baseDamage, Type::NORMAL, charizard);
|
||||
damage = calculateDamage<Generation::I>(baseDamage, Type::NORMAL, charizard);
|
||||
EXPECT_EQ(damage, 100);
|
||||
}
|
||||
|
||||
@@ -151,11 +151,11 @@ TEST_F(TypeSystemTest, CalculateDamageDualType) {
|
||||
const uint32_t baseDamage = 100;
|
||||
|
||||
// Electric attack on Water/Flying: 100 * 4 = 400
|
||||
uint32_t damage = calculateDamage<Generation::GENERATION_1>(baseDamage, Type::ELECTRIC, gyarados);
|
||||
uint32_t damage = calculateDamage<Generation::I>(baseDamage, Type::ELECTRIC, gyarados);
|
||||
EXPECT_EQ(damage, 400);
|
||||
|
||||
// Grass attack on Water/Flying: 100 * 0.25 = 25
|
||||
damage = calculateDamage<Generation::GENERATION_1>(baseDamage, Type::GRASS, gyarados);
|
||||
damage = calculateDamage<Generation::I>(baseDamage, Type::GRASS, gyarados);
|
||||
EXPECT_EQ(damage, 25);
|
||||
}
|
||||
|
||||
@@ -163,18 +163,18 @@ TEST_F(TypeSystemTest, CalculateDamageDualType) {
|
||||
TEST_F(TypeSystemTest, EdgeCases) {
|
||||
// Test with zero base damage
|
||||
PokemonTypes pokemon(Type::FIRE);
|
||||
uint32_t damage = calculateDamage<Generation::GENERATION_1>(0, Type::WATER, pokemon);
|
||||
uint32_t damage = calculateDamage<Generation::I>(0, Type::WATER, pokemon);
|
||||
EXPECT_EQ(damage, 0);
|
||||
|
||||
// Test immunity (0x multiplier)
|
||||
damage = calculateDamage<Generation::GENERATION_1>(100, Type::GROUND, PokemonTypes(Type::ELECTRIC));
|
||||
damage = calculateDamage<Generation::I>(100, Type::GROUND, PokemonTypes(Type::ELECTRIC));
|
||||
EXPECT_EQ(damage, 0);
|
||||
}
|
||||
|
||||
// Test different generations have different type charts
|
||||
TEST_F(TypeSystemTest, GenerationDifferences) {
|
||||
// Ghost/Fighting immunity in Gen 1
|
||||
uint32_t gen1Multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(
|
||||
uint32_t gen1Multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(
|
||||
Type::FIGHTING, PokemonTypes(Type::GHOST));
|
||||
EXPECT_EQ(gen1Multiplier, static_cast<uint32_t>(TypeMultiplier::ZERO));
|
||||
|
||||
@@ -190,7 +190,7 @@ TEST_P(TypeCombinationTest, VariousTypeCombinations) {
|
||||
auto [attackType, defendType, expectedMultiplier] = GetParam();
|
||||
|
||||
PokemonTypes defender(defendType);
|
||||
uint32_t actualMultiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(attackType, defender);
|
||||
uint32_t actualMultiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(attackType, defender);
|
||||
|
||||
EXPECT_EQ(actualMultiplier, expectedMultiplier)
|
||||
<< "Attack: " << TypeUtils::typeToString(attackType)
|
||||
@@ -215,7 +215,7 @@ TEST_F(TypeSystemTest, PerformanceTest) {
|
||||
|
||||
// Test that multiple lookups are fast (this would be caught by benchmark tests too)
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::GENERATION_1>(Type::WATER, pokemon);
|
||||
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::WATER, pokemon);
|
||||
(void)multiplier; // Prevent optimization
|
||||
}
|
||||
}
|
||||
@@ -223,44 +223,44 @@ TEST_F(TypeSystemTest, PerformanceTest) {
|
||||
// Test the high-level damage calculation functions
|
||||
TEST_F(TypeSystemTest, CalculateDamageFunctions) {
|
||||
// Test calculateTypeDamage with single type
|
||||
uint32_t damage1 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::WATER, Type::FIRE);
|
||||
uint32_t damage1 = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
|
||||
EXPECT_EQ(damage1, 200);
|
||||
|
||||
uint32_t damage2 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::FIRE, Type::WATER);
|
||||
uint32_t damage2 = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
|
||||
EXPECT_EQ(damage2, 50);
|
||||
|
||||
// Test calculateTypeDamage with dual type
|
||||
uint32_t damage3 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
uint32_t damage3 = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
|
||||
EXPECT_EQ(damage3, 400);
|
||||
|
||||
// Test immunity
|
||||
uint32_t damage4 = calculateTypeDamage<Generation::GENERATION_1>(100, Type::GROUND, Type::ELECTRIC);
|
||||
uint32_t damage4 = calculateTypeDamage<Generation::I>(100, Type::GROUND, Type::ELECTRIC);
|
||||
EXPECT_EQ(damage4, 0);
|
||||
}
|
||||
|
||||
// Test Pokemon damage calculation methods
|
||||
TEST_F(TypeSystemTest, PokemonDamageCalculation) {
|
||||
Pokemon charizard("Charizard", 100, Type::FIRE, Type::FLYING);
|
||||
Pokemon charizard(6, 100, Type::FIRE, Type::FLYING);
|
||||
|
||||
// Test various attack types
|
||||
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::FIRE);
|
||||
EXPECT_EQ(fireDamage, 50);
|
||||
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::FIRE);
|
||||
EXPECT_EQ(fireDamage, 100); // Fire vs Fire/Flying: 1.0x (neutral for Fire) * 1.0x (neutral for Flying)
|
||||
|
||||
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::WATER);
|
||||
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::WATER);
|
||||
EXPECT_EQ(waterDamage, 200);
|
||||
|
||||
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::ELECTRIC);
|
||||
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::ELECTRIC);
|
||||
EXPECT_EQ(electricDamage, 200); // 2x vs Flying, neutral vs Fire
|
||||
|
||||
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::GENERATION_1>(100, Type::GROUND);
|
||||
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::GROUND);
|
||||
EXPECT_EQ(groundDamage, 0); // Ground is immune to Flying
|
||||
}
|
||||
|
||||
// Test generation differences
|
||||
TEST_F(TypeSystemTest, GenerationDifferencesTest) {
|
||||
// Steel type was introduced in Gen 2
|
||||
uint32_t gen1Damage = calculateTypeDamage<Generation::GENERATION_1>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen8Damage = calculateTypeDamage<Generation::GENERATION_8>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen1Damage = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::STEEL);
|
||||
uint32_t gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::NORMAL, Type::STEEL);
|
||||
|
||||
// Results may differ based on loaded type charts
|
||||
EXPECT_GE(gen1Damage, 0);
|
||||
@@ -269,4 +269,4 @@ TEST_F(TypeSystemTest, GenerationDifferencesTest) {
|
||||
EXPECT_LE(gen8Damage, 400);
|
||||
}
|
||||
|
||||
} // namespace PokemonSim
|
||||
} // namespace PokEng
|
||||
|
||||
Reference in New Issue
Block a user