diff --git a/AI/VCAI/Fuzzy.cpp b/AI/VCAI/Fuzzy.cpp new file mode 100644 index 000000000..1c480abb0 --- /dev/null +++ b/AI/VCAI/Fuzzy.cpp @@ -0,0 +1,110 @@ +#include "StdInc.h" +#include "Fuzzy.h" +#include "../../lib/CObjectHandler.h" +#include "AreaCentroidAlgorithm.cpp" +#include "CompoundTerm.cpp" +#include "DescriptiveAntecedent.cpp" +#include "FuzzyEngine.cpp" +#include "FuzzyAnd.cpp" +#include "FuzzyOr.cpp" +#include "InputLVar.cpp" +#include "OutputLVar.cpp" +#include "FuzzyAntecedent.cpp" +#include "FuzzyConsequent.cpp" +#include "FuzzyDefuzzifier.cpp" +#include "FuzzyModulation.cpp" +#include "FuzzyOperator.cpp" +#include "FuzzyOperation.cpp" +#include "FuzzyException.cpp" +#include "FuzzyExceptions.cpp" +#include "FuzzyRule.cpp" +#include "HedgeSet.cpp" +#include "Hedge.cpp" +#include "SingletonTerm.cpp" +#include "TrapezoidalTerm.cpp" +#include "TriangularTerm.cpp" +#include "LinguisticTerm.cpp" +#include "LinguisticVariable.cpp" +#include "RuleBlock.cpp" +#include "ShoulderTerm.cpp" +#include "StrOp.cpp" +#include "MamdaniRule.cpp" +#include "MamdaniConsequent.cpp" + +/* + * Fuzzy.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * +*/ + +class BankConfig; +class FuzzyEngine; +class InputLVar; + +FuzzyHelper fh; + +ui64 evaluateBankConfig (BankConfig * bc) +{ + ui64 danger = 0; + BOOST_FOREACH (auto opt, bc->guards) + { + danger += VLC->creh->creatures[opt.first]->fightValue * opt.second; + } + return danger; +} + +FuzzyHelper::FuzzyHelper() +{ + bankInput = new fl::InputLVar("BankInput"); + bankDanger = new fl::OutputLVar("BankDanger"); + bankInput->addTerm(new fl::SingletonTerm ("SET")); + + engine.addRuleBlock (&ruleBlock); //have to be added before the rules are parsed + engine.addInputLVar (bankInput); + for (int i = 0; i < 4; ++i) + { + bankDanger->addTerm(new fl::TriangularTerm ("Bank" + boost::lexical_cast(i), 0, 1)); + ruleBlock.addRule(new fl::MamdaniRule("if BankInput is SET then BankDanger is Bank" + boost::lexical_cast(i), engine)); + } + engine.addOutputLVar (bankDanger); +} + +ui64 FuzzyHelper::estimateBankDanger (int ID) +{ + std::vector > & configs = VLC->objh->banksInfo[ID]; + ui64 val = INFINITY;; + switch (configs.size()) + { + case 4: + try + { + int bankVal; + for (int i = 0; i < 4; ++i) + { + bankVal = evaluateBankConfig (VLC->objh->banksInfo[ID][i]); + bankDanger->term("Bank" + boost::lexical_cast(i))->setMinimum(bankVal * 0.5f); + bankDanger->term("Bank" + boost::lexical_cast(i))->setMaximum(bankVal * 1.5f); + } + int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5; + dynamic_cast(bankInput->term("SET"))->setValue(1); + bankInput->setInput (0); + engine.process(); + val = bankDanger->output().defuzzify(); //some expected value of this bank + } + catch (fl::FuzzyException fe) + { + tlog1 << fe.name() << ": " << fe.message() << '\n'; + } + case 1: //rare case - Pyramid + val = evaluateBankConfig (VLC->objh->banksInfo[ID][0]); + break; + default: + tlog3 << ("Uhnandled bank config!\n"); + } + return val; + +} \ No newline at end of file diff --git a/AI/VCAI/Fuzzy.h b/AI/VCAI/Fuzzy.h new file mode 100644 index 000000000..c7256e52e --- /dev/null +++ b/AI/VCAI/Fuzzy.h @@ -0,0 +1,34 @@ +#define INFINITY 1000000000 //definition required by FuzzyLite (?) +#define NAN 1000000001 +#include "FuzzyLite.h" + +/* + * Fuzzy.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * +*/ + +class VCAI; + +template bool isinf (T val) +{ + return val == INFINITY || val == -INFINITY; +} + +class FuzzyHelper +{ + friend class VCAI; + + fl::FuzzyEngine engine; + fl::InputLVar* bankInput; + fl::OutputLVar* bankDanger; + fl::RuleBlock ruleBlock; + +public: + FuzzyHelper(); + ui64 estimateBankDanger (int ID); +}; \ No newline at end of file diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index fa7cc5c59..cdb24cbc6 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1,12 +1,14 @@ #include "StdInc.h" #include "VCAI.h" #include "../../lib/UnlockGuard.h" +#include "Fuzzy.h" +#include "../../lib/CObjectHandler.h" #define I_AM_ELEMENTAR return CGoal(*this).setisElementar(true) - - CLogger &aiLogger = tlog6; +extern FuzzyHelper fh; + const int ACTUAL_RESOURCE_COUNT = 7; const double SAFE_ATTACK_CONSTANT = 2.5; @@ -15,6 +17,7 @@ using namespace vstd; //one thread may be turn of AI and another will be handling a side effect for AI2 boost::thread_specific_ptr cb; boost::thread_specific_ptr ai; + // CCallback *cb; // VCAI *ai; @@ -72,6 +75,7 @@ namespace Obj MINE = 53, MONSTER = 54, OBELISK = 57, + PYRAMID = 63, CRYPT = 84, SHIPWRECK = 85, TRADING_POST = 99, @@ -319,22 +323,16 @@ ui64 evaluateDanger(const CGObjectInstance *obj) return cre->getArmyStrength(); } case Obj::CRYPT: //crypt - { - return VLC->creh->creatures[56]->AIValue * 25 - + VLC->creh->creatures[58]->AIValue * 20 - + VLC->creh->creatures[60]->AIValue * 9 - + VLC->creh->creatures[62]->AIValue * 5; - } case Obj::CREATURE_BANK: //crebank case Obj::SHIPWRECK: //shipwreck case Obj::DERELICT_SHIP: //derelict ship - //TODO estimate danger - return 1000000000; + case Obj::PYRAMID: + return fh.estimateBankDanger (VLC->objh->bankObjToIndex(obj)); case Obj::WHIRLPOOL: //whirlpool case Obj::MONOLITH1: case Obj::MONOLITH2: case Obj::MONOLITH3: - //TODO mechinism for handling monoliths + //TODO mechanism for handling monoliths return 1000000000; default: return 0; @@ -347,7 +345,7 @@ bool compareDanger(const CGObjectInstance *lhs, const CGObjectInstance *rhs) } VCAI::VCAI(void) -{ +{ LOG_ENTRY; myCb = NULL; battleAIName = "StupidAI"; @@ -356,19 +354,19 @@ VCAI::VCAI(void) VCAI::~VCAI(void) -{ +{ LOG_ENTRY; } void VCAI::availableCreaturesChanged(const CGDwelling *town) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroMoved(const TryMoveHero & details) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(details.result == TryMoveHero::TELEPORTATION) { @@ -393,43 +391,43 @@ void VCAI::heroMoved(const TryMoveHero & details) void VCAI::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroInGarrisonChange(const CGTownInstance *town) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::centerView(int3 pos, int focusTime) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::artifactAssembled(const ArtifactLocation &al) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showTavernWindow(const CGObjectInstance *townOrTavern) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::playerBlocked(int reason) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if (reason == PlayerBlocked::UPCOMING_BATTLE) status.setBattle(UPCOMING_BATTLE); @@ -437,19 +435,19 @@ void VCAI::playerBlocked(int reason) void VCAI::showPuzzleMap() { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showShipyardDialog(const IShipyard *obj) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::gameOver(ui8 player, bool victory) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; BNLOG("Player %d: I heard that player %d %s.", playerID % (int)player % (victory ? "won" : "lost")); if(player == playerID) @@ -480,32 +478,32 @@ void VCAI::gameOver(ui8 player, bool victory) void VCAI::artifactPut(const ArtifactLocation &al) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::artifactRemoved(const ArtifactLocation &al) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::stacksErased(const StackLocation &location) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::artifactDisassembled(const ArtifactLocation &al) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(start && visitedObj->ID != Obj::MONSTER) alreadyVisited.push_back(visitedObj); @@ -513,13 +511,13 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi void VCAI::availableArtifactsChanged(const CGBlackMarket *bm /*= NULL*/) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; //buildArmyIn(town); //moveCreaturesToHero(town); @@ -527,7 +525,7 @@ void VCAI::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * tow void VCAI::tileHidden(const boost::unordered_set &pos) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; // BOOST_FOREACH(int3 tile, pos) // BOOST_FOREACH(const CGObjectInstance *obj, cb->getVisitableObjs(tile)) @@ -537,7 +535,7 @@ void VCAI::tileHidden(const boost::unordered_set &pos) void VCAI::tileRevealed(const boost::unordered_set &pos) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; BOOST_FOREACH(int3 tile, pos) BOOST_FOREACH(const CGObjectInstance *obj, myCb->getVisitableObjs(tile)) @@ -546,43 +544,43 @@ void VCAI::tileRevealed(const boost::unordered_set &pos) void VCAI::heroExchangeStarted(si32 hero1, si32 hero2) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroMovePointsChanged(const CGHeroInstance * hero) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::stackChangedType(const StackLocation &location, const CCreature &newType) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::newObject(const CGObjectInstance * obj) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(obj->isVisitable()) addVisitableObj(obj); @@ -590,7 +588,7 @@ void VCAI::newObject(const CGObjectInstance * obj) void VCAI::objectRemoved(const CGObjectInstance *obj) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(remove_if_present(visitableObjs, obj)) assert(obj->isVisitable()); @@ -598,43 +596,43 @@ void VCAI::objectRemoved(const CGObjectInstance *obj) void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::playerBonusChanged(const Bonus &bonus, bool gain) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::newStackInserted(const StackLocation &location, const CStackInstance &stack) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroCreated(const CGHeroInstance*) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showInfoDialog(const std::string &text, const std::vector &components, int soundID) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::requestRealized(PackageApplied *pa) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(status.haveTurn()) { @@ -651,37 +649,37 @@ void VCAI::requestRealized(PackageApplied *pa) void VCAI::receivedResource(int type, int val) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroManaPointsChanged(const CGHeroInstance * hero) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::battleResultsApplied() { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; assert(status.getBattle() == ENDING_BATTLE); status.setBattle(NO_BATTLE); @@ -689,7 +687,7 @@ void VCAI::battleResultsApplied() void VCAI::objectPropertyChanged(const SetObjectProperty * sop) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; if(sop->what == ObjProperty::OWNER) { @@ -701,19 +699,19 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop) void VCAI::buildChanged(const CGTownInstance *town, int buildingID, int what) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } @@ -721,7 +719,7 @@ void VCAI::init(CCallback * CB) { myCb = CB; cbc = CB; - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; playerID = myCb->getMyColor(); myCb->waitTillRealize = true; @@ -732,7 +730,7 @@ void VCAI::init(CCallback * CB) void VCAI::yourTurn() { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; status.startedTurn(); makingTurn = new boost::thread(&VCAI::makeTurn, this); @@ -740,7 +738,7 @@ void VCAI::yourTurn() void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; status.addQuery(); callback(0); @@ -748,7 +746,7 @@ void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &components, ui32 askID, const int soundID, bool selection, bool cancel) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; int sel = 0; status.addQuery(); @@ -764,7 +762,7 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector &onEnd) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; status.addQuery(); onEnd(); @@ -772,13 +770,13 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do void VCAI::serialize(COSer &h, const int version) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } void VCAI::serialize(CISer &h, const int version) { - NET_EVENT_HANDLER; + NET_EVENT_HANDLER; LOG_ENTRY; } diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 5f2911b42..941c23331 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -150,6 +150,8 @@ struct CIssueCommand : CGoal class VCAI : public CAdventureAI { public: + friend class FuzzyHelper; + std::map knownSubterraneanGates; std::vector visitedThisWeek; //only OPWs std::map > townVisitsThisWeek; diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index b3b93ac10..3850d473a 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -190,6 +190,25 @@ void CObjectHandler::loadObjects() tlog5 << "\t\tDone loading banks configs \n"; } +int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj) +{ + switch (obj->ID) //find apriopriate key + { + case 16: //bank + return obj->subID; + case 24: //derelict ship + return 8; + case 25: //utopia + return 10; + case 84: //crypt + return 9; + case 85: //shipwreck + return 7; + default: + tlog2 << "Unrecognixed Bank indetifier!\n"; + return 0; + } +} int CGObjectInstance::getOwner() const { //if (state) @@ -5688,19 +5707,7 @@ void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const void CBank::initObj() { - switch (ID) //find apriopriate key - { - case 16: //bank - index = subID; break; - case 24: //derelict ship - index = 8; break; - case 25: //utopia - index = 10; break; - case 84: //crypt - index = 9; break; - case 85: //shipwreck - index = 7; break; - } + index = VLC->objh->bankObjToIndex(this); bc = NULL; daycounter = 0; multiplier = 1; diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index 60ed3b4b1..fc3ebedd1 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -1309,6 +1309,7 @@ public: std::vector resVals; //default values of resources in gold void loadObjects(); + int bankObjToIndex (const CGObjectInstance * obj); template void serialize(Handler &h, const int version) {