diff --git a/JGE/Dependencies/lib/libjpeg-static-mt-debug.pdb b/JGE/Dependencies/lib/libjpeg-static-mt-debug.pdb deleted file mode 100644 index 5e7dbba29..000000000 Binary files a/JGE/Dependencies/lib/libjpeg-static-mt-debug.pdb and /dev/null differ diff --git a/JGE/Dependencies/lib/libjpeg-static-mt.pdb b/JGE/Dependencies/lib/libjpeg-static-mt.pdb deleted file mode 100644 index 0c108332a..000000000 Binary files a/JGE/Dependencies/lib/libjpeg-static-mt.pdb and /dev/null differ diff --git a/projects/mtg/include/AIHints.h b/projects/mtg/include/AIHints.h index b5014725e..99d9975b3 100644 --- a/projects/mtg/include/AIHints.h +++ b/projects/mtg/include/AIHints.h @@ -12,6 +12,8 @@ using std::vector; class ManaCost; class MTGAbility; +namespace AI { + class AIHint { public: @@ -66,4 +68,6 @@ public: ~AIHints(); }; +}; + #endif diff --git a/projects/mtg/include/AIMomirPlayer.h b/projects/mtg/include/AIMomirPlayer.h index 07526778f..c32a0200e 100644 --- a/projects/mtg/include/AIMomirPlayer.h +++ b/projects/mtg/include/AIMomirPlayer.h @@ -3,6 +3,8 @@ #include "AIPlayerBaka.h" +namespace AI { + class AIMomirPlayer: public AIPlayerBaka { public: @@ -14,4 +16,6 @@ public: MTGAbility * getMomirAbility(); }; +}; + #endif diff --git a/projects/mtg/include/AIPlayer.h b/projects/mtg/include/AIPlayer.h index 01a029fae..563620a01 100644 --- a/projects/mtg/include/AIPlayer.h +++ b/projects/mtg/include/AIPlayer.h @@ -18,20 +18,44 @@ #include "Player.h" #include "config.h" +#include #include using std::queue; +using std::vector; + + +namespace AI { class AIStats; class AIPlayer; + +class Action +{ +protected: + GameObserver* m_pObserver; + bool parseLine(const string& s); + +public: + Action(GameObserver* g, const string& s) : m_pObserver(g) + { + parseLine(s); + }; + + friend ostream& operator<<(ostream&, const Action&); + friend istream& operator>>(istream&, Action&); +}; + class AIAction { +protected: + int clickMultiAct(vector&actionTargets); + public: AIPlayer * owner; MTGAbility * ability; - NestedAbility * nability; Player * player; - int id; +// int id; MTGCardInstance * click; MTGCardInstance * target; // TODO Improve vectormAbilityTargets; @@ -60,7 +84,6 @@ public: { }; int Act(); - int clickMultiAct(vector&actionTargets); }; @@ -77,8 +100,20 @@ protected: int clickMultiTarget(TargetChooser * tc,vector&potentialTargets); int clickSingleTarget(TargetChooser * tc,vector&potentialTargets, MTGCardInstance * Choosencard = NULL); RandomGenerator randomGenerator; + virtual bool canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); + virtual bool canPlay(MTGCardInstance * card); + virtual int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0); + + virtual int createAbilityPotentialsActions(MTGAbility * a, MTGCardInstance * c, vector& actions); public: + enum { + INFO_NBCREATURES, + INFO_CREATURESPOWER, + INFO_CREATURESRANK, + INFO_CREATURESTOUGHNESS, + INFO_CREATURESATTACKINGPOWER + }; //These variables are used by TestSuite and Rules.cpp... TODO change that? int agressivity; @@ -89,7 +124,7 @@ public: virtual int receiveEvent(WEvent * event); virtual void Render(); - AIPlayer(GameObserver *observer, string deckFile, string deckFileSmall, MTGDeck * deck = NULL); + AIPlayer(GameObserver *observer, string deckFile, string deckFileSmall, string avatarFile, MTGDeck * deck = NULL); virtual ~AIPlayer(); virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget = NULL, MTGCardInstance * Chosencard = NULL, bool checkonly = false) = 0; @@ -116,5 +151,6 @@ class AIPlayerFactory{ #endif }; +} #endif diff --git a/projects/mtg/include/AIPlayerBaka.h b/projects/mtg/include/AIPlayerBaka.h index 65816c015..ccdae3e17 100644 --- a/projects/mtg/include/AIPlayerBaka.h +++ b/projects/mtg/include/AIPlayerBaka.h @@ -4,6 +4,8 @@ #include "AIPlayer.h" #include "AllAbilities.h" +namespace AI { + class AIStats; class AIHints; class AIHint; @@ -57,7 +59,7 @@ public: OrderedAIAction* a2Ptr = const_cast(&a2); int e1 = a1Ptr->getEfficiency(); int e2 = a2Ptr->getEfficiency(); - if (e1 == e2) return a1Ptr->id < a2Ptr->id; +// if (e1 == e2) return a1Ptr->id < a2Ptr->id; return (e1 > e2); } }; @@ -72,7 +74,7 @@ class AIPlayerBaka: public AIPlayer{ virtual int interruptIfICan(); virtual int chooseAttackers(); virtual int chooseBlockers(); - virtual int canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); + virtual bool canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); virtual int effectBadOrGood(MTGCardInstance * card, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL); @@ -105,19 +107,10 @@ class AIPlayerBaka: public AIPlayer{ virtual int getEfficiency(OrderedAIAction * action); virtual int getEfficiency(MTGAbility * ability); virtual bool payTheManaCost(ManaCost * cost, MTGCardInstance * card = NULL,vector gotPayment = vector()); - virtual int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0); virtual ManaCost * getPotentialMana(MTGCardInstance * card = NULL); virtual int selectAbility(); public: - enum { - INFO_NBCREATURES, - INFO_CREATURESPOWER, - INFO_CREATURESRANK, - INFO_CREATURESTOUGHNESS, - INFO_CREATURESATTACKINGPOWER - }; - vectorgotPayments; AIPlayerBaka(GameObserver *observer, string deckFile, string deckfileSmall, string avatarFile, MTGDeck * deck = NULL); @@ -137,4 +130,5 @@ class AIPlayerBaka: public AIPlayer{ virtual int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingContainer& ranking); }; +} #endif diff --git a/projects/mtg/include/AIPlayerBakaB.h b/projects/mtg/include/AIPlayerBakaB.h index 8943578d0..ee04b9ebf 100644 --- a/projects/mtg/include/AIPlayerBakaB.h +++ b/projects/mtg/include/AIPlayerBakaB.h @@ -11,6 +11,8 @@ class AIStats; class AIHints; +namespace AI { + class AIPlayerBakaB: public AIPlayerBaka{ protected: int orderBlockers(); @@ -18,7 +20,7 @@ protected: int interruptIfICan(); int chooseAttackers(); int chooseBlockers(); - int canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); + bool canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); int effectBadOrGood(MTGCardInstance * card, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL); @@ -61,6 +63,8 @@ protected: int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingContainer& ranking); }; +}; + #endif #endif diff --git a/projects/mtg/include/AIPlayerMinMax.h b/projects/mtg/include/AIPlayerMinMax.h new file mode 100644 index 000000000..8c10814bb --- /dev/null +++ b/projects/mtg/include/AIPlayerMinMax.h @@ -0,0 +1,34 @@ +/* + * Wagic, The Homebrew ?! is licensed under the BSD license + * See LICENSE in the Folder's root + * http://wololo.net/wagic/ + + AIPlayerMinMax is the MinMax implementation of the AIPlayer interface + */ + +#ifndef _IAPLAYER_MINMAX_H +#define _IAPLAYER_MINMAX_H + +#include "AIPlayer.h" +#include "config.h" + +namespace AI { + +class AIPlayerMinMax: public AIPlayer{ + +protected: + void LookAround(); + +public: + AIPlayerMinMax(GameObserver *observer, string deckFile, string deckFileSmall, string avatarFile, MTGDeck * deck = NULL); + virtual ~AIPlayerMinMax(); + + virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget = NULL, MTGCardInstance * Chosencard = NULL, bool checkonly = false) = 0; + virtual int affectCombatDamages(CombatStep) = 0; + virtual int Act(float dt) = 0; + +}; + +}; + +#endif diff --git a/projects/mtg/include/AIStats.h b/projects/mtg/include/AIStats.h index 744988dce..cf6cd1692 100644 --- a/projects/mtg/include/AIStats.h +++ b/projects/mtg/include/AIStats.h @@ -18,6 +18,8 @@ class MTGCard; class Damage; class WEvent; +namespace AI { + class AIStat { public: @@ -49,4 +51,6 @@ public: void Render(); }; +}; + #endif diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index 281e742ba..01f51eea0 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -111,6 +111,7 @@ class GameObserver{ void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); virtual void loadPlayer(int playerId, Player* player); + int getPlayerId(Player* player) {if(player == players[0]) return 1; else if(player == players[1]) return 2; else return 0;}; Player * currentPlayer; Player * currentActionPlayer; Player * isInterrupting; diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 099b24604..eb52fd516 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -105,7 +105,7 @@ public: std::string GetCurrentDeckStatsFile(); virtual bool parseLine(const string& s); friend ostream& operator<<(ostream&, const Player&); - friend istream& operator>>(istream&, Player&); + friend istream& operator>>(istream&, Player&); bool operator<(Player& aPlayer); bool isDead(); }; diff --git a/projects/mtg/include/TestSuiteAI.h b/projects/mtg/include/TestSuiteAI.h index 6e33055ed..c90a966e4 100644 --- a/projects/mtg/include/TestSuiteAI.h +++ b/projects/mtg/include/TestSuiteAI.h @@ -114,7 +114,7 @@ public: int run(); }; -class TestSuiteAI:public AIPlayerBaka +class TestSuiteAI:public AI::AIPlayerBaka { private: MTGCardInstance * getCard(string action); diff --git a/projects/mtg/src/AIHints.cpp b/projects/mtg/src/AIHints.cpp index f61686598..434415d2b 100644 --- a/projects/mtg/src/AIHints.cpp +++ b/projects/mtg/src/AIHints.cpp @@ -7,6 +7,8 @@ #include +namespace AI { + AIHint::AIHint(string _line) { string line = _line; @@ -584,3 +586,5 @@ AIAction * AIHints::suggestAbility(ManaCost * potentialMana) } return NULL; } + +}; \ No newline at end of file diff --git a/projects/mtg/src/AIMomirPlayer.cpp b/projects/mtg/src/AIMomirPlayer.cpp index 0d7e741a5..05b0435b3 100644 --- a/projects/mtg/src/AIMomirPlayer.cpp +++ b/projects/mtg/src/AIMomirPlayer.cpp @@ -6,6 +6,8 @@ #include "AIStats.h" #include "AllAbilities.h" +namespace AI { + AIMomirPlayer::AIMomirPlayer(GameObserver *observer, string file, string fileSmall, string avatarFile, MTGDeck * deck) : AIPlayerBaka(observer, file, fileSmall, avatarFile, deck) { @@ -132,3 +134,4 @@ int AIMomirPlayer::computeActions() return AIPlayerBaka::computeActions(); } +}; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 1c911af9d..29978ff85 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -13,11 +13,36 @@ #include "AIPlayerBakaB.h" #endif +namespace AI { + + +bool Action::parseLine(const string& s) +{ + return true; +} + +ostream& operator<<(ostream& out, const Action&) +{ + return out; +} + +istream& operator>>(istream& in, Action& a) +{ + string s; + + while(std::getline(in, s)) + { + if(!a.parseLine(s)) + { + break; + } + } + + return in; +} int AIPlayer::totalAIDecks = -1; -const char * const MTG_LAND_TEXTS[] = { "artifact", "forest", "island", "mountain", "swamp", "plains", "other lands" }; - AIAction::AIAction(AIPlayer * owner, MTGCardInstance * c, MTGCardInstance * t) : owner(owner), ability(NULL), player(NULL), click(c), target(t) { @@ -116,7 +141,7 @@ int AIAction::clickMultiAct(vector& actionTargets) return 1; } -AIPlayer::AIPlayer(GameObserver *observer, string file, string fileSmall, MTGDeck * deck) : +AIPlayer::AIPlayer(GameObserver *observer, string file, string fileSmall, string avatarFile, MTGDeck * deck) : Player(observer, file, fileSmall, deck) { agressivity = 50; @@ -124,6 +149,33 @@ AIPlayer::AIPlayer(GameObserver *observer, string file, string fileSmall, MTGDec playMode = Player::MODE_AI; mFastTimerMode = false; + if(avatarFile != "") + { + if(!loadAvatar(avatarFile, "bakaAvatar")) + { + avatarFile = "baka.jpg"; + loadAvatar(avatarFile, "bakaAvatar"); + } + mAvatarName = avatarFile; + } + else //load a random avatar. + { + avatarFile = "avatar"; + char buffer[3]; + sprintf(buffer, "%i", int(observer->getRandomGenerator()->random()%100)); + avatarFile.append(buffer); + avatarFile.append(".jpg"); + if(!loadAvatar(avatarFile, "bakaAvatar")) + { + avatarFile = "baka.jpg"; + loadAvatar(avatarFile, "bakaAvatar"); + } + mAvatarName = avatarFile; + } + + if (fileSmall == "ai_baka_eviltwin") + mAvatar->SetHFlip(true); + } AIPlayer::~AIPlayer() @@ -372,3 +424,151 @@ void AIPlayer::invalidateTotalAIDecks() totalAIDecks = -1; } +bool AIPlayer::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) +{ + if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) + return false; + if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) + return false; + if (!(card->power >= ennemy->toughness)) + return false; + if (!(card->power >= ennemy->toughness + 1) && ennemy->has(Constants::FLANKING)) + return false; + return true; +} + +bool AIPlayer::canPlay(MTGCardInstance * card) +{ + if (card->hasType(Subtypes::TYPE_LAND)) + { + if (game->playRestrictions->canPutIntoZone(card, game->inPlay) == PlayRestriction::CANT_PLAY) + return false; + } + else + { + if (game->playRestrictions->canPutIntoZone(card, game->stack) == PlayRestriction::CANT_PLAY) + return false; + } + if (!manaPool->canAfford(card->getManaCost())) + return false; + + return true; +} + +int AIPlayer::getCreaturesInfo(Player * player, int neededInfo, int untapMode, int canAttack) +{ + int result = 0; + CardDescriptor cd; + cd.init(); + cd.setType("Creature"); + cd.unsecureSetTapped(untapMode); + MTGCardInstance * card = NULL; + while ((card = cd.nextmatch(player->game->inPlay, card))) + { + if (!canAttack || card->canAttack()) + { + if (neededInfo == INFO_NBCREATURES) + { + result++; + } + else + { + result += card->power; + } + } + } + return result; +} + +int AIPlayer::createAbilityPotentialsActions(MTGAbility * a, MTGCardInstance * c, vector& actions) +{ + if (!a->getActionTc()) + { + AIAction aiAction(this, a, c, NULL); + actions.push_back(aiAction); + return 1; + } + + vectorpotentialTargets; + for (int i = 0; i < 2; i++) + { + Player * p = observer->players[i]; + MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay,p->game->stack }; + // try player first + if(a->getActionTc()->canTarget((Targetable*)p)) + { + if(a->getActionTc()->maxtargets == 1) + { + AIAction aiAction(this, a, p, c); + actions.push_back(aiAction); + } + else + potentialTargets.push_back(p); + } + for (int j = 0; j < 5; j++) + { + MTGGameZone * zone = playerZones[j]; + for (int k = 0; k < zone->nb_cards; k++) + { + MTGCardInstance * t = zone->cards[k]; + if (a->getActionTc()->canTarget(t)) + { + if(a->getActionTc()->maxtargets == 1) + { + AIAction aiAction(this, a, c, t); + actions.push_back(aiAction); + } + else + { + potentialTargets.push_back(t); + } + } + } + } + } + vectorrealTargets; + if(a->getActionTc()->maxtargets != 1) + { + if(a->getActionTc()->getNbTargets() && a->getActionTc()->attemptsToFill > 4) + { + a->getActionTc()->done = true; + return 0; + } + while(potentialTargets.size()) + { + AIAction * check = NULL; + + Player * pTargeting = 0; + MTGCardInstance * cTargeting = dynamic_cast(potentialTargets[0]); + if(cTargeting) + { + check = NEW AIAction(this, a,c,cTargeting); + } + else + { + pTargeting = dynamic_cast(potentialTargets[0]); + if(pTargeting) + check = NEW AIAction(this, a,pTargeting,c); + } + + if(check && pTargeting) + { + AIAction aiAction(this, a,pTargeting,c); + actions.push_back(aiAction); + } + if(check) + realTargets.push_back(potentialTargets[0]); + potentialTargets.erase(potentialTargets.begin()); + SAFE_DELETE(check); + } + if(!realTargets.size() || (int(realTargets.size()) < a->getActionTc()->maxtargets && a->getActionTc()->targetMin)) + return 0; + AIAction aiAction(this, a, c,realTargets); + aiAction.target = dynamic_cast(realTargets[0]); + aiAction.playerAbilityTarget = dynamic_cast(realTargets[0]); + actions.push_back(aiAction); + } + return 1; +} + +} \ No newline at end of file diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index 2c1039562..634c7e555 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -14,6 +14,7 @@ // AIAction // +namespace AI { Player * OrderedAIAction::getPlayerTarget() { @@ -2204,36 +2205,6 @@ int AIPlayerBaka::computeActions() return 1; }; - -// -// Combat // -// - -int AIPlayerBaka::getCreaturesInfo(Player * player, int neededInfo, int untapMode, int canAttack) -{ - int result = 0; - CardDescriptor cd; - cd.init(); - cd.setType("Creature"); - cd.unsecureSetTapped(untapMode); - MTGCardInstance * card = NULL; - while ((card = cd.nextmatch(player->game->inPlay, card))) - { - if (!canAttack || card->canAttack()) - { - if (neededInfo == INFO_NBCREATURES) - { - result++; - } - else - { - result += card->power; - } - } - } - return result; -} - int AIPlayerBaka::chooseAttackers() { //Attack with all creatures @@ -2280,19 +2251,12 @@ int AIPlayerBaka::chooseAttackers() } /* Can I first strike my oponent and get away with murder ? */ -int AIPlayerBaka::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) +bool AIPlayerBaka::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) { if(hints && hints->HintSaysAlwaysBlock(observer,ennemy)) - return 1; - if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) - return 0; - if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) - return 0; - if (!(card->power >= ennemy->toughness)) - return 0; - if (!(card->power >= ennemy->toughness + 1) && ennemy->has(Constants::FLANKING)) - return 0; - return 1; + return true; + + return AIPlayer::canFirstStrikeKill(card, ennemy); } int AIPlayerBaka::chooseBlockers() @@ -2476,7 +2440,7 @@ int AIPlayerBaka::receiveEvent(WEvent * event) AIPlayerBaka::AIPlayerBaka(GameObserver *observer, string file, string fileSmall, string avatarFile, MTGDeck * deck) : - AIPlayer(observer, file, fileSmall, deck) + AIPlayer(observer, file, fileSmall, avatarFile, deck) { nextCardToPlay = NULL; @@ -2491,34 +2455,6 @@ AIPlayerBaka::AIPlayerBaka(GameObserver *observer, string file, string fileSmall for (size_t i = 0; i < mDeck->meta_AIHints.size(); ++i) hints->add(mDeck->meta_AIHints[i]); } - - - if(avatarFile != "") - { - if(!loadAvatar(avatarFile, "bakaAvatar")) - { - avatarFile = "baka.jpg"; - loadAvatar(avatarFile, "bakaAvatar"); - } - mAvatarName = avatarFile; - } - else //load a random avatar. - { - avatarFile = "avatar"; - char buffer[3]; - sprintf(buffer, "%i", int(observer->getRandomGenerator()->random()%100)); - avatarFile.append(buffer); - avatarFile.append(".jpg"); - if(!loadAvatar(avatarFile, "bakaAvatar")) - { - avatarFile = "baka.jpg"; - loadAvatar(avatarFile, "bakaAvatar"); - } - mAvatarName = avatarFile; - } - - if (fileSmall == "ai_baka_eviltwin") - mAvatar->SetHFlip(true); initTimer(); } @@ -2610,3 +2546,5 @@ AIPlayerBaka::~AIPlayerBaka() { } SAFE_DELETE(hints); } + +} diff --git a/projects/mtg/src/AIPlayerBakaB.cpp b/projects/mtg/src/AIPlayerBakaB.cpp index 67675ab21..281b39c7a 100644 --- a/projects/mtg/src/AIPlayerBakaB.cpp +++ b/projects/mtg/src/AIPlayerBakaB.cpp @@ -14,6 +14,7 @@ // Abilities/Target Selection // +namespace AI { MTGCardInstance * AIPlayerBakaB::chooseCard(TargetChooser * tc, MTGCardInstance * source, int random) { @@ -117,7 +118,7 @@ int AIPlayerBakaB::chooseAttackers() } /* Can I first strike my oponent and get away with murder ? */ -int AIPlayerBakaB::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) +bool AIPlayerBakaB::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) { return AIPlayerBaka::canFirstStrikeKill(card, ennemy); } @@ -180,7 +181,7 @@ AIPlayerBakaB::~AIPlayerBakaB() { } - +} #endif diff --git a/projects/mtg/src/AIPlayerMinMax.cpp b/projects/mtg/src/AIPlayerMinMax.cpp new file mode 100644 index 000000000..d087e3dc7 --- /dev/null +++ b/projects/mtg/src/AIPlayerMinMax.cpp @@ -0,0 +1,75 @@ +#include "PrecompiledHeader.h" + +#include "AIPlayerMinMax.h" +#include "CardDescriptor.h" +#include "AIStats.h" +#include "AllAbilities.h" +#include "ExtraCost.h" +#include "GuiCombat.h" +#include "AIHints.h" +#include "ManaCostHybrid.h" +#include "MTGRules.h" + +namespace AI { + +// +// Abilities/Target Selection +// + +AIPlayerMinMax::AIPlayerMinMax(GameObserver *observer, string deckFile, string deckFileSmall, string avatarFile, MTGDeck * deck) : + AIPlayer(observer, deckFile, deckFileSmall, avatarFile, deck) +{ +} + +int AIPlayerMinMax::Act(float dt) +{ + return 0; +}; + +AIPlayerMinMax::~AIPlayerMinMax() +{ +} + + +void AIPlayerMinMax::LookAround() +{ + vector::iterator ite; + vector potentialActions; + + // look for something useable (including mana) + for (size_t i = 1; i < observer->mLayers->actionLayer()->mObjects.size(); i++) + { + MTGAbility * a = ((MTGAbility *) observer->mLayers->actionLayer()->mObjects[i]); + //Make sure we can use the ability + for (int j = 0; j < game->inPlay->nb_cards; j++) + { + MTGCardInstance * card = game->inPlay->cards[j]; + if (a->isReactingToClick(card, 0)) + { + createAbilityPotentialsActions(a, card, potentialActions); + } + } + } + + // look for something playable + for(ite = game->hand->cards.begin(); ite != game->hand->cards.end(); ite++) + { + if(canPlay(*ite)) + { + AIAction a(this, (*ite)); + potentialActions.push_back(a); + } + } + + stringstream stream; + stream << *observer; + vector::iterator it; + for(it = potentialActions.begin(); it != potentialActions.end(); it++) + { + GameObserver g; + g.load(stream.str()); +// g.processAction((*it)); + } +} + +} diff --git a/projects/mtg/src/AIStats.cpp b/projects/mtg/src/AIStats.cpp index 3e9a59664..0da1f1122 100644 --- a/projects/mtg/src/AIStats.cpp +++ b/projects/mtg/src/AIStats.cpp @@ -6,6 +6,9 @@ #include "MTGCardInstance.h" #include "WEvent.h" #include "AllAbilities.h" + +namespace AI { + //TODO:better comments this is too cryptic to work on by anyone but original coder. bool compare_aistats(AIStat * first, AIStat * second) { @@ -217,3 +220,5 @@ void AIStats::Render() } } } + +} \ No newline at end of file diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 69a32202e..cf2dc5f20 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -994,15 +994,15 @@ void ActionStack::Update(float dt) void ActionStack::cancelInterruptOffer(InterruptDecision cancelMode, bool log) { int playerId = (observer->isInterrupting == observer->players[1]) ? 1 : 0; - interruptDecision[playerId] = cancelMode; - askIfWishesToInterrupt = NULL; - observer->isInterrupting = NULL; - timer = -1; if(log) { stringstream stream; stream << "no " << cancelMode; observer->logAction(playerId, stream.str()); } + interruptDecision[playerId] = cancelMode; + askIfWishesToInterrupt = NULL; + observer->isInterrupting = NULL; + timer = -1; } void ActionStack::endOfInterruption(bool log) diff --git a/projects/mtg/src/Credits.cpp b/projects/mtg/src/Credits.cpp index 1e07fcb49..d5c8062b1 100644 --- a/projects/mtg/src/Credits.cpp +++ b/projects/mtg/src/Credits.cpp @@ -625,7 +625,7 @@ int Credits::isDifficultyUnlocked(DeckStats * stats) { if (options[Options::DIFFICULTY_MODE_UNLOCKED].number) return 0; - int nbAIDecks = AIPlayer::getTotalAIDecks(); + int nbAIDecks = AI::AIPlayer::getTotalAIDecks(); int wins = 0; @@ -743,7 +743,7 @@ int Credits::IsMoreAIDecksUnlocked(DeckStats * stats) { // the number of currently unlocked decks in order to go through. if (stats->nbGames() < currentlyUnlocked * 1.2) return 0; - if (AIPlayer::getTotalAIDecks() > currentlyUnlocked) + if (AI::AIPlayer::getTotalAIDecks() > currentlyUnlocked) return 1; return 0; diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index b7dcda29c..17ace2d4f 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -1668,7 +1668,7 @@ bool GameObserver::load(const string& ss, bool undo, int controlledPlayerIndex } else { - logAction(s); + actionsList.push_back(s); } break; } @@ -1772,11 +1772,11 @@ bool GameObserver::processActions(bool undo for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++) { - processAction(*loadingite); - + string s = *loadingite; + processAction(s); size_t nb = actionsList.size(); - for (int i = 0; i<6; i++) + for (int i = 0; i < 6; i++) { // let's fake an update GameObserver::Update(counter); @@ -1815,12 +1815,15 @@ void GameObserver::logAction(MTGCardInstance* card, MTGGameZone* zone, size_t in void GameObserver::logAction(const string& s) { + stringstream stream; + stream << s << " cp " << getPlayerId(currentPlayer) << ", ii " << getPlayerId(isInterrupting) << ", cap " << getPlayerId(currentActionPlayer); + if(mLoading) { string toCheck = *loadingite; - dumpAssert(toCheck == s); + dumpAssert(toCheck == stream.str()); } - actionsList.push_back(s); + actionsList.push_back(stream.str()); }; bool GameObserver::undo() @@ -1850,7 +1853,7 @@ Player* GameObserver::createPlayer(const string& playerMode switch(aMode) { case Player::MODE_AI: - AIPlayerFactory playerCreator; + AI::AIPlayerFactory playerCreator; if(players.size()) pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), players[0]); else @@ -1923,7 +1926,7 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b } else { //AI Player, chooses deck - AIPlayerFactory playerCreator; + AI::AIPlayerFactory playerCreator; Player * opponent = NULL; if (playerId == 1) opponent = players[0]; @@ -1933,7 +1936,7 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b else { //Random deck - AIPlayerFactory playerCreator; + AI::AIPlayerFactory playerCreator; Player * opponent = NULL; // Reset the random logging. @@ -1950,7 +1953,7 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b } if (playerType == PLAYER_TYPE_CPU_TEST) - ((AIPlayer *) players[playerId])->setFastTimerMode(); + ((AI::AIPlayer *) players[playerId])->setFastTimerMode(); } } diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index 41a8a2f37..c657714a5 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -332,7 +332,7 @@ void GameStateDeckViewer::saveDeck() void GameStateDeckViewer::saveAsAIDeck(string deckName) { - int deckId = AIPlayer::getTotalAIDecks() + 1; + int deckId = AI::AIPlayer::getTotalAIDecks() + 1; std::ostringstream oss; oss << "deck" <save(filepath, true, deckName, deckDesc); - AIPlayer::invalidateTotalAIDecks(); //We added one AI deck, so we need to invalidate the count cache + AI::AIPlayer::invalidateTotalAIDecks(); //We added one AI deck, so we need to invalidate the count cache } void GameStateDeckViewer::sellCard() diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index c2b4174da..35f57d66c 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -1733,8 +1733,8 @@ void GameStateDuel::setAISpeed() { if (mParent->players[i] == PLAYER_TYPE_CPU) { - if(dynamic_cast(game->players[i])) - ((AIPlayer *)game->players[i])->setFastTimerMode(tournament->getFastTimerMode()); + if(dynamic_cast(game->players[i])) + ((AI::AIPlayer *)game->players[i])->setFastTimerMode(tournament->getFastTimerMode()); } } } diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index 11327ce83..a423c2875 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -253,7 +253,7 @@ int GameStateMenu::gamePercentComplete() { //unlocked AI decks int currentlyUnlocked = options[Options::AIDECKS_UNLOCKED].number; - int totalAIDecks = AIPlayer::getTotalAIDecks(); + int totalAIDecks = AI::AIPlayer::getTotalAIDecks(); int reallyUnlocked = MIN(currentlyUnlocked, totalAIDecks); total+= totalAIDecks / 10; done+= reallyUnlocked / 10; diff --git a/projects/mtg/src/GuiCombat.cpp b/projects/mtg/src/GuiCombat.cpp index 46265e209..8fd3a8af3 100644 --- a/projects/mtg/src/GuiCombat.cpp +++ b/projects/mtg/src/GuiCombat.cpp @@ -727,7 +727,7 @@ int GuiCombat::receiveEventMinus(WEvent* e) DAMAGE: step = event->step; if (!observer->currentPlayer->displayStack()) { - ((AIPlayer *) observer->currentPlayer)->affectCombatDamages(step); + ((AI::AIPlayer *) observer->currentPlayer)->affectCombatDamages(step); observer->userRequestNextGamePhase(false, false); return 1; } diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 2792c5a11..db9cb85cf 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -385,18 +385,30 @@ bool Player::operator<(Player& aPlayer) if(isDead() && !aPlayer.isDead()) return true; + // if this opponent is not dead and aPlayer opponent is dead then this < aPlayer + if(!opponent()->isDead() && aPlayer.opponent()->isDead()) + return true; + // heuristics for min-max // if this is more poisoined than aPlayer then this < aPlayer - if(poisonCount > aPlayer.poisonCount) + if((poisonCount - opponent()->poisonCount) > (aPlayer.poisonCount - aPlayer.opponent()->poisonCount)) return true; // if this has less life than aPlayer then this < aPlayer - if(life < aPlayer.life) + if((life - opponent()->life) < (aPlayer.life - aPlayer.opponent()->life)) return true; - // if this has less parmanents in game that aPlayer then this < aPlayer - if(game->battlefield->cards.size() < aPlayer.game->battlefield->cards.size()) + // if this has less permanents in game that aPlayer then this < aPlayer + if(((int)game->battlefield->cards.size() - (int)opponent()->game->battlefield->cards.size()) < ((int)aPlayer.game->battlefield->cards.size() - (int)aPlayer.opponent()->game->battlefield->cards.size())) + return true; + + // if this has less cards in hand that aPlayer then this < aPlayer + if(((int)game->hand->cards.size() - (int)opponent()->game->hand->cards.size()) < ((int)aPlayer.game->hand->cards.size() - (int)aPlayer.opponent()->game->hand->cards.size())) + return true; + + // if this has less mana than aPlayer then this < aPlayer + if(aPlayer.manaPool->canAfford(manaPool)) return true; return false; diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 9d7ed8ae9..54f051b46 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -183,8 +183,8 @@ void Rules::addExtraRules(GameObserver* g) else if (p->isAI() && (p->playMode == Player::MODE_AI && p->opponent()->playMode== Player::MODE_AI)) { handsize = ((AADrawer *)a)->getNumCards(); - ((AIPlayer *) p)->forceBestAbilityUse = true; - ((AIPlayer *) p)->agressivity += 100; + ((AI::AIPlayer *) p)->forceBestAbilityUse = true; + ((AI::AIPlayer *) p)->agressivity += 100; hand->OptimizedHand(p,handsize, 3, 1, 3); } else if (!p->isAI() && !Optimizedhandcheat) @@ -202,8 +202,8 @@ void Rules::addExtraRules(GameObserver* g) handsize = ((AADrawer *)a)->getNumCards(); if(difficultyRating == EASY) { - ((AIPlayer *) p)->forceBestAbilityUse = true; - ((AIPlayer *) p)->agressivity += 100; + ((AI::AIPlayer *) p)->forceBestAbilityUse = true; + ((AI::AIPlayer *) p)->agressivity += 100; hand->OptimizedHand(p,handsize, 3, 1, 3);//easy decks get a major boost, open hand is 2lands,1 creature under 3 mana,3spells under 3 mana. } else if (difficultyRating == NORMAL) @@ -265,7 +265,7 @@ Player * Rules::loadPlayerMomir(GameObserver* observer, int isAI) if (!isAI) // Human Player player = NEW HumanPlayer(observer, options.profileFile("momir.txt", "", true).c_str(), deckFileSmall, false, tempDeck); else - player = NEW AIMomirPlayer(observer, options.profileFile("momir.txt", "", true).c_str(), deckFileSmall, empty, tempDeck); + player = NEW AI::AIMomirPlayer(observer, options.profileFile("momir.txt", "", true).c_str(), deckFileSmall, empty, tempDeck); return player; } @@ -299,7 +299,7 @@ Player * Rules::loadPlayerRandom(GameObserver* observer, int isAI, int mode) if (!isAI) // Human Player player = NEW HumanPlayer(observer, deckFile, deckFileSmall, false, tempDeck); else - player = NEW AIPlayerBaka(observer, deckFile, deckFileSmall, "", tempDeck); + player = NEW AI::AIPlayerBaka(observer, deckFile, deckFileSmall, "", tempDeck); return player; } diff --git a/projects/mtg/src/StoryFlow.cpp b/projects/mtg/src/StoryFlow.cpp index b77c40efd..2b56e2502 100644 --- a/projects/mtg/src/StoryFlow.cpp +++ b/projects/mtg/src/StoryFlow.cpp @@ -310,7 +310,7 @@ void StoryDuel::init() sprintf(deckFile, "%s/opponent_deck.txt", folder); sprintf(deckFileSmall, "campaign_ennemy_%s_%s", mParent->folder.c_str(), pageId.c_str()); - game->loadPlayer(1, NEW AIPlayerBaka(game, deckFile, deckFileSmall, "baka.jpg")); + game->loadPlayer(1, NEW AI::AIPlayerBaka(game, deckFile, deckFileSmall, "baka.jpg")); string rulesFile = folder; rulesFile.append("/rules.txt"); diff --git a/projects/mtg/src/Tasks.cpp b/projects/mtg/src/Tasks.cpp index d1e32a63b..eca12e80e 100644 --- a/projects/mtg/src/Tasks.cpp +++ b/projects/mtg/src/Tasks.cpp @@ -616,7 +616,7 @@ string TaskWinAgainst::getShortDesc() bool TaskWinAgainst::isDone(GameObserver* observer, GameApp *) { - AIPlayerBaka * baka = (AIPlayerBaka*) observer->players[1]; + AI::AIPlayerBaka * baka = (AI::AIPlayerBaka*) observer->players[1]; return ((baka) && (!observer->players[0]->isAI()) && (observer->players[1]->isAI()) && (observer->didWin(observer->players[0])) // Human player wins && (baka->deckId == opponent)); } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index 80c930ef8..dad308b6a 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -567,7 +567,7 @@ int TestSuite::loadNext() #elif defined(IOS) thread_count = 6; #else - thread_count = 4; + thread_count = 2; #endif for(size_t i = 0; i < (thread_count-1); i++) mWorkerThread.push_back(new boost::thread(ThreadProc, this)); @@ -600,6 +600,13 @@ void TestSuite::ThreadProc(void* inParam) theGame.observer->startGame(theGame.gameType, /*instance->mRules*/Rules::getRulesByFilename("testsuite.txt")); theGame.initGame(); + while(!theGame.observer->didWin()) + theGame.observer->Update(counter++); + + stringstream stream; + stream << (*theGame.observer); + theGame.observer->load(stream.str(), false, 0, &theGame); + while(!theGame.observer->didWin()) theGame.observer->Update(counter++); } @@ -834,7 +841,7 @@ void TestSuiteGame::initGame() for (int i = 0; i < 2; i++) { - AIPlayerBaka * p = (AIPlayerBaka *) (observer->players[i]); + AI::AIPlayerBaka * p = (AI::AIPlayerBaka *) (observer->players[i]); p->forceBestAbilityUse = forceAbility; p->life = initState.players[i]->life; p->poisonCount = initState.players[i]->poisonCount; diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index 7109ebd09..6086a7965 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -310,6 +310,7 @@ + @@ -450,6 +451,7 @@ + diff --git a/projects/mtg/template.vcxproj.filters b/projects/mtg/template.vcxproj.filters index 32cd0ca8b..db101b330 100644 --- a/projects/mtg/template.vcxproj.filters +++ b/projects/mtg/template.vcxproj.filters @@ -331,6 +331,9 @@ src + + src + @@ -687,6 +690,9 @@ inc + + inc +