Fuzzy.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #include "StdInc.h"
  2. #include "Fuzzy.h"
  3. #include <limits>
  4. #include "../../lib/mapObjects/MapObjects.h"
  5. #include "../../lib/mapObjects/CommonConstructors.h"
  6. #include "../../lib/CCreatureHandler.h"
  7. #include "../../lib/VCMI_Lib.h"
  8. #include "../../CCallback.h"
  9. #include "VCAI.h"
  10. /*
  11. * Fuzzy.cpp, part of VCMI engine
  12. *
  13. * Authors: listed in file AUTHORS in main folder
  14. *
  15. * License: GNU General Public License v2.0 or later
  16. * Full text of license available in license.txt file, in main folder
  17. *
  18. */
  19. #define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
  20. #define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 10 times weaker than us
  21. struct BankConfig;
  22. class Engine;
  23. class InputVariable;
  24. class CGTownInstance;
  25. using namespace vstd;
  26. //using namespace Goals;
  27. FuzzyHelper *fh;
  28. extern boost::thread_specific_ptr<CCallback> cb;
  29. extern boost::thread_specific_ptr<VCAI> ai;
  30. struct armyStructure
  31. {
  32. float walkers, shooters, flyers;
  33. ui32 maxSpeed;
  34. };
  35. armyStructure evaluateArmyStructure (const CArmedInstance * army)
  36. {
  37. ui64 totalStrenght = army->getArmyStrength();
  38. double walkersStrenght = 0;
  39. double flyersStrenght = 0;
  40. double shootersStrenght = 0;
  41. ui32 maxSpeed = 0;
  42. for(auto s : army->Slots())
  43. {
  44. bool walker = true;
  45. if (s.second->type->hasBonusOfType(Bonus::SHOOTER))
  46. {
  47. shootersStrenght += s.second->getPower();
  48. walker = false;
  49. }
  50. if (s.second->type->hasBonusOfType(Bonus::FLYING))
  51. {
  52. flyersStrenght += s.second->getPower();
  53. walker = false;
  54. }
  55. if (walker)
  56. walkersStrenght += s.second->getPower();
  57. amax (maxSpeed, s.second->type->valOfBonuses(Bonus::STACKS_SPEED));
  58. }
  59. armyStructure as;
  60. as.walkers = walkersStrenght / totalStrenght;
  61. as.shooters = shootersStrenght / totalStrenght;
  62. as.flyers = flyersStrenght / totalStrenght;
  63. as.maxSpeed = maxSpeed;
  64. return as;
  65. }
  66. FuzzyHelper::FuzzyHelper()
  67. {
  68. initBank();
  69. initTacticalAdvantage();
  70. initVisitTile();
  71. engine.configure("AlgebraicProduct", "AlgebraicSum",
  72. "AlgebraicProduct", "AlgebraicSum", "Centroid");
  73. logAi->infoStream() << engine.toString();
  74. }
  75. void FuzzyHelper::initBank()
  76. {
  77. try
  78. {
  79. //Trivial bank estimation
  80. bankInput = new fl::InputVariable("BankInput");
  81. bankDanger = new fl::OutputVariable("BankDanger");
  82. bankInput->addTerm(new fl::Rectangle("SET", 0.5 - 5 * fl::fuzzylite::macheps(),
  83. 0.5 + 5 * fl::fuzzylite::macheps()));
  84. engine.addInputVariable(bankInput);
  85. engine.addOutputVariable(bankDanger);
  86. engine.addRuleBlock(&bankBlock);
  87. for (int i = 0; i < 4; ++i)
  88. {
  89. bankDanger->addTerm(new fl::Triangle("Bank" + boost::lexical_cast<std::string>(i), 0, 1));
  90. bankBlock.addRule(fl::Rule::parse("if BankInput is SET then BankDanger is Bank" + boost::lexical_cast<std::string>(i), &engine));
  91. }
  92. }
  93. catch (fl::Exception & fe)
  94. {
  95. logAi->errorStream() << "initBank : " << fe.getWhat();
  96. }
  97. }
  98. void FuzzyHelper::initTacticalAdvantage()
  99. {
  100. try
  101. {
  102. ta.ourShooters = new fl::InputVariable("OurShooters");
  103. ta.ourWalkers = new fl::InputVariable("OurWalkers");
  104. ta.ourFlyers = new fl::InputVariable("OurFlyers");
  105. ta.enemyShooters = new fl::InputVariable("EnemyShooters");
  106. ta.enemyWalkers = new fl::InputVariable("EnemyWalkers");
  107. ta.enemyFlyers = new fl::InputVariable("EnemyFlyers");
  108. //Tactical advantage calculation
  109. std::vector<fl::InputVariable*> helper =
  110. {
  111. ta.ourShooters, ta.ourWalkers, ta.ourFlyers, ta.enemyShooters, ta.enemyWalkers, ta.enemyFlyers
  112. };
  113. for (auto val : helper)
  114. {
  115. engine.addInputVariable(val);
  116. val->addTerm(new fl::Ramp("FEW", 0.6, 0.0));
  117. val->addTerm(new fl::Ramp("MANY", 0.4, 1));
  118. }
  119. ta.ourSpeed = new fl::InputVariable("OurSpeed");
  120. ta.enemySpeed = new fl::InputVariable("EnemySpeed");
  121. helper = {ta.ourSpeed, ta.enemySpeed};
  122. for (auto val : helper)
  123. {
  124. engine.addInputVariable(val);
  125. val->addTerm(new fl::Ramp("LOW", 6.5, 3));
  126. val->addTerm(new fl::Triangle("MEDIUM", 5.5, 10.5));
  127. val->addTerm(new fl::Ramp("HIGH", 8.5, 16));
  128. }
  129. ta.castleWalls = new fl::InputVariable("CastleWalls");
  130. engine.addInputVariable(ta.castleWalls);
  131. ta.castleWalls->addTerm(new fl::Rectangle("NONE", CGTownInstance::NONE - 5.0 * fl::fuzzylite::macheps(),
  132. CGTownInstance::NONE + 5.0 * fl::fuzzylite::macheps()));
  133. {
  134. fl::scalar a = CGTownInstance::FORT, d = 2.5;
  135. fl::scalar b = a + (d - a) * 1.0 / 5.0;
  136. fl::scalar c = a + (d - a) * 4.0 / 5.0;
  137. ta.castleWalls->addTerm(new fl::Trapezoid("MEDIUM", a, b, c, d));
  138. }
  139. ta.castleWalls->addTerm(new fl::Ramp("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE));
  140. ta.bankPresent = new fl::InputVariable("Bank");
  141. engine.addInputVariable(ta.bankPresent);
  142. ta.bankPresent->addTerm(new fl::Rectangle("FALSE", 0.0 - 5.0 * fl::fuzzylite::macheps(),
  143. 0.0 + 5.0 * fl::fuzzylite::macheps()));
  144. ta.bankPresent->addTerm(new fl::Rectangle("TRUE", 1.0 - 5.0 * fl::fuzzylite::macheps(),
  145. 0.0 + 5.0 * fl::fuzzylite::macheps()));
  146. ta.threat = new fl::OutputVariable("Threat");
  147. engine.addOutputVariable(ta.threat);
  148. ta.threat->addTerm(new fl::Ramp("LOW", 1, MIN_AI_STRENGHT));
  149. ta.threat->addTerm(new fl::Triangle("MEDIUM", 0.8, 1.2));
  150. ta.threat->addTerm(new fl::Ramp("HIGH", 1, 1.5));
  151. engine.addRuleBlock(&ta.tacticalAdvantage);
  152. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemySpeed is LOW then Threat is LOW", &engine));
  153. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemyShooters is FEW then Threat is LOW", &engine));
  154. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurSpeed is LOW and EnemyShooters is MANY then Threat is HIGH", &engine));
  155. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurSpeed is HIGH and EnemyShooters is MANY then Threat is LOW", &engine));
  156. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurWalkers is FEW and EnemyShooters is MANY then Threat is somewhat LOW", &engine));
  157. ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemySpeed is HIGH then Threat is somewhat HIGH", &engine));
  158. //just to cover all cases
  159. ta.tacticalAdvantage.addRule(fl::Rule::parse("if EnemySpeed is MEDIUM then Threat is MEDIUM", &engine));
  160. ta.tacticalAdvantage.addRule(fl::Rule::parse("if EnemySpeed is LOW and OurShooters is FEW then Threat is MEDIUM", &engine));
  161. ta.tacticalAdvantage.addRule(fl::Rule::parse("if Bank is TRUE and OurShooters is MANY then Threat is somewhat HIGH", &engine));
  162. ta.tacticalAdvantage.addRule(fl::Rule::parse("if Bank is TRUE and EnemyShooters is MANY then Threat is LOW", &engine));
  163. ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is HIGH and OurWalkers is MANY then Threat is very HIGH", &engine));
  164. ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is HIGH and OurFlyers is MANY and OurShooters is MANY then Threat is MEDIUM", &engine));
  165. ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is MEDIUM and OurShooters is MANY and EnemyWalkers is MANY then Threat is LOW", &engine));
  166. }
  167. catch (fl::Exception & pe)
  168. {
  169. logAi->errorStream() << "initTacticalAdvantage " << ": " << pe.getWhat();
  170. }
  171. }
  172. ui64 FuzzyHelper::estimateBankDanger (const CBank * bank)
  173. {
  174. auto info = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance);
  175. ui64 val = std::numeric_limits<ui64>::max();
  176. try
  177. {
  178. fl::Triangle* bank0 = dynamic_cast<fl::Triangle*> (bankDanger->getTerm("Bank0"));
  179. fl::Triangle* bank1 = dynamic_cast<fl::Triangle*> (bankDanger->getTerm("Bank1"));
  180. if (bank0 && bank1)
  181. {
  182. bank0->setVertexA(info->minGuards().totalStrength * 0.5f);
  183. bank0->setVertexC(info->minGuards().totalStrength * 1.5f);
  184. bank1->setVertexA(info->maxGuards().totalStrength * 0.5f);
  185. bank1->setVertexC(info->maxGuards().totalStrength * 1.5f);
  186. }
  187. //comparison purposes
  188. //int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
  189. //dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5);
  190. bankInput->setInputValue(0.5);
  191. //engine.process(BANK_DANGER);//TODO: Process Bank_Dange only
  192. engine.process(); //TODO: Process Bank_Dange only
  193. val = bankDanger->getOutputValue(); //some expected value of this bank
  194. }
  195. catch (fl::Exception & fe)
  196. {
  197. logAi->errorStream() << "estimateBankDanger " << ": " << fe.getWhat();
  198. }
  199. return val;
  200. }
  201. float FuzzyHelper::getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy)
  202. {
  203. float output = 1;
  204. try
  205. {
  206. armyStructure ourStructure = evaluateArmyStructure(we);
  207. armyStructure enemyStructure = evaluateArmyStructure(enemy);
  208. ta.ourWalkers->setInputValue(ourStructure.walkers);
  209. ta.ourShooters->setInputValue(ourStructure.shooters);
  210. ta.ourFlyers->setInputValue(ourStructure.flyers);
  211. ta.ourSpeed->setInputValue(ourStructure.maxSpeed);
  212. ta.enemyWalkers->setInputValue(enemyStructure.walkers);
  213. ta.enemyShooters->setInputValue(enemyStructure.shooters);
  214. ta.enemyFlyers->setInputValue(enemyStructure.flyers);
  215. ta.enemySpeed->setInputValue(enemyStructure.maxSpeed);
  216. bool bank = dynamic_cast<const CBank*> (enemy);
  217. if (bank)
  218. ta.bankPresent->setInputValue(1);
  219. else
  220. ta.bankPresent->setInputValue(0);
  221. const CGTownInstance * fort = dynamic_cast<const CGTownInstance*> (enemy);
  222. if (fort)
  223. {
  224. ta.castleWalls->setInputValue(fort->fortLevel());
  225. }
  226. else
  227. ta.castleWalls->setInputValue(0);
  228. //engine.process(TACTICAL_ADVANTAGE);//TODO: Process only Tactical_Advantage
  229. engine.process();
  230. output = ta.threat->getOutputValue();
  231. }
  232. catch (fl::Exception & fe)
  233. {
  234. logAi->errorStream() << "getTacticalAdvantage " << ": " << fe.getWhat();
  235. }
  236. return output;
  237. }
  238. FuzzyHelper::TacticalAdvantage::~TacticalAdvantage()
  239. {
  240. //TODO: smart pointers?
  241. delete ourWalkers;
  242. delete ourShooters;
  243. delete ourFlyers;
  244. delete enemyWalkers;
  245. delete enemyShooters;
  246. delete enemyFlyers;
  247. delete ourSpeed;
  248. delete enemySpeed;
  249. delete bankPresent;
  250. delete castleWalls;
  251. delete threat;
  252. }
  253. //shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec)
  254. Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
  255. {
  256. if (vec.empty()) //no possibilities found
  257. return sptr(Goals::Invalid());
  258. //a trick to switch between heroes less often - calculatePaths is costly
  259. auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
  260. {
  261. return lhs->hero.h < rhs->hero.h;
  262. };
  263. boost::sort (vec, sortByHeroes);
  264. for (auto g : vec)
  265. {
  266. setPriority(g);
  267. }
  268. auto compareGoals = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
  269. {
  270. return lhs->priority < rhs->priority;
  271. };
  272. boost::sort (vec, compareGoals);
  273. return vec.back();
  274. }
  275. float FuzzyHelper::evaluate (Goals::Explore & g)
  276. {
  277. return 1;
  278. }
  279. float FuzzyHelper::evaluate (Goals::RecruitHero & g)
  280. {
  281. return 1; //just try to recruit hero as one of options
  282. }
  283. FuzzyHelper::EvalVisitTile::~EvalVisitTile()
  284. {
  285. delete strengthRatio;
  286. delete heroStrength;
  287. delete turnDistance;
  288. delete missionImportance;
  289. }
  290. void FuzzyHelper::initVisitTile()
  291. {
  292. try
  293. {
  294. vt.strengthRatio = new fl::InputVariable("strengthRatio"); //hero must be strong enough to defeat guards
  295. vt.heroStrength = new fl::InputVariable("heroStrength"); //we want to use weakest possible hero
  296. vt.turnDistance = new fl::InputVariable("turnDistance"); //we want to use hero who is near
  297. vt.missionImportance = new fl::InputVariable("lockedMissionImportance"); //we may want to preempt hero with low-priority mission
  298. vt.value = new fl::OutputVariable("Value");
  299. std::vector<fl::InputVariable*> helper = {vt.strengthRatio, vt.heroStrength, vt.turnDistance, vt.missionImportance};
  300. for (auto val : helper)
  301. {
  302. engine.addInputVariable(val);
  303. }
  304. engine.addOutputVariable(vt.value);
  305. vt.strengthRatio->addTerm(new fl::Ramp("LOW", SAFE_ATTACK_CONSTANT, 0));
  306. vt.strengthRatio->addTerm(new fl::Ramp("HIGH", SAFE_ATTACK_CONSTANT, SAFE_ATTACK_CONSTANT * 3));
  307. //strength compared to our main hero
  308. vt.heroStrength->addTerm(new fl::Ramp("LOW", 0.2, 0));
  309. vt.heroStrength->addTerm(new fl::Triangle("MEDIUM", 0.2, 0.8));
  310. vt.heroStrength->addTerm(new fl::Ramp("HIGH", 0.5, 1));
  311. vt.turnDistance->addTerm(new fl::Ramp("SMALL", 0.5, 0));
  312. vt.turnDistance->addTerm(new fl::Triangle("MEDIUM", 0.1, 0.8));
  313. vt.turnDistance->addTerm(new fl::Ramp("LONG", 0.5, 3));
  314. vt.missionImportance->addTerm(new fl::Ramp("LOW", 2.5, 0));
  315. vt.missionImportance->addTerm(new fl::Triangle("MEDIUM", 2, 3));
  316. vt.missionImportance->addTerm(new fl::Ramp("HIGH", 2.5, 5));
  317. //an issue: in 99% cases this outputs center of mass (2.5) regardless of actual input :/
  318. //should be same as "mission Importance" to keep consistency
  319. vt.value->addTerm(new fl::Ramp("LOW", 2.5, 0));
  320. vt.value->addTerm(new fl::Triangle("MEDIUM", 2, 3)); //can't be center of mass :/
  321. vt.value->addTerm(new fl::Ramp("HIGH", 2.5, 5));
  322. engine.addRuleBlock (&vt.rules);
  323. //use unarmed scouts if possible
  324. vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is LOW then Value is very HIGH", &engine));
  325. //we may want to use secondary hero(es) rather than main hero
  326. vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is MEDIUM then Value is somewhat HIGH", &engine));
  327. vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is HIGH then Value is somewhat LOW", &engine));
  328. //don't assign targets to heroes who are too weak, but prefer targets of our main hero (in case we need to gather army)
  329. vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is LOW then Value is very LOW", &engine));
  330. //attempt to arm secondary heroes is not stupid
  331. vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is MEDIUM then Value is somewhat HIGH", &engine));
  332. vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is HIGH then Value is LOW", &engine));
  333. //do not cancel important goals
  334. vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is HIGH then Value is very LOW", &engine));
  335. vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is MEDIUM then Value is somewhat LOW", &engine));
  336. vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is LOW then Value is HIGH", &engine));
  337. //pick nearby objects if it's easy, avoid long walks
  338. vt.rules.addRule(fl::Rule::parse("if turnDistance is SMALL then Value is HIGH", &engine));
  339. vt.rules.addRule(fl::Rule::parse("if turnDistance is MEDIUM then Value is MEDIUM", &engine));
  340. vt.rules.addRule(fl::Rule::parse("if turnDistance is LONG then Value is LOW", &engine));
  341. }
  342. catch (fl::Exception & fe)
  343. {
  344. logAi->errorStream() << "visitTile " << ": " << fe.getWhat();
  345. }
  346. }
  347. float FuzzyHelper::evaluate (Goals::VisitTile & g)
  348. {
  349. //we assume that hero is already set and we want to choose most suitable one for the mission
  350. if (!g.hero)
  351. return 0;
  352. //assert(cb->isInTheMap(g.tile));
  353. float turns = 0;
  354. float distance = cb->getMovementCost(g.hero.h, g.tile);
  355. if (!distance) //we stand on that tile
  356. turns = 0;
  357. else
  358. {
  359. if (distance < g.hero->movement) //we can move there within one turn
  360. turns = (fl::scalar)distance / g.hero->movement;
  361. else
  362. turns = 1 + (fl::scalar)(distance - g.hero->movement) / g.hero->maxMovePoints(true); //bool on land?
  363. }
  364. float missionImportance = 0;
  365. if (vstd::contains(ai->lockedHeroes, g.hero))
  366. missionImportance = ai->lockedHeroes[g.hero]->priority;
  367. float strengthRatio = 10.0f; //we are much stronger than enemy
  368. ui64 danger = evaluateDanger (g.tile, g.hero.h);
  369. if (danger)
  370. strengthRatio = (fl::scalar)g.hero.h->getTotalStrength() / danger;
  371. try
  372. {
  373. vt.strengthRatio->setInputValue(strengthRatio);
  374. vt.heroStrength->setInputValue((fl::scalar)g.hero->getTotalStrength() / ai->primaryHero()->getTotalStrength());
  375. vt.turnDistance->setInputValue(turns);
  376. vt.missionImportance->setInputValue(missionImportance);
  377. engine.process();
  378. //engine.process(VISIT_TILE); //TODO: Process only Visit_Tile
  379. g.priority = vt.value->getOutputValue();
  380. }
  381. catch (fl::Exception & fe)
  382. {
  383. logAi->errorStream() << "evaluate VisitTile " << ": " << fe.getWhat();
  384. }
  385. return g.priority;
  386. }
  387. float FuzzyHelper::evaluate (Goals::VisitHero & g)
  388. {
  389. auto obj = cb->getObj(ObjectInstanceID(g.objid)); //we assume for now that these goals are similar
  390. if (!obj)
  391. return -100; //hero died in the meantime
  392. //TODO: consider direct copy (constructor?)
  393. g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
  394. return g.priority;
  395. }
  396. float FuzzyHelper::evaluate (Goals::GatherArmy & g)
  397. {
  398. //the more army we need, the more important goal
  399. //the more army we lack, the less important goal
  400. float army = g.hero->getArmyStrength();
  401. return g.value / std::max(g.value - army, 1000.0f);
  402. }
  403. float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
  404. {
  405. if (!g.hero.h)
  406. throw cannotFulfillGoalException("ClearWayTo called without hero!");
  407. SectorMap sm(g.hero);
  408. int3 t = sm.firstTileToGet(g.hero, g.tile);
  409. if (t.valid())
  410. {
  411. if (isSafeToVisit(g.hero, t))
  412. {
  413. g.setpriority(Goals::VisitTile(g.tile).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
  414. }
  415. else
  416. {
  417. g.setpriority (Goals::GatherArmy(evaluateDanger(t, g.hero.h)*SAFE_ATTACK_CONSTANT).
  418. sethero(g.hero).setisAbstract(true).accept(this));
  419. }
  420. return g.priority;
  421. }
  422. else
  423. return -1;
  424. }
  425. float FuzzyHelper::evaluate (Goals::BuildThis & g)
  426. {
  427. return 1;
  428. }
  429. float FuzzyHelper::evaluate (Goals::DigAtTile & g)
  430. {
  431. return 0;
  432. }
  433. float FuzzyHelper::evaluate (Goals::CollectRes & g)
  434. {
  435. return 0;
  436. }
  437. float FuzzyHelper::evaluate (Goals::Build & g)
  438. {
  439. return 0;
  440. }
  441. float FuzzyHelper::evaluate (Goals::Invalid & g)
  442. {
  443. return -1e10;
  444. }
  445. float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
  446. {
  447. logAi->warnStream() << boost::format("Cannot evaluate goal %s") % g.name();
  448. return g.priority;
  449. }
  450. void FuzzyHelper::setPriority (Goals::TSubgoal & g)
  451. {
  452. g->setpriority(g->accept(this)); //this enforces returned value is set
  453. }