mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-14 10:12:59 +02:00
AI-variant without fuzzy-logic
It is now possible to switch to an AI-variant that uses hand-written heuristics for decision-making rather than the FuzzyLite-engine. This is configurable in nkai-settings.json via the new parameter "useFuzzy".
This commit is contained in:
parent
aa891cb8b1
commit
7b407b6432
@ -469,7 +469,9 @@ void ObjectClusterizer::clusterizeObject(
|
|||||||
|
|
||||||
float priority = priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
|
float priority = priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
|
||||||
|
|
||||||
if(priority < MIN_PRIORITY)
|
if(ai->settings->isUseFuzzy() && priority < MIN_PRIORITY)
|
||||||
|
continue;
|
||||||
|
else if (priority <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ClusterMap::accessor cluster;
|
ClusterMap::accessor cluster;
|
||||||
@ -490,7 +492,9 @@ void ObjectClusterizer::clusterizeObject(
|
|||||||
|
|
||||||
float priority = priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
|
float priority = priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
|
||||||
|
|
||||||
if(priority < MIN_PRIORITY)
|
if (ai->settings->isUseFuzzy() && priority < MIN_PRIORITY)
|
||||||
|
continue;
|
||||||
|
else if (priority <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool interestingObject = path.turn() <= 2 || priority > 0.5f;
|
bool interestingObject = path.turn() <= 2 || priority > 0.5f;
|
||||||
|
@ -1113,36 +1113,71 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
|
|
||||||
double result = 0;
|
double result = 0;
|
||||||
|
|
||||||
try
|
bool useFuzzy = ai->settings->isUseFuzzy();
|
||||||
|
|
||||||
|
if (task->hero)
|
||||||
{
|
{
|
||||||
armyLossPersentageVariable->setValue(evaluationContext.armyLossPersentage);
|
if (task->hero->getOwner().getNum() > 1)
|
||||||
heroRoleVariable->setValue(evaluationContext.heroRole);
|
useFuzzy = true;
|
||||||
mainTurnDistanceVariable->setValue(evaluationContext.movementCostByRole[HeroRole::MAIN]);
|
|
||||||
scoutTurnDistanceVariable->setValue(evaluationContext.movementCostByRole[HeroRole::SCOUT]);
|
|
||||||
goldRewardVariable->setValue(goldRewardPerTurn);
|
|
||||||
armyRewardVariable->setValue(evaluationContext.armyReward);
|
|
||||||
armyGrowthVariable->setValue(evaluationContext.armyGrowth);
|
|
||||||
skillRewardVariable->setValue(evaluationContext.skillReward);
|
|
||||||
dangerVariable->setValue(evaluationContext.danger);
|
|
||||||
rewardTypeVariable->setValue(rewardType);
|
|
||||||
closestHeroRatioVariable->setValue(evaluationContext.closestWayRatio);
|
|
||||||
strategicalValueVariable->setValue(evaluationContext.strategicalValue);
|
|
||||||
goldPressureVariable->setValue(ai->buildAnalyzer->getGoldPressure());
|
|
||||||
goldCostVariable->setValue(evaluationContext.goldCost / ((float)ai->getFreeResources()[EGameResID::GOLD] + (float)ai->buildAnalyzer->getDailyIncome()[EGameResID::GOLD] + 1.0f));
|
|
||||||
turnVariable->setValue(evaluationContext.turn);
|
|
||||||
fearVariable->setValue(evaluationContext.enemyHeroDangerRatio);
|
|
||||||
|
|
||||||
engine->process();
|
|
||||||
|
|
||||||
result = value->getValue();
|
|
||||||
}
|
}
|
||||||
catch(fl::Exception & fe)
|
|
||||||
|
if (useFuzzy)
|
||||||
{
|
{
|
||||||
logAi->error("evaluate VisitTile: %s", fe.getWhat());
|
try
|
||||||
|
{
|
||||||
|
armyLossPersentageVariable->setValue(evaluationContext.armyLossPersentage);
|
||||||
|
heroRoleVariable->setValue(evaluationContext.heroRole);
|
||||||
|
mainTurnDistanceVariable->setValue(evaluationContext.movementCostByRole[HeroRole::MAIN]);
|
||||||
|
scoutTurnDistanceVariable->setValue(evaluationContext.movementCostByRole[HeroRole::SCOUT]);
|
||||||
|
goldRewardVariable->setValue(goldRewardPerTurn);
|
||||||
|
armyRewardVariable->setValue(evaluationContext.armyReward);
|
||||||
|
armyGrowthVariable->setValue(evaluationContext.armyGrowth);
|
||||||
|
skillRewardVariable->setValue(evaluationContext.skillReward);
|
||||||
|
dangerVariable->setValue(evaluationContext.danger);
|
||||||
|
rewardTypeVariable->setValue(rewardType);
|
||||||
|
closestHeroRatioVariable->setValue(evaluationContext.closestWayRatio);
|
||||||
|
strategicalValueVariable->setValue(evaluationContext.strategicalValue);
|
||||||
|
goldPressureVariable->setValue(ai->buildAnalyzer->getGoldPressure());
|
||||||
|
goldCostVariable->setValue(evaluationContext.goldCost / ((float)ai->getFreeResources()[EGameResID::GOLD] + (float)ai->buildAnalyzer->getDailyIncome()[EGameResID::GOLD] + 1.0f));
|
||||||
|
turnVariable->setValue(evaluationContext.turn);
|
||||||
|
fearVariable->setValue(evaluationContext.enemyHeroDangerRatio);
|
||||||
|
|
||||||
|
engine->process();
|
||||||
|
|
||||||
|
result = value->getValue();
|
||||||
|
}
|
||||||
|
catch (fl::Exception& fe)
|
||||||
|
{
|
||||||
|
logAi->error("evaluate VisitTile: %s", fe.getWhat());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float score = evaluationContext.armyReward + evaluationContext.skillReward * 2000 + std::max((float)evaluationContext.goldReward, std::max((float)evaluationContext.armyGrowth, evaluationContext.strategicalValue * 1000));
|
||||||
|
|
||||||
|
if (task->hero)
|
||||||
|
{
|
||||||
|
score -= evaluationContext.armyLossPersentage * task->hero->getArmyCost();
|
||||||
|
if (evaluationContext.enemyHeroDangerRatio > 1)
|
||||||
|
score /= evaluationContext.enemyHeroDangerRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > 0)
|
||||||
|
{
|
||||||
|
result = score * evaluationContext.closestWayRatio / evaluationContext.movementCost;
|
||||||
|
if (task->hero)
|
||||||
|
{
|
||||||
|
if (task->hero->getArmyCost() > score
|
||||||
|
&& evaluationContext.strategicalValue == 0)
|
||||||
|
result /= task->hero->getArmyCost() / score;
|
||||||
|
//logAi->trace("Score %s: %f Armyreward: %f skillReward: %f GoldReward: %f Strategical: %f Armygrowth: %f", task->toString(), score, evaluationContext.armyReward, evaluationContext.skillReward, evaluationContext.goldReward, evaluationContext.strategicalValue, evaluationContext.armyGrowth);
|
||||||
|
logAi->trace("Score %s: %f Cost: %f Dist: %f Armygrowth: %f Prio: %f", task->toString(), score, task->hero->getArmyCost(), evaluationContext.movementCost, evaluationContext.armyGrowth, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NKAI_TRACE_LEVEL >= 2
|
#if NKAI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %f, cost: %d, army gain: %f, danger: %d, role: %s, strategical value: %f, cwr: %f, fear: %f, result %f",
|
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %f, cost: %d, army gain: %f, skill: %f danger: %d, role: %s, strategical value: %f, cwr: %f, fear: %f, result %f",
|
||||||
task->toString(),
|
task->toString(),
|
||||||
evaluationContext.armyLossPersentage,
|
evaluationContext.armyLossPersentage,
|
||||||
(int)evaluationContext.turn,
|
(int)evaluationContext.turn,
|
||||||
@ -1151,6 +1186,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
goldRewardPerTurn,
|
goldRewardPerTurn,
|
||||||
evaluationContext.goldCost,
|
evaluationContext.goldCost,
|
||||||
evaluationContext.armyReward,
|
evaluationContext.armyReward,
|
||||||
|
evaluationContext.skillReward,
|
||||||
evaluationContext.danger,
|
evaluationContext.danger,
|
||||||
evaluationContext.heroRole == HeroRole::MAIN ? "main" : "scout",
|
evaluationContext.heroRole == HeroRole::MAIN ? "main" : "scout",
|
||||||
evaluationContext.strategicalValue,
|
evaluationContext.strategicalValue,
|
||||||
|
@ -30,7 +30,8 @@ namespace NKAI
|
|||||||
maxpass(10),
|
maxpass(10),
|
||||||
allowObjectGraph(true),
|
allowObjectGraph(true),
|
||||||
useTroopsFromGarrisons(false),
|
useTroopsFromGarrisons(false),
|
||||||
openMap(true)
|
openMap(true),
|
||||||
|
useFuzzy(false)
|
||||||
{
|
{
|
||||||
JsonNode node = JsonUtils::assembleFromFiles("config/ai/nkai/nkai-settings");
|
JsonNode node = JsonUtils::assembleFromFiles("config/ai/nkai/nkai-settings");
|
||||||
|
|
||||||
@ -69,6 +70,11 @@ namespace NKAI
|
|||||||
openMap = node.Struct()["openMap"].Bool();
|
openMap = node.Struct()["openMap"].Bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!node.Struct()["useFuzzy"].isNull())
|
||||||
|
{
|
||||||
|
useFuzzy = node.Struct()["useFuzzy"].Bool();
|
||||||
|
}
|
||||||
|
|
||||||
if(!node.Struct()["useTroopsFromGarrisons"].isNull())
|
if(!node.Struct()["useTroopsFromGarrisons"].isNull())
|
||||||
{
|
{
|
||||||
useTroopsFromGarrisons = node.Struct()["useTroopsFromGarrisons"].Bool();
|
useTroopsFromGarrisons = node.Struct()["useTroopsFromGarrisons"].Bool();
|
||||||
|
@ -29,6 +29,7 @@ namespace NKAI
|
|||||||
bool allowObjectGraph;
|
bool allowObjectGraph;
|
||||||
bool useTroopsFromGarrisons;
|
bool useTroopsFromGarrisons;
|
||||||
bool openMap;
|
bool openMap;
|
||||||
|
bool useFuzzy;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Settings();
|
Settings();
|
||||||
@ -41,5 +42,6 @@ namespace NKAI
|
|||||||
bool isObjectGraphAllowed() const { return allowObjectGraph; }
|
bool isObjectGraphAllowed() const { return allowObjectGraph; }
|
||||||
bool isGarrisonTroopsUsageAllowed() const { return useTroopsFromGarrisons; }
|
bool isGarrisonTroopsUsageAllowed() const { return useTroopsFromGarrisons; }
|
||||||
bool isOpenMap() const { return openMap; }
|
bool isOpenMap() const { return openMap; }
|
||||||
|
bool isUseFuzzy() const { return useFuzzy; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": true
|
"allowObjectGraph": false
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user