From efad9a32a972bf53f6a81b3d5ae8694c358a4625 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Tue, 8 Oct 2024 13:04:35 -0400 Subject: [PATCH] Fix AI tests using PASSES_RANDOMLY (#5486) --- include/test/battle.h | 14 ++++- test/battle/ai/ai_switching.c | 14 +---- test/test_runner_battle.c | 105 +++++++++++++++++----------------- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/include/test/battle.h b/include/test/battle.h index c28410948deb..041ebc1c725b 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -645,6 +645,15 @@ struct AILogLine s16 score; }; +// Data which is updated by the test runner during a battle and needs to +// be reset between trials. +struct BattleTrialData +{ + u8 lastActionTurn; + u8 queuedEvent; + u8 aiActionsPlayed[MAX_BATTLERS_COUNT]; +}; + struct BattleTestData { u8 stack[BATTLE_TEST_STACK_SIZE]; @@ -676,20 +685,19 @@ struct BattleTestData u8 battleRecordSourceLineOffsets[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE]; u16 recordIndexes[MAX_BATTLERS_COUNT]; struct BattlerTurn battleRecordTurns[MAX_TURNS][MAX_BATTLERS_COUNT]; - u8 lastActionTurn; u8 queuedEventsCount; u8 queueGroupType; u8 queueGroupStart; - u8 queuedEvent; struct QueuedEvent queuedEvents[MAX_QUEUED_EVENTS]; u8 expectedAiActionIndex[MAX_BATTLERS_COUNT]; - u8 aiActionsPlayed[MAX_BATTLERS_COUNT]; struct ExpectedAIAction expectedAiActions[MAX_BATTLERS_COUNT][MAX_EXPECTED_ACTIONS]; struct ExpectedAiScore expectedAiScores[MAX_BATTLERS_COUNT][MAX_TURNS][MAX_AI_SCORE_COMPARISION_PER_TURN]; // Max 4 comparisions per turn struct AILogLine aiLogLines[MAX_BATTLERS_COUNT][MAX_MON_MOVES][MAX_AI_LOG_LINES]; u8 aiLogPrintedForMove[MAX_BATTLERS_COUNT]; // Marks ai score log as printed for move, so the same log isn't displayed multiple times. u16 flagId; + + struct BattleTrialData trial; }; struct BattleTestRunnerState diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 3e97ec1f6121..59a6d884935b 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -378,28 +378,18 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if mon would AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to a mon with Wonder Guard 66% of the time") { - u32 aiOmniscientFlag = 0; - PARAMETRIZE { aiOmniscientFlag = 0; } - PARAMETRIZE { aiOmniscientFlag = AI_FLAG_OMNISCIENT; } PASSES_RANDOMLY(66, 100, RNG_AI_SWITCH_WONDER_GUARD); GIVEN { ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG); ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST); ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST); - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiOmniscientFlag); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SHADOW_BALL); } } WHEN { - if(aiOmniscientFlag == 0) { - TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_MOVE(opponent, MOVE_TACKLE); } - TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); } - } - else { - TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); } - } - + TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); } } } diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 6f318bbeadac..c8e4496030b1 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -567,19 +567,19 @@ void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryAbilityPopUp(DATA.queuedEvent, event->groupSize, battlerId, ability) != -1) - DATA.queuedEvent += event->groupSize; + if (TryAbilityPopUp(DATA.trial.queuedEvent, event->groupSize, battlerId, ability) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryAbilityPopUp(queuedEvent, event->groupSize, battlerId, ability)) != -1) @@ -598,7 +598,7 @@ void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability) continue; if (TryAbilityPopUp(queuedEvent, event->groupSize, battlerId, ability) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -630,19 +630,19 @@ void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryAnimation(DATA.queuedEvent, event->groupSize, animType, animId) != -1) - DATA.queuedEvent += event->groupSize; + if (TryAnimation(DATA.trial.queuedEvent, event->groupSize, animType, animId) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryAnimation(queuedEvent, event->groupSize, animType, animId)) != -1) @@ -661,7 +661,7 @@ void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId) continue; if (TryAnimation(queuedEvent, event->groupSize, animType, animId) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -720,19 +720,19 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryHP(DATA.queuedEvent, event->groupSize, battlerId, oldHP, newHP) != -1) - DATA.queuedEvent += event->groupSize; + if (TryHP(DATA.trial.queuedEvent, event->groupSize, battlerId, oldHP, newHP) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryHP(queuedEvent, event->groupSize, battlerId, oldHP, newHP)) != -1) @@ -751,7 +751,7 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP) continue; if (TryHP(queuedEvent, event->groupSize, battlerId, oldHP, newHP) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -782,7 +782,7 @@ static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battl void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target) { const char *filename = gTestRunnerState.test->filename; - u32 id = DATA.aiActionsPlayed[battlerId]; + u32 id = DATA.trial.aiActionsPlayed[battlerId]; struct ExpectedAIAction *expectedAction = &DATA.expectedAiActions[battlerId][id]; if (!expectedAction->actionSet) @@ -845,13 +845,13 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target) } // Turn passed, clear logs from the turn ClearAiLog(battlerId); - DATA.aiActionsPlayed[battlerId]++; + DATA.trial.aiActionsPlayed[battlerId]++; } void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex) { const char *filename = gTestRunnerState.test->filename; - u32 id = DATA.aiActionsPlayed[battlerId]; + u32 id = DATA.trial.aiActionsPlayed[battlerId]; struct ExpectedAIAction *expectedAction = &DATA.expectedAiActions[battlerId][id]; if (!expectedAction->actionSet) @@ -865,7 +865,7 @@ void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex) if (expectedAction->target != partyIndex) Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected partyIndex %d, got %d", filename, expectedAction->sourceLine, expectedAction->target, partyIndex); } - DATA.aiActionsPlayed[battlerId]++; + DATA.trial.aiActionsPlayed[battlerId]++; } void TestRunner_Battle_InvalidNoHPMon(u32 battlerId, u32 partyIndex) @@ -1029,7 +1029,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId) } // We need to make sure that the expected move has the best score. We have to rule out a situation where the expected move is used, but it has the same number of points as some other moves. - aiAction = &DATA.expectedAiActions[battlerId][DATA.aiActionsPlayed[battlerId]]; + aiAction = &DATA.expectedAiActions[battlerId][DATA.trial.aiActionsPlayed[battlerId]]; if (aiAction->actionSet && !aiAction->pass) { s32 target = aiAction->target; @@ -1102,19 +1102,19 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryExp(DATA.queuedEvent, event->groupSize, battlerId, oldExp, newExp) != -1) - DATA.queuedEvent += event->groupSize; + if (TryExp(DATA.trial.queuedEvent, event->groupSize, battlerId, oldExp, newExp) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryExp(queuedEvent, event->groupSize, battlerId, oldExp, newExp)) != -1) @@ -1133,7 +1133,7 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp) continue; if (TryExp(queuedEvent, event->groupSize, battlerId, oldExp, newExp) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -1191,19 +1191,19 @@ void TestRunner_Battle_RecordMessage(const u8 *string) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryMessage(DATA.queuedEvent, event->groupSize, string) != -1) - DATA.queuedEvent += event->groupSize; + if (TryMessage(DATA.trial.queuedEvent, event->groupSize, string) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryMessage(queuedEvent, event->groupSize, string)) != -1) @@ -1222,7 +1222,7 @@ void TestRunner_Battle_RecordMessage(const u8 *string) continue; if (TryMessage(queuedEvent, event->groupSize, string) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -1256,19 +1256,19 @@ void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1) s32 match; struct QueuedEvent *event; - if (DATA.queuedEvent == DATA.queuedEventsCount) + if (DATA.trial.queuedEvent == DATA.queuedEventsCount) return; - event = &DATA.queuedEvents[DATA.queuedEvent]; + event = &DATA.queuedEvents[DATA.trial.queuedEvent]; switch (event->groupType) { case QUEUE_GROUP_NONE: case QUEUE_GROUP_ONE_OF: - if (TryStatus(DATA.queuedEvent, event->groupSize, battlerId, status1) != -1) - DATA.queuedEvent += event->groupSize; + if (TryStatus(DATA.trial.queuedEvent, event->groupSize, battlerId, status1) != -1) + DATA.trial.queuedEvent += event->groupSize; break; case QUEUE_GROUP_NONE_OF: - queuedEvent = DATA.queuedEvent; + queuedEvent = DATA.trial.queuedEvent; do { if ((match = TryStatus(queuedEvent, event->groupSize, battlerId, status1)) != -1) @@ -1287,7 +1287,7 @@ void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1) continue; if (TryStatus(queuedEvent, event->groupSize, battlerId, status1) != -1) - DATA.queuedEvent = queuedEvent + event->groupSize; + DATA.trial.queuedEvent = queuedEvent + event->groupSize; } while (FALSE); break; } @@ -1307,22 +1307,22 @@ void TestRunner_Battle_AfterLastTurn(void) { const struct BattleTest *test = GetBattleTest(); - if (DATA.turns - 1 != DATA.lastActionTurn) + if (DATA.turns - 1 != DATA.trial.lastActionTurn) { const char *filename = gTestRunnerState.test->filename; - Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.lastActionTurn + 1); + Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.trial.lastActionTurn + 1); } - while (DATA.queuedEvent < DATA.queuedEventsCount - && DATA.queuedEvents[DATA.queuedEvent].groupType == QUEUE_GROUP_NONE_OF) + while (DATA.trial.queuedEvent < DATA.queuedEventsCount + && DATA.queuedEvents[DATA.trial.queuedEvent].groupType == QUEUE_GROUP_NONE_OF) { - DATA.queuedEvent += DATA.queuedEvents[DATA.queuedEvent].groupSize; + DATA.trial.queuedEvent += DATA.queuedEvents[DATA.trial.queuedEvent].groupSize; } - if (DATA.queuedEvent != DATA.queuedEventsCount) + if (DATA.trial.queuedEvent != DATA.queuedEventsCount) { const char *filename = gTestRunnerState.test->filename; - u32 line = SourceLine(DATA.queuedEvents[DATA.queuedEvent].sourceLineOffset); - const char *macro = sEventTypeMacros[DATA.queuedEvents[DATA.queuedEvent].type]; + u32 line = SourceLine(DATA.queuedEvents[DATA.trial.queuedEvent].sourceLineOffset); + const char *macro = sEventTypeMacros[DATA.queuedEvents[DATA.trial.queuedEvent].type]; Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Unmatched %s", filename, line, macro); } @@ -1395,8 +1395,7 @@ static void CB2_BattleTest_NextTrial(void) PrintTestName(); gTestRunnerState.result = TEST_RESULT_PASS; DATA.recordedBattle.rngSeed = MakeRngValue(STATE->runTrial); - DATA.queuedEvent = 0; - DATA.lastActionTurn = 0; + memset(&DATA.trial, 0, sizeof(DATA.trial)); SetVariablesForRecordedBattle(&DATA.recordedBattle); SetMainCallback2(CB2_InitBattle); } @@ -1892,7 +1891,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde if (DATA.battleRecordTypes[battlerId][recordIndex] != RECORDED_BYTE) { - DATA.lastActionTurn = gBattleResults.battleTurnCounter; + DATA.trial.lastActionTurn = gBattleResults.battleTurnCounter; if (actionType != DATA.battleRecordTypes[battlerId][recordIndex]) { @@ -1926,7 +1925,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde } else { - if (DATA.lastActionTurn == gBattleResults.battleTurnCounter) + if (DATA.trial.lastActionTurn == gBattleResults.battleTurnCounter) { const char *filename = gTestRunnerState.test->filename; Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: TURN %d incomplete", filename, SourceLine(0), gBattleResults.battleTurnCounter + 1);