diff --git a/projects/mtg/bin/Res/test/thallid.txt b/projects/mtg/bin/Res/test/thallid.txt index ea5ad9aae..ee0cf151b 100644 --- a/projects/mtg/bin/Res/test/thallid.txt +++ b/projects/mtg/bin/Res/test/thallid.txt @@ -1,7 +1,8 @@ [INIT] UNTAP [PLAYER1] -inplay:Thallid +#1924 is thallid, we use the id to be sure to match the token in the end +inplay:1924 [PLAYER2] [DO] eot @@ -13,11 +14,11 @@ eot next next next -thallid -thallid +1924 +1924 [ASSERT] FIRSTMAIN [PLAYER1] -inplay:Thallid,-1924 +inplay:1924,-1924 [PLAYER2] [END] diff --git a/projects/mtg/include/AIPlayer.h b/projects/mtg/include/AIPlayer.h index b25416c40..dff566b86 100644 --- a/projects/mtg/include/AIPlayer.h +++ b/projects/mtg/include/AIPlayer.h @@ -107,7 +107,7 @@ class AIPlayerFactory{ public: AIPlayer * createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid = 0); #ifdef AI_CHANGE_TESTING - AIPlayer * createAIPlayerTest(MTGAllCards * collection, Player * opponent, int deckid = 0); + AIPlayer * createAIPlayerTest(MTGAllCards * collection, Player * opponent, string folder); #endif }; diff --git a/projects/mtg/include/ActionStack.h b/projects/mtg/include/ActionStack.h index 461cb6af7..62b089026 100644 --- a/projects/mtg/include/ActionStack.h +++ b/projects/mtg/include/ActionStack.h @@ -210,7 +210,7 @@ public: Player * lastActionController; int setIsInterrupting(Player * player); int count( int type = 0 , int state = 0 , int display = -1); - int getActionElementFromCard(MTGCardInstance * card); + Interruptible * getActionElementFromCard(MTGCardInstance * card); Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1); int getPreviousIndex(Interruptible * next, int type = 0, int state = 0 , int display = -1); Interruptible * getNext(Interruptible * previous, int type = 0, int state = 0 , int display = -1); diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 10bb5ecbc..0b7729971 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -37,12 +37,9 @@ public: if (card) return card->X; return 1; //this should only hapen when the ai calls the ability. This is to give it an idea of the "direction" of X (positive/negative) } - WParsedInt(int value = 0) - { - intValue = value; - } - WParsedInt(string s, Spell * spell, MTGCardInstance * card) +private: + void init(string s, Spell * spell, MTGCardInstance * card) { if(!card) return; @@ -73,8 +70,7 @@ public: } if(s == "prex") { - ManaCost * cX = NEW ManaCost(card->controller()->getManaPool()->Diff(card->getManaCost())); - int preX = + ManaCost * cX = card->controller()->getManaPool()->Diff(card->getManaCost()); intValue = cX->getCost(Constants::MTG_NB_COLORS); delete cX; } @@ -220,6 +216,22 @@ public: } intValue *= multiplier; } +public: + + WParsedInt(int value = 0) + { + intValue = value; + } + + WParsedInt(string s, Spell * spell, MTGCardInstance * card) + { + init(s, spell, card); + } + + WParsedInt(string s, MTGCardInstance * card) + { + init(s, NULL, card); + } int getValue() { diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index 0ce182d11..62ade5a27 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -119,6 +119,11 @@ public: map primitives; MTGCard * _(int id); MTGCard * getCardById(int id); + +#ifdef TESTSUITE + void prefetchCardNameCache(); +#endif + MTGCard * getCardByName(string name); int load(const char * config_file, const char * setName = NULL, int autoload = 1); int countByType(const char * _type); diff --git a/projects/mtg/include/TestSuiteAI.h b/projects/mtg/include/TestSuiteAI.h index ce21d7a37..05cb35c72 100644 --- a/projects/mtg/include/TestSuiteAI.h +++ b/projects/mtg/include/TestSuiteAI.h @@ -68,6 +68,7 @@ private: bool forceAbility; int summoningSickness; + int load(const char * filename); void cleanup(); @@ -84,6 +85,7 @@ public: int assertGame(); public: + int startTime, endTime; int gameType; unsigned int seed; int nbFailed, nbTests, nbAIFailed, nbAITests; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 1e827b78f..fa7238a5d 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -286,46 +286,44 @@ void AIPlayer::Render() } #ifdef AI_CHANGE_TESTING -AIPlayer * AIPlayerFactory::createAIPlayerTest(MTGAllCards * collection, Player * opponent, int deckid) +AIPlayer * AIPlayerFactory::createAIPlayerTest(MTGAllCards * collection, Player * opponent, string _folder) { 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 + + + string folder = _folder.size() ? _folder : "ai/baka/"; + + int deckid = 0; + + //random deck + int nbdecks = 0; + int found = 1; + while (found && nbdecks < options[Options::AIDECKS_UNLOCKED].number) { - if (!deckid) + found = 0; + char buffer[512]; + sprintf(buffer, "%sdeck%i.txt", folder.c_str(), nbdecks + 1); + if (FileExists(buffer)) { - //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); + found = 1; + 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); } + if (!nbdecks) + { + if (_folder.size()) + return createAIPlayerTest(collection, opponent, ""); + return NULL; + } + deckid = 1 + WRand() % (nbdecks); + + sprintf(deckFile, "%sdeck%i.txt", folder.c_str(), deckid); + DeckMetaData *aiMeta = DeckManager::GetInstance()->getDeckMetaDataByFilename( deckFile, true); + avatarFilename = aiMeta->getAvatarFilename(); + sprintf(deckFileSmall, "ai_baka_deck%i", deckid); + int deckSetting = EASY; if ( opponent ) @@ -337,7 +335,9 @@ AIPlayer * AIPlayerFactory::createAIPlayerTest(MTGAllCards * collection, Player } // AIPlayerBaka will delete MTGDeck when it's time - AIPlayerBakaB * baka = NEW AIPlayerBakaB(deckFile, deckFileSmall, avatarFilename, NEW MTGDeck(deckFile, collection,0, deckSetting)); + AIPlayerBaka * baka = opponent ? + NEW AIPlayerBakaB(deckFile, deckFileSmall, avatarFilename, NEW MTGDeck(deckFile, collection,0, deckSetting)) : + NEW AIPlayerBaka(deckFile, deckFileSmall, avatarFilename, NEW MTGDeck(deckFile, collection,0, deckSetting)); baka->deckId = deckid; return baka; } diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index abf968fa8..5b02a68b8 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -1754,10 +1754,8 @@ int AIPlayerBaka::computeActions() return 0; } Interruptible * action = g->mLayers->stackLayer()->getAt(-1); - Spell * spell = (Spell *) action; - Player * lastStackActionController = NULL; - if(spell && spell->type == ACTION_SPELL) - lastStackActionController = spell->source->controller(); + Spell * spell = dynamic_cast(action); + Player * lastStackActionController = spell ? spell->source->controller() : NULL; if (g->isInterrupting == this && this == currentP //and i am the currentlyActivePlayer diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 68e690077..4f300e408 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -243,7 +243,7 @@ Interruptible(id), tc(tc), cost(_cost), payResult(payResult) int Spell::computeX(MTGCardInstance * card) { - ManaCost * c = NEW ManaCost(cost->Diff(card->getManaCost())); + ManaCost * c = cost->Diff(card->getManaCost()); int x = c->getCost(Constants::MTG_NB_COLORS); delete c; return x; @@ -763,7 +763,7 @@ int ActionStack::count(int type, int state, int display) return result; } -int ActionStack::getActionElementFromCard(MTGCardInstance * card) +Interruptible * ActionStack::getActionElementFromCard(MTGCardInstance * card) { if(!card) @@ -773,10 +773,10 @@ int ActionStack::getActionElementFromCard(MTGCardInstance * card) Interruptible * current = (Interruptible *) mObjects[i]; if (current->source == card) { - return i; + return current; } } - return 0; + return NULL; } Interruptible * ActionStack::getNext(Interruptible * previous, int type, int state, int display) diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 6780486ae..f6a4eb911 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -416,7 +416,7 @@ ACounterShroud::~ACounterShroud() SAFE_DELETE(counter); } -//sheild a card from a certain type of counter. +//shield a card from a certain type of counter. ACounterTracker::ACounterTracker(int id, MTGCardInstance * source, MTGCardInstance * target, string scounter) : MTGAbility(id, source, target),scounter(scounter) { @@ -428,7 +428,7 @@ int ACounterTracker::addToGame() MTGCardInstance * _target = (MTGCardInstance*)target; Counter * counter = NULL; AbilityFactory af; - counter = af.parseCounter(scounter, _target, (Spell*)source); + counter = af.parseCounter(scounter, _target, NULL); //(Spell*)source); if (!counter) { return 0; @@ -455,7 +455,7 @@ int ACounterTracker::destroy() MTGCardInstance * _target = (MTGCardInstance*)target; Counter * counter = NULL; AbilityFactory af; - counter = af.parseCounter(scounter, _target, (Spell*)source); + counter = af.parseCounter(scounter, _target, NULL); //(Spell*)source); if (!counter) { return 0; @@ -665,12 +665,12 @@ int AAFizzler::resolve() if(!target && source->target) { //ai is casting a spell from it's hand to fizzle. - target = stack->getAt(stack->getActionElementFromCard(source->target)); + target = stack->getActionElementFromCard(source->target); } else if(target->typeAsTarget() == TARGET_CARD) { //ai targeted using an ability on a card to fizzle. - target = stack->getAt(stack->getActionElementFromCard((MTGCardInstance*)target)); + target = stack->getActionElementFromCard((MTGCardInstance*)target); } Spell * sTarget = (Spell *) target; MTGCardInstance* sCard = (MTGCardInstance*)sTarget->source; diff --git a/projects/mtg/src/Credits.cpp b/projects/mtg/src/Credits.cpp index 8308a9f07..9ef3ffb0a 100644 --- a/projects/mtg/src/Credits.cpp +++ b/projects/mtg/src/Credits.cpp @@ -48,8 +48,13 @@ void Credits::compute(Player * _p1, Player * _p2, GameApp * _app) GameObserver * g = GameObserver::GetInstance(); if (!g->turn) return; + + //no credits when the AI plays :) + if (p1->isAI()) + return; + PlayerData * playerdata = NEW PlayerData(MTGCollection()); - if (!p1->isAI() && p2->isAI() && p1 != g->gameOver) + if (p2->isAI() && p1 != g->gameOver) { gameLength = time(0) - g->startedAt; value = 400; diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index e4ef7fa6e..91efefc1c 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -238,8 +238,8 @@ void GameStateDuel::loadPlayer(int playerId, int decknb, bool isAI, bool isNetwo Player * opponent = NULL; if (playerId == 1) opponent = mPlayers[0]; #ifdef AI_CHANGE_TESTING - if (mParent->players[1] == PLAYER_TYPE_CPU_TEST && playerId == 1) - mPlayers[playerId] = playerCreator.createAIPlayerTest(MTGCollection(), opponent); + if (mParent->players[0] == PLAYER_TYPE_CPU_TEST) + mPlayers[playerId] = playerCreator.createAIPlayerTest(MTGCollection(), opponent, playerId == 0 ? "ai/bakaA/" : "ai/bakaB/"); else #endif { @@ -646,6 +646,12 @@ void GameStateDuel::Render() { r->ClearScreen(ARGB(255,0,0,0)); char buf[4096]; + mFont->SetColor(ARGB(255,255,255,255)); + + int elapsedTime = (testSuite->endTime - testSuite->startTime); + sprintf(buf, "Time to run the tests: %is", elapsedTime/1000); + mFont->DrawString(buf,0,SCREEN_HEIGHT/2 - 20); + int nbFailed = testSuite->nbFailed; int nbTests = testSuite->nbTests; if (!nbFailed) @@ -656,7 +662,7 @@ void GameStateDuel::Render() { sprintf(buf, "%i tests out of %i FAILED!", nbFailed, nbTests); } - mFont->SetColor(ARGB(255,255,255,255)); + mFont->DrawString(buf,0,SCREEN_HEIGHT/2); nbFailed = testSuite->nbAIFailed; nbTests = testSuite->nbAITests; diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index edf8549eb..6b823ede8 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -590,39 +590,75 @@ MTGCard * MTGAllCards::_(int index) return getCardById(ids[index]); } -MTGCard * MTGAllCards::getCardByName(string name) +#ifdef TESTSUITE +void MTGAllCards::prefetchCardNameCache() { - if (!name.size()) return NULL; - if (name[0] == '#') return NULL; + map::iterator it; + for (it = collection.begin(); it != collection.end(); it++) + { + MTGCard * c = it->second; - map::iterator cached = mtgCardByNameCache.end(); - if (mtgCardByNameCache.size() > 0) - cached = mtgCardByNameCache.find(name); + //Name only + string cardName = c->data->name; + std::transform(cardName.begin(), cardName.end(), cardName.begin(), ::tolower); + mtgCardByNameCache[cardName] = c; + + //Name + set + int setId = c->setId; + MTGSetInfo* setInfo = setlist.getInfo(setId); + if (setInfo) + { + string setName = setInfo->getName(); + std::transform(setName.begin(), setName.end(), setName.begin(), ::tolower); + cardName = cardName + " (" + setName + ")"; + mtgCardByNameCache[cardName] = c; + } + + // id + std::stringstream out; + out << c->getMTGId(); + mtgCardByNameCache[out.str()] = c; + } +} +#endif + +MTGCard * MTGAllCards::getCardByName(string nameDescriptor) +{ + if (!nameDescriptor.size()) return NULL; + if (nameDescriptor[0] == '#') return NULL; + + std::transform(nameDescriptor.begin(), nameDescriptor.end(), nameDescriptor.begin(), ::tolower); + + map::iterator cached = mtgCardByNameCache.find(nameDescriptor); if (cached!= mtgCardByNameCache.end()) { return cached->second; } - int cardnb = atoi(name.c_str()); + int cardnb = atoi(nameDescriptor.c_str()); if (cardnb) { MTGCard * result = getCardById(cardnb); - mtgCardByNameCache[name] = result; + mtgCardByNameCache[nameDescriptor] = result; return result; } - std::transform(name.begin(), name.end(), name.begin(), ::tolower); int setId = -1; - size_t found = name.find(" ("); + size_t found = nameDescriptor.find(" ("); + string name = nameDescriptor; if (found != string::npos) { - size_t end = name.find(")"); - string setName = name.substr(found + 2, end - found - 2); + size_t end = nameDescriptor.find(")"); + string setName = nameDescriptor.substr(found + 2, end - found - 2); trim(setName); - name = name.substr(0, found); + name = nameDescriptor.substr(0, found); trim(name); setId = setlist[setName]; + + //Reconstruct a clean string "name (set)" for cache consistency + nameDescriptor = name + " (" + setName + ")"; + } map::iterator it; for (it = collection.begin(); it != collection.end(); it++) @@ -632,12 +668,12 @@ MTGCard * MTGAllCards::getCardByName(string name) string cardName = c->data->name; std::transform(cardName.begin(), cardName.end(), cardName.begin(), ::tolower); if (cardName.compare(name) == 0) { - mtgCardByNameCache[name] = c; + mtgCardByNameCache[nameDescriptor] = c; return c; } } - mtgCardByNameCache[name] = NULL; + mtgCardByNameCache[nameDescriptor] = NULL; return NULL; } diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index 0842b649d..de6adb298 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -180,11 +180,19 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta { targetMin = true;//if upto: is not found, then we need to have a minimum of the amount.... } - WParsedInt * howmuch = NEW WParsedInt(howmany, NULL, card); - howmany.find("anyamount") != string::npos?maxtargets = TargetChooser::UNLITMITED_TARGETS:maxtargets = howmuch->getValue(); - if(howmany.find("anyamount") != string::npos) + + if (howmany.find("anyamount") != string::npos) + { + maxtargets = TargetChooser::UNLITMITED_TARGETS; targetMin = false; - delete howmuch; + } + else + { + WParsedInt * howmuch = NEW WParsedInt(howmany, NULL, card); + maxtargets = howmuch->getValue(); + delete howmuch; + } + s1 = s1.substr(end + 1); } } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index 772911e2b..671196af0 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -566,7 +566,8 @@ TestSuite::TestSuite(const char * filename) seed = 0; forceAbility = false; aiMaxCalls = -1; - + startTime = JGEGetTime(); + endTime = startTime; std::string contents; if (JFileSystem::GetInstance()->readIntoString(filename, contents)) { @@ -585,6 +586,11 @@ TestSuite::TestSuite(const char * filename) } } + //If more than 1 test, prefecth names to make the suite run faster + if (nbfiles > 1) + MTGCollection()->prefetchCardNameCache(); + + ofstream file2; if (JFileSystem::GetInstance()->openForWrite(file2, "/test/results.html")) { @@ -603,6 +609,7 @@ TestSuite::TestSuite(const char * filename) int TestSuite::loadNext() { + endTime = JGEGetTime(); summoningSickness = 0; seed = 0; aiMaxCalls = -1; @@ -613,8 +620,6 @@ int TestSuite::loadNext() return loadNext(); else cout << "Starting test : " << files[currentfile - 1] << endl; - //load(files[currentfile].c_str()); - //currentfile++; return currentfile; }