PkmnLibAI/test_runner/Runner.cpp

126 lines
5.8 KiB
C++

#include "Runner.hpp"
#include <CreatureLib/Battling/TurnChoices/AttackTurnChoice.hpp>
#include <PkmnLib/Battling/Battle/Battle.hpp>
#include <PkmnLib/Battling/Pokemon/CreatePokemon.hpp>
#include <PkmnLib/Battling/Pokemon/PokemonParty.hpp>
#include <iomanip>
void LearnMove(PkmnLib::Battling::CreatePokemon& c, ArbUt::Random& random,
ArbUt::BorrowedPtr<const CreatureLib::Library::SpeciesVariant> 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<PkmnLib::Battling::PokemonParty> 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<PkmnLib::Battling::Battle>(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<PkmnLib::Battling::Pokemon*>(battle->GetCreature(0, 0).GetValue()));
auto c2 =
aiTwo->GetChoice(battle, static_cast<PkmnLib::Battling::Pokemon*>(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<size_t> 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<std::chrono::milliseconds>((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);
}