#include "Runner.hpp" #include #include #include #include #include void LearnMove(PkmnLib::Battling::CreatePokemon& c, ArbUt::Random& random, ArbUt::BorrowedPtr forme) { auto a = forme->GetLearnableAttacks(); auto move = a->GetRandomAttack(random); if (move.has_value()) { c.LearnMove(move.value()->GetName(), CreatureLib::Battling::AttackLearnMethod::Level); } } PkmnLib::Battling::Pokemon* CreateMon(const PkmnLib::Battling::BattleLibrary* library, ArbUt::Random& random) { auto species = library->GetSpeciesLibrary()->GetRandomValue(random); auto c = PkmnLib::Battling::CreatePokemon(library, species->GetName(), 100); LearnMove(c, random, species->GetVariant("default"_cnc)); LearnMove(c, random, species->GetVariant("default"_cnc)); LearnMove(c, random, species->GetVariant("default"_cnc)); LearnMove(c, random, species->GetVariant("default"_cnc)); return c.Build(random); } ArbUt::ScopedPtr CreateParty(const PkmnLib::Battling::BattleLibrary* library, ArbUt::Random& random) { return new PkmnLib::Battling::PokemonParty({ CreateMon(library, random), CreateMon(library, random), CreateMon(library, random), CreateMon(library, random), CreateMon(library, random), CreateMon(library, random), }); } u8 RunBattle(ArbUt::Random& rand, const PkmnLib::Battling::BattleLibrary* library, PkmnLibAI::PokemonAI* aiOne, PkmnLibAI::PokemonAI* aiTwo) { auto party1 = CreateParty(library, rand); auto party2 = CreateParty(library, rand); auto battle = ArbUt::ScopedPtr(new PkmnLib::Battling::Battle( library, { new CreatureLib::Battling::BattleParty(party1, {CreatureLib::Battling::CreatureIndex(0, 0)}), new CreatureLib::Battling::BattleParty(party2, {CreatureLib::Battling::CreatureIndex(1, 0)}), })); while (!battle->HasEnded()) { if (!battle->GetCreature(0, 0).HasValue() || battle->GetCreature(0, 0).GetValue()->IsFainted()) { for (auto* mon : party1->GetParty()) { if (!mon->IsFainted()) { battle->SwitchCreature(0, 0, mon); break; } } } if (!battle->GetCreature(1, 0).HasValue() || battle->GetCreature(1, 0).GetValue()->IsFainted()) { for (auto* mon : party2->GetParty()) { if (!mon->IsFainted()) { battle->SwitchCreature(1, 0, mon); break; } } } auto c1 = aiOne->GetChoice(battle, static_cast(battle->GetCreature(0, 0).GetValue())); auto c2 = aiTwo->GetChoice(battle, static_cast(battle->GetCreature(1, 0).GetValue())); EnsureNotNull(c1); EnsureNotNull(c2); if (!battle->TrySetChoice(c1)) { if (c1->GetKind() == CreatureLib::Battling::TurnChoiceKind::Attack) { auto a = (CreatureLib::Battling::AttackTurnChoice*)c1; THROW("Failed to set move choice of move: '" << a->GetAttack()->GetAttack()->GetName() << "' targeting side " << (i32)a->GetTarget().GetSideIndex() << " and index " << (i32)a->GetTarget().GetCreatureIndex()); } else { THROW("Failed to set choice of kind: " << CreatureLib::Battling::TurnChoiceKindHelper::ToString(c1->GetKind())); } } Ensure(battle->TrySetChoice(c2)); if (battle->GetCurrentTurn() >= 2000) { std::cout << ((CreatureLib::Battling::AttackTurnChoice*)c1)->GetAttack()->GetAttack()->GetName() << std::endl; std::cout << ((CreatureLib::Battling::AttackTurnChoice*)c2)->GetAttack()->GetAttack()->GetName() << std::endl; std::cout << battle->GetCreature(0, 0).GetValue()->GetSpecies()->GetName() << std::endl; std::cout << battle->GetCreature(1, 0).GetValue()->GetSpecies()->GetName() << std::endl; } Ensure(battle->GetCurrentTurn() < 2000); } return battle->GetResult().GetWinningSide(); } #define align std::setw(15) << std::left << void PrintResult(std::string name, size_t wins, size_t total) { std::cout << align name << align wins << wins / (float)total * 100.0 << "%" << std::endl; } void Runner::Run(const PkmnLib::Battling::BattleLibrary* library, PkmnLibAI::PokemonAI* aiOne, PkmnLibAI::PokemonAI* aiTwo, size_t runs) { ArbUt::Random rand; std::vector wins = {0, 0}; auto startTime = std::chrono::steady_clock::now(); std::cout << "Running 0/" << runs << " battles (0/0)"; for (size_t i = 0; i < runs; ++i) { std::cout << "\rRunning " << i + 1 << "/" << runs << " battles (" << wins[0] / (float)i << "/" << wins[1] / (float)i << ")" << std::flush; auto result = RunBattle(rand, library, aiOne, aiTwo); wins[result]++; } std::cout << std::endl; auto endTime = std::chrono::steady_clock::now(); std::cout << "Ran " << runs << " battles in " << duration_cast((endTime - startTime)).count() << " ms. Results:" << std::endl; std::cout << align "AI Name" << align "Wins" << align "Percentage" << std::endl; PrintResult(aiOne->GetName(), wins[0], runs); PrintResult(aiTwo->GetName(), wins[1], runs); }