1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Nullkiller: parallel object clusterization, stabilization

This commit is contained in:
Andrii Danylchenko
2021-05-16 15:08:56 +03:00
committed by Andrii Danylchenko
parent 66843b22d3
commit 9a203b8af9
14 changed files with 332 additions and 165 deletions

View File

@@ -29,8 +29,6 @@
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
extern boost::thread_specific_ptr<CCallback> cb;
EvaluationContext::EvaluationContext(const Nullkiller * ai)
: movementCost(0.0),
manaCost(0),
@@ -78,7 +76,7 @@ void PriorityEvaluator::initVisitTile()
value = engine->getOutputVariable("Value");
}
int32_t estimateTownIncome(const CGObjectInstance * target, const CGHeroInstance * hero)
int32_t estimateTownIncome(CCallback * cb, const CGObjectInstance * target, const CGHeroInstance * hero)
{
auto relations = cb->getPlayerRelations(hero->tempOwner, target->tempOwner);
@@ -116,7 +114,7 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
return result;
}
uint64_t getDwellingScore(const CGObjectInstance * target, bool checkGold)
uint64_t getDwellingScore(CCallback * cb, const CGObjectInstance * target, bool checkGold)
{
auto dwelling = dynamic_cast<const CGDwelling *>(target);
uint64_t score = 0;
@@ -207,14 +205,14 @@ uint64_t RewardEvaluator::getArmyReward(
case Obj::TOWN:
return target->tempOwner == PlayerColor::NEUTRAL ? 1000 : 10000;
case Obj::HILL_FORT:
return ai->armyManager->calculateCreateresUpgrade(army, target, cb->getResourceAmount()).upgradeValue;
return ai->armyManager->calculateCreateresUpgrade(army, target, ai->cb->getResourceAmount()).upgradeValue;
case Obj::CREATURE_BANK:
return getCreatureBankArmyReward(target, hero);
case Obj::CREATURE_GENERATOR1:
case Obj::CREATURE_GENERATOR2:
case Obj::CREATURE_GENERATOR3:
case Obj::CREATURE_GENERATOR4:
return getDwellingScore(target, checkGold);
return getDwellingScore(ai->cb.get(), target, checkGold);
case Obj::CRYPT:
case Obj::SHIPWRECK:
case Obj::SHIPWRECK_SURVIVOR:
@@ -225,7 +223,7 @@ uint64_t RewardEvaluator::getArmyReward(
case Obj::DRAGON_UTOPIA:
return 10000;
case Obj::HERO:
return cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
? enemyArmyEliminationRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->getArmyStrength()
: 0;
default:
@@ -241,7 +239,7 @@ int RewardEvaluator::getGoldCost(const CGObjectInstance * target, const CGHeroIn
switch(target->ID)
{
case Obj::HILL_FORT:
return ai->armyManager->calculateCreateresUpgrade(army, target, cb->getResourceAmount()).upgradeCost[Res::GOLD];
return ai->armyManager->calculateCreateresUpgrade(army, target, ai->cb->getResourceAmount()).upgradeCost[Res::GOLD];
case Obj::SCHOOL_OF_MAGIC:
case Obj::SCHOOL_OF_WAR:
return 1000;
@@ -325,7 +323,7 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
: 0.5f;
case Obj::HERO:
return cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance *>(target))
: 0;
@@ -380,7 +378,7 @@ float RewardEvaluator::getSkillReward(const CGObjectInstance * target, const CGH
case Obj::WITCH_HUT:
return evaluateWitchHutSkillScore(dynamic_cast<const CGWitchHut *>(target), hero, role);
case Obj::HERO:
return cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
? enemyHeroEliminationSkillRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->level
: 0;
default:
@@ -438,7 +436,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
case Obj::WATER_WHEEL:
return 1000;
case Obj::TOWN:
return dailyIncomeMultiplier * estimateTownIncome(target, hero);
return dailyIncomeMultiplier * estimateTownIncome(ai->cb.get(), target, hero);
case Obj::MINE:
case Obj::ABANDONED_MINE:
return dailyIncomeMultiplier * (isGold ? 1000 : 75);
@@ -459,7 +457,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
case Obj::SEA_CHEST:
return 1500;
case Obj::HERO:
return cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
? heroEliminationBonus + enemyArmyEliminationGoldRewardRatio * getArmyCost(dynamic_cast<const CGHeroInstance *>(target))
: 0;
default:
@@ -550,7 +548,12 @@ public:
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
{
private:
const Nullkiller * ai;
public:
ExecuteHeroChainEvaluationContextBuilder(const Nullkiller * ai) : ai(ai) {}
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
{
if(task->goalType != Goals::EXECUTE_HERO_CHAIN)
@@ -578,14 +581,14 @@ public:
}
auto heroPtr = task->hero;
auto day = cb->getDate(Date::DAY);
auto hero = heroPtr.get();
auto day = ai->cb->getDate(Date::DAY);
auto hero = heroPtr.get(ai->cb.get());
bool checkGold = evaluationContext.danger == 0;
auto army = path.heroArmy;
const CGObjectInstance * target = cb->getObj((ObjectInstanceID)task->objid, false);
const CGObjectInstance * target = ai->cb->getObj((ObjectInstanceID)task->objid, false);
if (target && cb->getPlayerRelations(target->tempOwner, hero->tempOwner) == PlayerRelations::ENEMIES)
if (target && ai->cb->getPlayerRelations(target->tempOwner, hero->tempOwner) == PlayerRelations::ENEMIES)
{
evaluationContext.goldReward += evaluationContext.evaluator.getGoldReward(target, hero);
evaluationContext.armyReward += evaluationContext.evaluator.getArmyReward(target, hero, army, checkGold);
@@ -603,7 +606,12 @@ public:
class ClusterEvaluationContextBuilder : public IEvaluationContextBuilder
{
private:
const Nullkiller * ai;
public:
ClusterEvaluationContextBuilder(const Nullkiller * ai) : ai(ai) {}
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
{
if(task->goalType != Goals::UNLOCK_CLUSTER)
@@ -627,7 +635,7 @@ public:
for(auto objInfo : objects)
{
auto target = objInfo.first;
auto day = cb->getDate(Date::DAY);
auto day = ai->cb->getDate(Date::DAY);
bool checkGold = objInfo.second.danger == 0;
auto army = hero;
@@ -709,9 +717,9 @@ PriorityEvaluator::PriorityEvaluator(const Nullkiller * ai)
:ai(ai)
{
initVisitTile();
evaluationContextBuilders.push_back(std::make_shared<ExecuteHeroChainEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<ExecuteHeroChainEvaluationContextBuilder>(ai));
evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>());
evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>(ai));
evaluationContextBuilders.push_back(std::make_shared<HeroExchangeEvaluator>());
evaluationContextBuilders.push_back(std::make_shared<ArmyUpgradeEvaluator>());
evaluationContextBuilders.push_back(std::make_shared<DefendTownEvaluator>());
@@ -769,7 +777,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
closestHeroRatioVariable->setValue(evaluationContext.closestWayRatio);
strategicalValueVariable->setValue(evaluationContext.strategicalValue);
goldPreasureVariable->setValue(ai->buildAnalyzer->getGoldPreasure());
goldCostVariable->setValue(evaluationContext.goldCost / ((float)cb->getResourceAmount(Res::GOLD) + (float)ai->buildAnalyzer->getDailyIncome()[Res::GOLD] + 1.0f));
goldCostVariable->setValue(evaluationContext.goldCost / ((float)ai->cb->getResourceAmount(Res::GOLD) + (float)ai->buildAnalyzer->getDailyIncome()[Res::GOLD] + 1.0f));
turnVariable->setValue(evaluationContext.turn);
fearVariable->setValue(evaluationContext.enemyHeroDangerRatio);