From 64b7c9f0368efd1345fefef6f645584123d998bb Mon Sep 17 00:00:00 2001 From: Dydzio Date: Sun, 5 Aug 2018 19:03:25 +0200 Subject: [PATCH] VisitTile fuzzy logic separated from FuzzyHelper --- AI/VCAI/Fuzzy.cpp | 210 ++++++++++++++++++++++++---------------------- AI/VCAI/Fuzzy.h | 30 ++++--- 2 files changed, 125 insertions(+), 115 deletions(-) diff --git a/AI/VCAI/Fuzzy.cpp b/AI/VCAI/Fuzzy.cpp index 92dddb03c..cc94b25ba 100644 --- a/AI/VCAI/Fuzzy.cpp +++ b/AI/VCAI/Fuzzy.cpp @@ -125,60 +125,6 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank) } -float FuzzyHelper::getTacticalAdvantage(const CArmedInstance * we, const CArmedInstance * enemy) -{ - float output = 1; - try - { - armyStructure ourStructure = evaluateArmyStructure(we); - armyStructure enemyStructure = evaluateArmyStructure(enemy); - - ta.ourWalkers->setValue(ourStructure.walkers); - ta.ourShooters->setValue(ourStructure.shooters); - ta.ourFlyers->setValue(ourStructure.flyers); - ta.ourSpeed->setValue(ourStructure.maxSpeed); - - ta.enemyWalkers->setValue(enemyStructure.walkers); - ta.enemyShooters->setValue(enemyStructure.shooters); - ta.enemyFlyers->setValue(enemyStructure.flyers); - ta.enemySpeed->setValue(enemyStructure.maxSpeed); - - bool bank = dynamic_cast(enemy); - if(bank) - ta.bankPresent->setValue(1); - else - ta.bankPresent->setValue(0); - - const CGTownInstance * fort = dynamic_cast(enemy); - if(fort) - ta.castleWalls->setValue(fort->fortLevel()); - else - ta.castleWalls->setValue(0); - - //engine.process(TACTICAL_ADVANTAGE);//TODO: Process only Tactical_Advantage - ta.engine.process(); - output = ta.threat->getValue(); - } - catch(fl::Exception & fe) - { - logAi->error("getTacticalAdvantage: %s ", fe.getWhat()); - } - - if(output < 0 || (output != output)) - { - fl::InputVariable * tab[] = {ta.bankPresent, ta.castleWalls, ta.ourWalkers, ta.ourShooters, ta.ourFlyers, ta.ourSpeed, ta.enemyWalkers, ta.enemyShooters, ta.enemyFlyers, ta.enemySpeed}; - std::string names[] = {"bankPresent", "castleWalls", "ourWalkers", "ourShooters", "ourFlyers", "ourSpeed", "enemyWalkers", "enemyShooters", "enemyFlyers", "enemySpeed" }; - std::stringstream log("Warning! Fuzzy engine doesn't cover this set of parameters: "); - - for(int i = 0; i < boost::size(tab); i++) - log << names[i] << ": " << tab[i]->getValue() << " "; - logAi->error(log.str()); - assert(false); - } - - return output; -} - float FuzzyHelper::getWanderTargetObjectValue(const CGHeroInstance & h, const ObjectIdRef & obj) { float distFromObject = calculateTurnDistanceInputValue(&h, obj->pos); @@ -211,7 +157,7 @@ float FuzzyHelper::getWanderTargetObjectValue(const CGHeroInstance & h, const Ob return output; } -TacticalAdvantage::TacticalAdvantage() +TacticalAdvantageEngine::TacticalAdvantageEngine() { try { @@ -311,7 +257,61 @@ TacticalAdvantage::TacticalAdvantage() configure(); } -TacticalAdvantage::~TacticalAdvantage() +float TacticalAdvantageEngine::getTacticalAdvantage(const CArmedInstance * we, const CArmedInstance * enemy) +{ + float output = 1; + try + { + armyStructure ourStructure = evaluateArmyStructure(we); + armyStructure enemyStructure = evaluateArmyStructure(enemy); + + ourWalkers->setValue(ourStructure.walkers); + ourShooters->setValue(ourStructure.shooters); + ourFlyers->setValue(ourStructure.flyers); + ourSpeed->setValue(ourStructure.maxSpeed); + + enemyWalkers->setValue(enemyStructure.walkers); + enemyShooters->setValue(enemyStructure.shooters); + enemyFlyers->setValue(enemyStructure.flyers); + enemySpeed->setValue(enemyStructure.maxSpeed); + + bool bank = dynamic_cast(enemy); + if(bank) + bankPresent->setValue(1); + else + bankPresent->setValue(0); + + const CGTownInstance * fort = dynamic_cast(enemy); + if(fort) + castleWalls->setValue(fort->fortLevel()); + else + castleWalls->setValue(0); + + //engine.process(TACTICAL_ADVANTAGE);//TODO: Process only Tactical_Advantage + engine.process(); + output = threat->getValue(); + } + catch(fl::Exception & fe) + { + logAi->error("getTacticalAdvantage: %s ", fe.getWhat()); + } + + if(output < 0 || (output != output)) + { + fl::InputVariable * tab[] = { bankPresent, castleWalls, ourWalkers, ourShooters, ourFlyers, ourSpeed, enemyWalkers, enemyShooters, enemyFlyers, enemySpeed }; + std::string names[] = { "bankPresent", "castleWalls", "ourWalkers", "ourShooters", "ourFlyers", "ourSpeed", "enemyWalkers", "enemyShooters", "enemyFlyers", "enemySpeed" }; + std::stringstream log("Warning! Fuzzy engine doesn't cover this set of parameters: "); + + for(int i = 0; i < boost::size(tab); i++) + log << names[i] << ": " << tab[i]->getValue() << " "; + logAi->error(log.str()); + assert(false); + } + + return output; +} + +TacticalAdvantageEngine::~TacticalAdvantageEngine() { //TODO: smart pointers? delete ourWalkers; @@ -454,50 +454,7 @@ HeroMovementGoalEngineBase::~HeroMovementGoalEngineBase() float FuzzyHelper::evaluate(Goals::VisitTile & g) { - //we assume that hero is already set and we want to choose most suitable one for the mission - if(!g.hero) - return 0; - - //assert(cb->isInTheMap(g.tile)); - float turns = calculateTurnDistanceInputValue(g.hero.h, g.tile); - float missionImportance = 0; - if(vstd::contains(ai->lockedHeroes, g.hero)) - missionImportance = ai->lockedHeroes[g.hero]->priority; - - float strengthRatio = 10.0f; //we are much stronger than enemy - ui64 danger = evaluateDanger(g.tile, g.hero.h); - if(danger) - strengthRatio = (fl::scalar)g.hero.h->getTotalStrength() / danger; - - float tilePriority = 0; - if(g.objid == -1) - { - vt.estimatedReward->setEnabled(false); - } - else if(g.objid == Obj::TOWN) //TODO: move to getObj eventually and add appropiate logic there - { - vt.estimatedReward->setEnabled(true); - tilePriority = 5; - } - - try - { - vt.strengthRatio->setValue(strengthRatio); - vt.heroStrength->setValue((fl::scalar)g.hero->getTotalStrength() / ai->primaryHero()->getTotalStrength()); - vt.turnDistance->setValue(turns); - vt.missionImportance->setValue(missionImportance); - vt.estimatedReward->setValue(tilePriority); - - vt.engine.process(); - //engine.process(VISIT_TILE); //TODO: Process only Visit_Tile - g.priority = vt.value->getValue(); - } - catch(fl::Exception & fe) - { - logAi->error("evaluate VisitTile: %s", fe.getWhat()); - } - assert(g.priority >= 0); - return g.priority; + return visitTileEngine.evaluate(g); } float FuzzyHelper::evaluate(Goals::VisitHero & g) { @@ -616,11 +573,60 @@ EvalWanderTargetObject::~EvalWanderTargetObject() delete objectValue; } -EvalVisitTile::EvalVisitTile() +VisitTileEngine::VisitTileEngine() //so far no VisitTile-specific variables that are not shared with HeroMovementGoalEngineBase { configure(); } -EvalVisitTile::~EvalVisitTile() +VisitTileEngine::~VisitTileEngine() { } + +float VisitTileEngine::evaluate(Goals::AbstractGoal & goal) +{ + auto g = dynamic_cast(goal); + //we assume that hero is already set and we want to choose most suitable one for the mission + if(!g.hero) + return 0; + + //assert(cb->isInTheMap(g.tile)); + float turns = calculateTurnDistanceInputValue(g.hero.h, g.tile); + float missionImportanceData = 0; + if(vstd::contains(ai->lockedHeroes, g.hero)) + missionImportanceData = ai->lockedHeroes[g.hero]->priority; + + float strengthRatioData = 10.0f; //we are much stronger than enemy + ui64 danger = evaluateDanger(g.tile, g.hero.h); + if(danger) + strengthRatioData = (fl::scalar)g.hero.h->getTotalStrength() / danger; + + float tilePriority = 0; + if(g.objid == -1) + { + estimatedReward->setEnabled(false); + } + else if(g.objid == Obj::TOWN) //TODO: move to getObj eventually and add appropiate logic there + { + estimatedReward->setEnabled(true); + tilePriority = 5; + } + + try + { + strengthRatio->setValue(strengthRatioData); + heroStrength->setValue((fl::scalar)g.hero->getTotalStrength() / ai->primaryHero()->getTotalStrength()); + turnDistance->setValue(turns); + missionImportance->setValue(missionImportanceData); + estimatedReward->setValue(tilePriority); + + engine.process(); + //engine.process(VISIT_TILE); //TODO: Process only Visit_Tile + g.priority = value->getValue(); + } + catch(fl::Exception & fe) + { + logAi->error("evaluate VisitTile: %s", fe.getWhat()); + } + assert(g.priority >= 0); + return g.priority; +} diff --git a/AI/VCAI/Fuzzy.h b/AI/VCAI/Fuzzy.h index 4549e1d2d..5b39d35e4 100644 --- a/AI/VCAI/Fuzzy.h +++ b/AI/VCAI/Fuzzy.h @@ -23,23 +23,25 @@ public: fl::RuleBlock rules; engineBase(); - void configure(); + virtual void configure(); void addRule(const std::string & txt); }; -class TacticalAdvantage : public engineBase +class TacticalAdvantageEngine : public engineBase { public: - TacticalAdvantage(); + TacticalAdvantageEngine(); fl::InputVariable * ourWalkers, *ourShooters, *ourFlyers, *enemyWalkers, *enemyShooters, *enemyFlyers; fl::InputVariable * ourSpeed, *enemySpeed; fl::InputVariable * bankPresent; fl::InputVariable * castleWalls; fl::OutputVariable * threat; - ~TacticalAdvantage(); + + float getTacticalAdvantage(const CArmedInstance * we, const CArmedInstance * enemy); //returns factor how many times enemy is stronger than us + ~TacticalAdvantageEngine(); }; -class HeroMovementGoalEngineBase : public engineBase //abstract class for hero visiting goals, allows evaluating newly added elementar objectives with appropiately broad context data +class HeroMovementGoalEngineBase : public engineBase { public: HeroMovementGoalEngineBase(); @@ -49,17 +51,20 @@ public: fl::InputVariable * missionImportance; fl::InputVariable * estimatedReward; fl::OutputVariable * value; + + virtual float evaluate(Goals::AbstractGoal & goal) = 0; ~HeroMovementGoalEngineBase(); protected: float calculateTurnDistanceInputValue(const CGHeroInstance * h, int3 tile) const; }; -class EvalVisitTile : public HeroMovementGoalEngineBase +class VisitTileEngine : public HeroMovementGoalEngineBase { public: - EvalVisitTile(); - ~EvalVisitTile(); + VisitTileEngine(); + ~VisitTileEngine(); + float evaluate(Goals::AbstractGoal & goal) override; }; class EvalWanderTargetObject : public HeroMovementGoalEngineBase //designed for use with VCAI::wander() @@ -74,11 +79,11 @@ class FuzzyHelper { friend class VCAI; - TacticalAdvantage ta; + TacticalAdvantageEngine tacticalAdvantageEngine; - EvalVisitTile vt; + VisitTileEngine visitTileEngine; - EvalWanderTargetObject wanderTarget; + EvalWanderTargetObject wanderTargetEngine; public: float evaluate(Goals::Explore & g); @@ -96,8 +101,7 @@ public: float evaluate(Goals::AbstractGoal & g); void setPriority(Goals::TSubgoal & g); - ui64 estimateBankDanger(const CBank * bank); - float getTacticalAdvantage(const CArmedInstance * we, const CArmedInstance * enemy); //returns factor how many times enemy is stronger than us + ui64 estimateBankDanger(const CBank * bank); //TODO: move to another class? float getWanderTargetObjectValue(const CGHeroInstance & h, const ObjectIdRef & obj); Goals::TSubgoal chooseSolution(Goals::TGoalVec vec);