Deal with setting targets

This commit is contained in:
2021-08-22 12:06:11 +02:00
parent c9b8e663f8
commit 47a27960a2
5 changed files with 165 additions and 79 deletions

View File

@@ -17,6 +17,27 @@ namespace PkmnLibAI {
NaiveAI _naive;
private:
class SimulatedResult {
public:
std::optional<float> Score;
CreatureLib::Battling::CreatureIndex Target;
SimulatedResult(std::optional<float> score, CreatureLib::Battling::CreatureIndex target)
: Score(score), Target(target) {}
SimulatedResult() {}
};
class ScoredOption {
public:
u8 OptionIndex;
std::optional<float> Score;
CreatureLib::Battling::CreatureIndex Target;
ScoredOption(u8 optionIndex, SimulatedResult result)
: OptionIndex(optionIndex), Score(result.Score), Target(result.Target) {}
ScoredOption() {}
};
float ScoreBattle(PkmnLib::Battling::Battle* battle, PkmnLib::Battling::Pokemon* user) {
auto side = user->GetBattleSide().GetValue();
if (battle->HasEnded()) {
@@ -62,9 +83,9 @@ namespace PkmnLibAI {
}
};
std::vector<std::tuple<u8, float>> ScoreChoicesThreaded(PkmnLib::Battling::Battle* battle,
PkmnLib::Battling::Pokemon* user, uint8_t depth) {
std::vector<std::future<std::tuple<u8, float>>> threadPool;
std::vector<ScoredOption> ScoreChoicesThreaded(PkmnLib::Battling::Battle* battle,
PkmnLib::Battling::Pokemon* user, uint8_t depth) {
std::vector<std::future<ScoredOption>> threadPool;
auto side = user->GetBattleSide().GetValue();
for (u8 moveIndex = 0; moveIndex < (u8)user->GetMoves().Count(); ++moveIndex) {
auto move = user->GetMoves()[moveIndex];
@@ -75,7 +96,7 @@ namespace PkmnLibAI {
continue;
}
threadPool.push_back(std::async([this, battle, side, moveIndex, depth] {
auto v = std::tuple(moveIndex, SimulateTurn(battle, side->GetSideIndex(), 0, moveIndex, depth));
auto v = ScoredOption(moveIndex, SimulateTurn(battle, side->GetSideIndex(), 0, moveIndex, depth));
asThreadCleanup();
return v;
}));
@@ -90,21 +111,21 @@ namespace PkmnLibAI {
continue;
}
threadPool.push_back(std::async([this, battle, side, i, depth] {
auto v = std::tuple((u8)(i + 4), SimulateTurn(battle, side->GetSideIndex(), 0, i + 4, depth));
auto v = ScoredOption((u8)(i + 4), SimulateTurn(battle, side->GetSideIndex(), 0, i + 4, depth));
asThreadCleanup();
return v;
}));
}
std::vector<std::tuple<u8, float>> results(threadPool.size());
std::vector<ScoredOption> results(threadPool.size());
for (size_t i = 0; i < threadPool.size(); ++i) {
results[i] = threadPool[i].get();
}
return results;
}
std::vector<std::tuple<int, float>> ScoreChoices(PkmnLib::Battling::Battle* battle,
PkmnLib::Battling::Pokemon* user, uint8_t depth) {
std::vector<std::tuple<int, float>> scoredMoves;
std::vector<ScoredOption> ScoreChoices(PkmnLib::Battling::Battle* battle, PkmnLib::Battling::Pokemon* user,
uint8_t depth) {
std::vector<ScoredOption> scoredMoves;
auto side = user->GetBattleSide().GetValue();
for (u8 moveIndex = 0; moveIndex < (u8)user->GetMoves().Count(); ++moveIndex) {
auto move = user->GetMoves()[moveIndex];
@@ -133,32 +154,60 @@ namespace PkmnLibAI {
return scoredMoves;
}
float SimulateTurn(PkmnLib::Battling::Battle* originalBattle, u8 sideIndex, u8 pokemonIndex, u8 index,
u8 depth) {
std::optional<CreatureLib::Battling::CreatureIndex>
GetTarget(PkmnLib::Battling::Pokemon* user, ArbUt::BorrowedPtr<const CreatureLib::Library::AttackData> move) {
switch (move->GetTarget()) {
case CreatureLib::Library::AttackTarget::Adjacent: return {};
case CreatureLib::Library::AttackTarget::AdjacentAlly: return {};
case CreatureLib::Library::AttackTarget::AdjacentAllySelf: return user->GetBattleIndex();
case CreatureLib::Library::AttackTarget::AdjacentOpponent: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::All: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::AllAdjacent: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::AllAdjacentOpponent: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::AllAlly: return user->GetBattleIndex();
case CreatureLib::Library::AttackTarget::AllOpponent: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::Any: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::RandomOpponent: return GetOppositeIndex(user);
case CreatureLib::Library::AttackTarget::Self: return user->GetBattleIndex();
}
}
SimulatedResult SimulateTurn(PkmnLib::Battling::Battle* originalBattle, u8 sideIndex, u8 pokemonIndex, u8 index,
u8 depth) {
auto battle = BattlePointerWrapper(originalBattle->Clone());
auto user =
dynamic_cast<PkmnLib::Battling::Pokemon*>(battle->GetCreature(sideIndex, pokemonIndex).GetValue());
auto target = GetOppositeIndex(user);
CreatureLib::Battling::CreatureIndex target;
if (index < 4) {
auto move = user->GetMoves()[index];
if (!move.HasValue()) {
return std::numeric_limits<float>::min();
return {};
}
if (move.GetValue()->GetRemainingUses() <= 0) {
return {};
}
auto targetOption = GetTarget(user, move.GetValue()->GetAttack());
if (!targetOption.has_value()) {
return {};
}
target = targetOption.value();
auto choice = new CreatureLib::Battling::AttackTurnChoice(user, move.GetValue(), target);
if (!battle->TrySetChoice(choice)) {
delete choice;
return std::numeric_limits<float>::min();
return {};
}
} else {
auto mon = battle->GetParties()[sideIndex]->GetParty()->GetParty().At(index - 4);
auto choice = new CreatureLib::Battling::SwitchTurnChoice(user, mon);
if (!battle->TrySetChoice(choice)) {
delete choice;
return std::numeric_limits<float>::min();
return {};
}
}
battle->TrySetChoice(_naive.GetChoice(
battle.Battle, dynamic_cast<PkmnLib::Battling::Pokemon*>(battle->GetCreature(target).GetValue())));
battle.Battle,
dynamic_cast<PkmnLib::Battling::Pokemon*>(battle->GetCreature(GetOppositeIndex(user)).GetValue())));
float score;
if (depth <= 1) {
@@ -168,16 +217,20 @@ namespace PkmnLibAI {
float summedScore = 0;
size_t amount = 0;
for (auto& option : scoredChoices) {
summedScore += std::get<1>(option);
auto v = option.Score;
if (!v.has_value()) {
continue;
}
summedScore += v.value();
amount++;
}
if (amount == 0) {
return std::numeric_limits<float>::min();
return {};
}
score = summedScore / amount;
}
return score;
return SimulatedResult(score, target);
}
public:
@@ -189,25 +242,32 @@ namespace PkmnLibAI {
auto side = user->GetBattleSide().GetValue();
auto& party = battle->GetParties()[side->GetSideIndex()]->GetParty()->GetParty();
auto target = GetOppositeIndex(user);
if (scoredChoices.empty()) {
return battle->GetLibrary()->GetMiscLibrary()->ReplacementAttack(user, target);
return battle->GetLibrary()->GetMiscLibrary()->ReplacementAttack(user, GetOppositeIndex(user));
}
i32 highest = -1;
float highestScore = -std::numeric_limits<float>::infinity();
CreatureLib::Battling::CreatureIndex highestTarget;
for (auto& option : scoredChoices) {
if (std::get<1>(option) > highestScore) {
highestScore = std::get<1>(option);
highest = std::get<0>(option);
auto v = option.Score;
if (!v.has_value()) {
continue;
}
if (v.value() > highestScore) {
highestScore = v.value();
highest = option.OptionIndex;
highestTarget = option.Target;
}
}
if (highest == -1) {
return battle->GetLibrary()->GetMiscLibrary()->ReplacementAttack(user, target);
return battle->GetLibrary()->GetMiscLibrary()->ReplacementAttack(user, GetOppositeIndex(user));
}
if (highest < 4) {
return new CreatureLib::Battling::AttackTurnChoice(user, user->GetMoves()[highest].GetValue(), target);
return new CreatureLib::Battling::AttackTurnChoice(user, user->GetMoves()[highest].GetValue(),
highestTarget);
} else {
return new CreatureLib::Battling::SwitchTurnChoice(user, party.At(highest - 4));
}