Adding a system to compare two AI implementations (AIPlayerBaka and AIPlayerBakaB). This can be used to make sure a change to the AI is not making the AI weaker, for example.
This commit is contained in:
@@ -9,6 +9,12 @@
|
||||
// Instances for Factory
|
||||
#include "AIPlayerBaka.h"
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
#include "AIPlayerBakaB.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
const char * const MTG_LAND_TEXTS[] = { "artifact", "forest", "island", "mountain", "swamp", "plains", "other lands" };
|
||||
|
||||
int AIAction::currentId = 0;
|
||||
@@ -123,6 +129,7 @@ AIPlayer::AIPlayer(string file, string fileSmall, MTGDeck * deck) :
|
||||
agressivity = 50;
|
||||
forceBestAbilityUse = false;
|
||||
playMode = Player::MODE_AI;
|
||||
mFastTimerMode = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -278,5 +285,60 @@ void AIPlayer::Render()
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
AIPlayer * AIPlayerFactory::createAIPlayerTest(MTGAllCards * collection, Player * opponent, int deckid)
|
||||
{
|
||||
char deckFile[512];
|
||||
string avatarFilename; // default imagename
|
||||
char deckFileSmall[512];
|
||||
|
||||
if (deckid == GameStateDuel::MENUITEM_EVIL_TWIN)
|
||||
{ //Evil twin
|
||||
sprintf(deckFile, "%s", opponent->deckFile.c_str());
|
||||
DebugTrace("Evil Twin => " << opponent->deckFile);
|
||||
avatarFilename = "avatar.jpg";
|
||||
sprintf(deckFileSmall, "%s", "ai_baka_eviltwin");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!deckid)
|
||||
{
|
||||
//random deck
|
||||
int nbdecks = 0;
|
||||
int found = 1;
|
||||
while (found && nbdecks < options[Options::AIDECKS_UNLOCKED].number)
|
||||
{
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "ai/baka/deck%i.txt", nbdecks + 1);
|
||||
if (FileExists(buffer))
|
||||
{
|
||||
found = 1;
|
||||
nbdecks++;
|
||||
}
|
||||
}
|
||||
if (!nbdecks)
|
||||
return NULL;
|
||||
deckid = 1 + WRand() % (nbdecks);
|
||||
}
|
||||
sprintf(deckFile, "ai/baka/deck%i.txt", deckid);
|
||||
DeckMetaData *aiMeta = DeckManager::GetInstance()->getDeckMetaDataByFilename( deckFile, true);
|
||||
avatarFilename = aiMeta->getAvatarFilename();
|
||||
sprintf(deckFileSmall, "ai_baka_deck%i", deckid);
|
||||
}
|
||||
|
||||
|
||||
int deckSetting = EASY;
|
||||
if ( opponent )
|
||||
{
|
||||
bool isOpponentAI = opponent->isAI() == 1;
|
||||
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
|
||||
if ( meta->getVictoryPercentage() >= 65)
|
||||
deckSetting = HARD;
|
||||
}
|
||||
|
||||
// AIPlayerBaka will delete MTGDeck when it's time
|
||||
AIPlayerBakaB * baka = NEW AIPlayerBakaB(deckFile, deckFileSmall, avatarFilename, NEW MTGDeck(deckFile, collection,0, deckSetting));
|
||||
baka->deckId = deckid;
|
||||
return baka;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1729,7 +1729,10 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * ty
|
||||
|
||||
void AIPlayerBaka::initTimer()
|
||||
{
|
||||
timer = 0.1f;
|
||||
if (mFastTimerMode)
|
||||
timer = 0;
|
||||
else
|
||||
timer = 0.1f;
|
||||
}
|
||||
|
||||
int AIPlayerBaka::computeActions()
|
||||
@@ -2243,12 +2246,16 @@ int AIPlayerBaka::Act(float dt)
|
||||
|
||||
oldGamePhase = currentGamePhase;
|
||||
|
||||
timer -= dt;
|
||||
if (mFastTimerMode)
|
||||
timer -= 1;
|
||||
else
|
||||
timer -= dt;
|
||||
if (timer > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
initTimer();
|
||||
|
||||
if (combatDamages())
|
||||
{
|
||||
return 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -84,6 +84,27 @@ GameState(parent, "duel")
|
||||
testSuite = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
totalTestGames = 0;
|
||||
testPlayer2Victories = 0;
|
||||
totalAIDecks = 0;
|
||||
{
|
||||
int found = 1;
|
||||
while (found)
|
||||
{
|
||||
found = 0;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "ai/baka/deck%i.txt", totalAIDecks + 1);
|
||||
if (FileExists(buffer))
|
||||
{
|
||||
found = 1;
|
||||
totalAIDecks++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
credits = NULL;
|
||||
|
||||
#ifdef NETWORK_SUPPORT
|
||||
@@ -216,7 +237,17 @@ void GameStateDuel::loadPlayer(int playerId, int decknb, bool isAI, bool isNetwo
|
||||
AIPlayerFactory playerCreator;
|
||||
Player * opponent = NULL;
|
||||
if (playerId == 1) opponent = mPlayers[0];
|
||||
mPlayers[playerId] = playerCreator.createAIPlayer(MTGCollection(), opponent);
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
if (mParent->players[1] == PLAYER_TYPE_CPU_TEST && playerId == 1)
|
||||
mPlayers[playerId] = playerCreator.createAIPlayerTest(MTGCollection(), opponent);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mPlayers[playerId] = playerCreator.createAIPlayer(MTGCollection(), opponent);
|
||||
}
|
||||
|
||||
if (mParent->players[playerId] == PLAYER_TYPE_CPU_TEST)
|
||||
((AIPlayer *) mPlayers[playerId])->setFastTimerMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,11 +510,21 @@ void GameStateDuel::Update(float dt)
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU)
|
||||
{
|
||||
End();
|
||||
Start();
|
||||
}
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
if (mParent->players[0] == PLAYER_TYPE_CPU_TEST && mParent->players[1] == PLAYER_TYPE_CPU_TEST)
|
||||
{
|
||||
totalTestGames++;
|
||||
if (game->gameOver == game->players[0])
|
||||
testPlayer2Victories++;
|
||||
End();
|
||||
Start();
|
||||
}
|
||||
#endif
|
||||
if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU)
|
||||
{
|
||||
End();
|
||||
Start();
|
||||
}
|
||||
}
|
||||
if (mEngine->GetButtonClick(JGE_BTN_MENU))
|
||||
{
|
||||
@@ -571,6 +612,29 @@ void GameStateDuel::Render()
|
||||
|
||||
if (game) game->Render();
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
if (game && totalTestGames)
|
||||
{
|
||||
char buf[4096];
|
||||
|
||||
if (totalTestGames < 2.5 * totalAIDecks)
|
||||
{
|
||||
mFont->SetColor(ARGB(255,255,255,0));
|
||||
sprintf(buf, "Results are not significant, you should let at least %i more games run", totalAIDecks * 2.5 - totalTestGames);
|
||||
mFont->DrawString(buf,0,SCREEN_HEIGHT/2 - 20);
|
||||
}
|
||||
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
float ratio = float(testPlayer2Victories) / float(totalTestGames);
|
||||
if (ratio < 0.48)
|
||||
mFont->SetColor(ARGB(255,255,0,0));
|
||||
if (ratio > 0.52)
|
||||
mFont->SetColor(ARGB(255,0,255,0));
|
||||
sprintf(buf, "Victories Player 2/total Games: %i/%i", testPlayer2Victories, totalTestGames);
|
||||
mFont->DrawString(buf,0,SCREEN_HEIGHT/2);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (mGamePhase)
|
||||
{
|
||||
case DUEL_STATE_END:
|
||||
|
||||
@@ -801,6 +801,10 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
|
||||
if (Rules::getRulesByFilename("testsuite.txt"))
|
||||
subMenuController->Add(SUBMENUITEM_TESTSUITE, "Test Suite");
|
||||
#endif
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
subMenuController->Add(SUBMENUITEM_TESTAI, "AI A/B Testing");
|
||||
#endif
|
||||
currentState = MENU_STATE_MAJOR_SUBMENU | MENU_STATE_MINOR_NONE;
|
||||
}
|
||||
break;
|
||||
@@ -877,7 +881,16 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
|
||||
#endif //NETWORK_SUPPORT
|
||||
currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING;
|
||||
break;
|
||||
|
||||
#ifdef AI_CHANGE_TESTING
|
||||
case SUBMENUITEM_TESTAI:
|
||||
options[Options::AIDECKS_UNLOCKED].number = 5000; //hack to force-test all decks
|
||||
mParent->players[0] = PLAYER_TYPE_CPU_TEST;
|
||||
mParent->players[1] = PLAYER_TYPE_CPU_TEST;
|
||||
mParent->gameType = GAME_TYPE_DEMO;
|
||||
subMenuController->Close();
|
||||
currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING;
|
||||
break;
|
||||
#endif
|
||||
#ifdef TESTSUITE
|
||||
case SUBMENUITEM_TESTSUITE:
|
||||
mParent->rules = Rules::getRulesByFilename("testsuite.txt");
|
||||
|
||||
Reference in New Issue
Block a user