TGoalVec Conquer::getAllPossibleSubgoals() { TGoalVec ret; auto conquerable = [](const CGObjectInstance * obj) -> bool { if (cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES) { switch (obj->ID.num) { case Obj::TOWN: case Obj::HERO: case Obj::CREATURE_GENERATOR1: case Obj::MINE: //TODO: check ai->knownSubterraneanGates return true; } } return false; }; std::vector<const CGObjectInstance *> objs; for (auto obj : ai->visitableObjs) { if (conquerable(obj)) objs.push_back (obj); } for (auto h : cb->getHeroesInfo()) { SectorMap sm(h); std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero { if (conquerable(obj)) ourObjs.push_back(obj); } for (auto obj : ourObjs) //double loop, performance risk? { auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded ai->whatToDoToReachTile (h, t, ret); } } if (!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture ret.push_back (sptr(Goals::RecruitHero())); if (ret.empty()) ret.push_back (sptr(Goals::Explore())); //we need to find an enemy return ret; }
TGoalVec Explore::getAllPossibleSubgoals() { TGoalVec ret; std::vector<const CGHeroInstance *> heroes; //std::vector<HeroPtr> heroes; if (hero) //heroes.push_back(hero); heroes.push_back(hero.h); else { //heroes = ai->getUnblockedHeroes(); heroes = cb->getHeroesInfo(); erase_if (heroes, [](const HeroPtr h) { if (vstd::contains(ai->lockedHeroes, h)) if (ai->lockedHeroes[h]->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer return true; return !h->movement; //saves time, immobile heroes are useless anyway }); } //try to use buildings that uncover map std::vector<const CGObjectInstance *> objs; for (auto obj : ai->visitableObjs) { if (!vstd::contains(ai->alreadyVisited, obj)) { switch (obj->ID.num) { case Obj::REDWOOD_OBSERVATORY: case Obj::PILLAR_OF_FIRE: case Obj::CARTOGRAPHER: case Obj::SUBTERRANEAN_GATE: //TODO: check ai->knownSubterraneanGates objs.push_back (obj); } } } for (auto h : heroes) { SectorMap sm(h); for (auto obj : objs) //double loop, performance risk? { auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded ai->whatToDoToReachTile(h, t, ret); } int3 t = whereToExplore(h); if (t.valid()) { ret.push_back (sptr (Goals::VisitTile(t).sethero(h))); } else if (hero.h == h || (!hero && h == ai->primaryHero().h)) //check this only ONCE, high cost { t = ai->explorationDesperate(h); ai->whatToDoToReachTile(h, t, ret); } } //we either don't have hero yet or none of heroes can explore if ((!hero || ret.empty()) && ai->canRecruitAnyHero()) ret.push_back (sptr(Goals::RecruitHero())); //if (ret.empty()) //{ // for (auto h : heroes) //this is costly function, use only when there is no other way // { // auto t = ai->explorationDesperate (h); //we assume that no more than one tile on the way is guarded // if (t.valid()) // { // if (isSafeToVisit(h, t)) // { // ret.push_back (sptr (Goals::VisitTile(t).sethero(h))); // } // else // { // ret.push_back (sptr (Goals::GatherArmy(evaluateDanger(t, h)*SAFE_ATTACK_CONSTANT). // sethero(h).setisAbstract(true))); // } // } // } //} if (ret.empty()) { throw goalFulfilledException (sptr(Goals::Explore().sethero(hero))); } //throw cannotFulfillGoalException("Cannot explore - no possible ways found!"); return ret; }