2012-03-03 13:08:01 +03:00
# include "StdInc.h"
# include "Fuzzy.h"
2012-03-12 23:11:46 +03:00
# include <limits>
2012-09-06 13:39:48 +03:00
# include "../../lib/CObjectHandler.h"
# include "../../lib/CCreatureHandler.h"
# include "../../lib/VCMI_Lib.h"
2013-12-20 12:43:12 +03:00
# include "../../CCallback.h"
2013-11-30 10:52:08 +03:00
//#include "Goals.cpp"
2013-12-20 12:43:12 +03:00
# include "VCAI.h"
2012-03-03 13:08:01 +03:00
/*
* Fuzzy . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2012-03-04 13:43:46 +03:00
# define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
2012-05-28 22:29:32 +03:00
struct BankConfig ;
2012-03-03 13:08:01 +03:00
class FuzzyEngine ;
class InputLVar ;
2012-03-04 13:43:46 +03:00
class CGTownInstance ;
using namespace boost : : assign ;
using namespace vstd ;
2013-11-24 11:21:51 +03:00
//using namespace Goals;
2012-03-03 13:08:01 +03:00
2012-03-10 22:14:45 +03:00
FuzzyHelper * fh ;
2012-03-03 13:08:01 +03:00
2013-12-20 12:43:12 +03:00
extern boost : : thread_specific_ptr < CCallback > cb ;
extern boost : : thread_specific_ptr < VCAI > ai ;
2012-03-04 13:43:46 +03:00
struct armyStructure
{
float walkers , shooters , flyers ;
ui32 maxSpeed ;
} ;
2012-03-03 13:08:01 +03:00
ui64 evaluateBankConfig ( BankConfig * bc )
{
ui64 danger = 0 ;
2013-06-29 16:05:48 +03:00
for ( auto opt : bc - > guards )
2012-03-03 13:08:01 +03:00
{
danger + = VLC - > creh - > creatures [ opt . first ] - > fightValue * opt . second ;
}
return danger ;
}
2012-03-04 13:43:46 +03:00
armyStructure evaluateArmyStructure ( const CArmedInstance * army )
{
ui64 totalStrenght = army - > getArmyStrength ( ) ;
double walkersStrenght = 0 ;
double flyersStrenght = 0 ;
double shootersStrenght = 0 ;
ui32 maxSpeed = 0 ;
2013-06-29 16:05:48 +03:00
for ( auto s : army - > Slots ( ) )
2012-03-04 13:43:46 +03:00
{
bool walker = true ;
if ( s . second - > type - > hasBonusOfType ( Bonus : : SHOOTER ) )
{
shootersStrenght + = s . second - > getPower ( ) ;
walker = false ;
}
if ( s . second - > type - > hasBonusOfType ( Bonus : : FLYING ) )
{
flyersStrenght + = s . second - > getPower ( ) ;
walker = false ;
}
if ( walker )
walkersStrenght + = s . second - > getPower ( ) ;
2012-08-30 18:37:43 +03:00
amax ( maxSpeed , s . second - > type - > valOfBonuses ( Bonus : : STACKS_SPEED ) ) ;
2012-03-04 13:43:46 +03:00
}
armyStructure as ;
as . walkers = walkersStrenght / totalStrenght ;
as . shooters = shootersStrenght / totalStrenght ;
as . flyers = flyersStrenght / totalStrenght ;
as . maxSpeed = maxSpeed ;
return as ;
}
2012-03-03 13:08:01 +03:00
FuzzyHelper : : FuzzyHelper ( )
2012-03-04 13:43:46 +03:00
{
2013-12-20 12:43:12 +03:00
engine . hedgeSet ( ) . add ( new fl : : HedgeSomewhat ( ) ) ;
engine . hedgeSet ( ) . add ( new fl : : HedgeVery ( ) ) ;
2012-03-04 13:43:46 +03:00
initBank ( ) ;
initTacticalAdvantage ( ) ;
2013-12-20 12:43:12 +03:00
initVisitTile ( ) ;
2012-03-04 13:43:46 +03:00
}
void FuzzyHelper : : initBank ( )
2012-03-03 13:08:01 +03:00
{
2012-03-03 14:39:54 +03:00
try
{
2012-03-04 13:43:46 +03:00
//Trivial bank estimation
2012-03-03 14:39:54 +03:00
bankInput = new fl : : InputLVar ( " BankInput " ) ;
bankDanger = new fl : : OutputLVar ( " BankDanger " ) ;
bankInput - > addTerm ( new fl : : SingletonTerm ( " SET " ) ) ;
2012-03-03 13:08:01 +03:00
2012-03-04 13:43:46 +03:00
engine . addRuleBlock ( & bankBlock ) ; //have to be added before the rules are parsed
2012-03-03 14:39:54 +03:00
engine . addInputLVar ( bankInput ) ;
engine . addOutputLVar ( bankDanger ) ;
for ( int i = 0 ; i < 4 ; + + i )
{
bankDanger - > addTerm ( new fl : : TriangularTerm ( " Bank " + boost : : lexical_cast < std : : string > ( i ) , 0 , 1 ) ) ;
2012-03-04 13:43:46 +03:00
bankBlock . addRule ( new fl : : MamdaniRule ( " if BankInput is SET then BankDanger is Bank " + boost : : lexical_cast < std : : string > ( i ) , engine ) ) ;
2012-03-03 14:39:54 +03:00
}
}
2013-11-07 15:48:41 +03:00
catch ( fl : : FuzzyException & fe )
2012-03-03 13:08:01 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < " initBank " < < fe . name ( ) < < " : " < < fe . message ( ) ;
2012-03-04 13:43:46 +03:00
}
}
void FuzzyHelper : : initTacticalAdvantage ( )
{
try
{
//Tactical advantage calculation
std : : vector < fl : : InputLVar * > helper ;
2013-12-20 12:43:12 +03:00
//TODO: delete all that stuff upon destruction
ta . ourShooters = new fl : : InputLVar ( " OurShooters " ) ;
ta . ourWalkers = new fl : : InputLVar ( " OurWalkers " ) ;
ta . ourFlyers = new fl : : InputLVar ( " OurFlyers " ) ;
ta . enemyShooters = new fl : : InputLVar ( " EnemyShooters " ) ;
ta . enemyWalkers = new fl : : InputLVar ( " EnemyWalkers " ) ;
ta . enemyFlyers = new fl : : InputLVar ( " EnemyFlyers " ) ;
helper + = ta . ourShooters , ta . ourWalkers , ta . ourFlyers , ta . enemyShooters , ta . enemyWalkers , ta . enemyFlyers ;
2012-03-04 13:43:46 +03:00
2013-06-29 16:05:48 +03:00
for ( auto val : helper )
2012-03-04 13:43:46 +03:00
{
val - > addTerm ( new fl : : ShoulderTerm ( " FEW " , 0 , 0.75 , true ) ) ;
val - > addTerm ( new fl : : ShoulderTerm ( " MANY " , 0.25 , 1 , false ) ) ;
engine . addInputLVar ( val ) ;
}
helper . clear ( ) ;
2013-12-20 12:43:12 +03:00
ta . ourSpeed = new fl : : InputLVar ( " OurSpeed " ) ;
ta . enemySpeed = new fl : : InputLVar ( " EnemySpeed " ) ;
2012-03-04 13:43:46 +03:00
2013-12-20 12:43:12 +03:00
helper + = ta . ourSpeed , ta . enemySpeed ;
2012-03-04 13:43:46 +03:00
2013-06-29 16:05:48 +03:00
for ( auto val : helper )
2012-03-04 13:43:46 +03:00
{
2012-03-04 14:19:34 +03:00
val - > addTerm ( new fl : : ShoulderTerm ( " LOW " , 3 , 8.1 , true ) ) ;
val - > addTerm ( new fl : : TriangularTerm ( " MEDIUM " , 6.9 , 13.1 ) ) ;
val - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , 10.5 , 16 , false ) ) ;
2012-03-04 13:43:46 +03:00
engine . addInputLVar ( val ) ;
}
2013-12-20 12:43:12 +03:00
ta . castleWalls = new fl : : InputLVar ( " CastleWalls " ) ;
ta . castleWalls - > addTerm ( new fl : : SingletonTerm ( " NONE " , CGTownInstance : : NONE ) ) ;
ta . castleWalls - > addTerm ( new fl : : TrapezoidalTerm ( " MEDIUM " , CGTownInstance : : FORT , 2.5 ) ) ;
ta . castleWalls - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , CGTownInstance : : CITADEL - 0.1 , CGTownInstance : : CASTLE ) ) ;
engine . addInputLVar ( ta . castleWalls ) ;
ta . bankPresent = new fl : : InputLVar ( " Bank " ) ;
ta . bankPresent - > addTerm ( new fl : : SingletonTerm ( " FALSE " , 0 ) ) ;
ta . bankPresent - > addTerm ( new fl : : SingletonTerm ( " TRUE " , 1 ) ) ;
engine . addInputLVar ( ta . bankPresent ) ;
ta . threat = new fl : : OutputLVar ( " Threat " ) ;
ta . threat - > addTerm ( new fl : : TriangularTerm ( " LOW " , MIN_AI_STRENGHT , 1 ) ) ;
ta . threat - > addTerm ( new fl : : TriangularTerm ( " MEDIUM " , 0.8 , 1.2 ) ) ;
ta . threat - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , 1 , 1.5 , false ) ) ;
engine . addOutputLVar ( ta . threat ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if OurShooters is MANY and EnemySpeed is LOW then Threat is very LOW " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if OurSpeed is LOW and OurShooters is FEW and EnemyShooters is MANY then Threat is very HIGH " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if (OurShooters is MANY and OurFlyers is MANY) and EnemyShooters is MANY then Threat is LOW " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if OurShooters is MANY and EnemySpeed is HIGH then Threat is somewhat HIGH " , engine ) ) ;
2012-03-04 13:43:46 +03:00
//tacticalAdvantage.addRule(new fl::MamdaniRule("if OurShooters is MANY and EnemyShooters is MANY then Threat is MEDIUM", engine));
2013-12-20 12:43:12 +03:00
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if Bank is TRUE and OurShooters is MANY then Threat is somewhat HIGH " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if Bank is TRUE and EnemyShooters is MANY then Threat is LOW " , engine ) ) ;
2012-03-04 13:43:46 +03:00
2013-12-20 12:43:12 +03:00
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if CastleWalls is HIGH and OurWalkers is MANY then Threat is very HIGH " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if CastleWalls is HIGH and OurFlyers is MANY and OurShooters is MANY then Threat is MEDIUM " , engine ) ) ;
ta . tacticalAdvantage . addRule ( new fl : : MamdaniRule ( " if CastleWalls is MEDIUM and OurShooters is MANY and EnemyWalkers is MANY then Threat is LOW " , engine ) ) ;
2012-03-04 13:43:46 +03:00
2013-12-20 12:43:12 +03:00
engine . addRuleBlock ( & ta . tacticalAdvantage ) ;
2012-03-04 13:43:46 +03:00
}
2013-11-07 15:48:41 +03:00
catch ( fl : : ParsingException & pe )
2012-03-04 13:43:46 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < " initTacticalAdvantage " < < pe . name ( ) < < " : " < < pe . message ( ) ;
2012-03-04 13:43:46 +03:00
}
2013-11-07 15:48:41 +03:00
catch ( fl : : FuzzyException & fe )
2012-03-04 13:43:46 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < " initTacticalAdvantage " < < fe . name ( ) < < " : " < < fe . message ( ) ;
2012-03-03 13:08:01 +03:00
}
}
ui64 FuzzyHelper : : estimateBankDanger ( int ID )
{
std : : vector < ConstTransitivePtr < BankConfig > > & configs = VLC - > objh - > banksInfo [ ID ] ;
2012-03-12 23:11:46 +03:00
ui64 val = std : : numeric_limits < ui64 > : : max ( ) ;
2012-03-04 13:43:46 +03:00
try
2012-03-03 13:08:01 +03:00
{
2012-03-04 13:43:46 +03:00
switch ( configs . size ( ) )
{
case 4 :
try
{
for ( int i = 0 ; i < 4 ; + + i )
{
2013-11-07 15:48:41 +03:00
int bankVal = evaluateBankConfig ( VLC - > objh - > banksInfo [ ID ] [ i ] ) ;
2012-03-04 13:43:46 +03:00
bankDanger - > term ( " Bank " + boost : : lexical_cast < std : : string > ( i ) ) - > setMinimum ( bankVal * 0.5f ) ;
bankDanger - > term ( " Bank " + boost : : lexical_cast < std : : string > ( i ) ) - > setMaximum ( bankVal * 1.5f ) ;
}
//comparison purposes
//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
dynamic_cast < fl : : SingletonTerm * > ( bankInput - > term ( " SET " ) ) - > setValue ( 0.5 ) ;
bankInput - > setInput ( 0.5 ) ;
engine . process ( BANK_DANGER ) ;
val = bankDanger - > output ( ) . defuzzify ( ) ; //some expected value of this bank
}
2013-11-07 15:48:41 +03:00
catch ( fl : : FuzzyException & fe )
2012-03-03 13:08:01 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < fe . name ( ) < < " : " < < fe . message ( ) ;
2012-03-03 13:08:01 +03:00
}
2012-03-04 13:43:46 +03:00
break ;
case 1 : //rare case - Pyramid
val = evaluateBankConfig ( VLC - > objh - > banksInfo [ ID ] [ 0 ] ) ;
break ;
default :
2013-04-10 19:28:14 +03:00
logAi - > warnStream ( ) < < ( " Uhnandled bank config! " ) ;
2012-03-04 13:43:46 +03:00
}
}
2013-11-07 15:48:41 +03:00
catch ( fl : : FuzzyException & fe )
2012-03-04 13:43:46 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < " estimateBankDanger " < < fe . name ( ) < < " : " < < fe . message ( ) ;
2012-03-03 13:08:01 +03:00
}
return val ;
2012-03-04 13:43:46 +03:00
}
float FuzzyHelper : : getTacticalAdvantage ( const CArmedInstance * we , const CArmedInstance * enemy )
{
float output = 1 ;
try
{
armyStructure ourStructure = evaluateArmyStructure ( we ) ;
armyStructure enemyStructure = evaluateArmyStructure ( enemy ) ;
2013-12-20 12:43:12 +03:00
ta . ourWalkers - > setInput ( ourStructure . walkers ) ;
ta . ourShooters - > setInput ( ourStructure . shooters ) ;
ta . ourFlyers - > setInput ( ourStructure . flyers ) ;
ta . ourSpeed - > setInput ( ourStructure . maxSpeed ) ;
2012-03-04 13:43:46 +03:00
2013-12-20 12:43:12 +03:00
ta . enemyWalkers - > setInput ( enemyStructure . walkers ) ;
ta . enemyShooters - > setInput ( enemyStructure . shooters ) ;
ta . enemyFlyers - > setInput ( enemyStructure . flyers ) ;
ta . enemySpeed - > setInput ( enemyStructure . maxSpeed ) ;
2012-03-04 13:43:46 +03:00
bool bank = dynamic_cast < const CBank * > ( enemy ) ;
if ( bank )
2013-12-20 12:43:12 +03:00
ta . bankPresent - > setInput ( 1 ) ;
2012-03-04 13:43:46 +03:00
else
2013-12-20 12:43:12 +03:00
ta . bankPresent - > setInput ( 0 ) ;
2012-03-04 13:43:46 +03:00
const CGTownInstance * fort = dynamic_cast < const CGTownInstance * > ( enemy ) ;
if ( fort )
{
2013-12-20 12:43:12 +03:00
ta . castleWalls - > setInput ( fort - > fortLevel ( ) ) ;
2012-03-04 13:43:46 +03:00
}
else
2013-12-20 12:43:12 +03:00
ta . castleWalls - > setInput ( 0 ) ;
2012-03-04 13:43:46 +03:00
engine . process ( TACTICAL_ADVANTAGE ) ;
2013-12-20 12:43:12 +03:00
output = ta . threat - > output ( ) . defuzzify ( ) ;
2012-03-04 13:43:46 +03:00
}
2013-11-07 15:48:41 +03:00
catch ( fl : : FuzzyException & fe )
2012-03-04 13:43:46 +03:00
{
2013-04-10 19:28:14 +03:00
logAi - > errorStream ( ) < < " getTacticalAdvantage " < < fe . name ( ) < < " : " < < fe . message ( ) ;
2012-03-04 13:43:46 +03:00
}
return output ;
2012-03-05 16:31:59 +03:00
}
2013-11-24 11:21:51 +03:00
2013-12-20 12:43:12 +03:00
FuzzyHelper : : TacticalAdvantage : : ~ TacticalAdvantage ( )
{
//TODO: smart pointers?
delete ourWalkers ;
delete ourShooters ;
delete ourFlyers ;
delete enemyWalkers ;
delete enemyShooters ;
delete enemyFlyers ;
delete ourSpeed ;
delete enemySpeed ;
delete bankPresent ;
delete castleWalls ;
delete threat ;
}
2013-11-24 11:21:51 +03:00
//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec)
2013-12-20 16:07:58 +03:00
Goals : : TSubgoal FuzzyHelper : : chooseSolution ( Goals : : TGoalVec vec )
2013-11-25 14:55:48 +03:00
{
2013-12-20 12:43:12 +03:00
if ( vec . empty ( ) ) //no possibilities found
return sptr ( Goals : : Invalid ( ) ) ;
2013-11-25 14:55:48 +03:00
typedef std : : pair < Goals : : TSubgoal , float > goalValue ;
std : : vector < goalValue > values ;
for ( auto g : vec )
{
2013-12-19 23:21:21 +03:00
values . push_back ( std : : make_pair ( g , g - > accept ( this ) ) ) ;
2013-11-25 14:55:48 +03:00
}
auto compareGoals = [ & ] ( const goalValue & lhs , const goalValue & rhs ) - > bool
{
return lhs . second < rhs . second ;
} ;
boost : : sort ( values , compareGoals ) ;
2013-12-20 12:43:12 +03:00
return values . back ( ) . first ;
2013-12-19 23:21:21 +03:00
}
float FuzzyHelper : : evaluate ( Goals : : Explore & g )
{
2013-12-20 12:43:12 +03:00
return 1 ;
2013-12-19 23:21:21 +03:00
}
float FuzzyHelper : : evaluate ( Goals : : RecruitHero & g )
{
2013-12-20 12:43:12 +03:00
return 1 ; //just try to recruit hero as one of options
}
FuzzyHelper : : EvalVisitTile : : ~ EvalVisitTile ( )
{
delete strengthRatio ;
delete heroStrength ;
delete tileDistance ;
delete missionImportance ;
}
void FuzzyHelper : : initVisitTile ( )
{
std : : vector < fl : : InputLVar * > helper ;
vt . strengthRatio = new fl : : InputLVar ( " strengthRatio " ) ; //hero must be strong enough to defeat guards
vt . heroStrength = new fl : : InputLVar ( " heroStrength " ) ; //we want to use weakest possible hero
vt . tileDistance = new fl : : InputLVar ( " tileDistance " ) ; //we want to use hero who is near
vt . missionImportance = new fl : : InputLVar ( " lockedMissionImportance " ) ; //we may want to preempt hero with low-priority mission
vt . value = new fl : : OutputLVar ( " Value " ) ;
helper + = vt . strengthRatio , vt . heroStrength , vt . tileDistance , vt . missionImportance ;
vt . strengthRatio - > addTerm ( new fl : : ShoulderTerm ( " LOW " , 0.3 , SAFE_ATTACK_CONSTANT , true ) ) ;
vt . strengthRatio - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , SAFE_ATTACK_CONSTANT , SAFE_ATTACK_CONSTANT * 3 , false ) ) ;
vt . heroStrength - > addTerm ( new fl : : ShoulderTerm ( " LOW " , 1 , 2500 , true ) ) ; //assumed strength of new hero from tavern
vt . heroStrength - > addTerm ( new fl : : TriangularTerm ( " MEDIUM " , 2500 , 40000 ) ) ; //assumed strength of hero able to defeat bank
vt . heroStrength - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , 40000 , 1e5 , false ) ) ; //assumed strength of hero able to clear utopia
vt . tileDistance - > addTerm ( new fl : : ShoulderTerm ( " SMALL " , 0 , 3.5 , true ) ) ;
vt . tileDistance - > addTerm ( new fl : : TriangularTerm ( " MEDIUM " , 3 , 10.5 ) ) ;
vt . tileDistance - > addTerm ( new fl : : ShoulderTerm ( " LONG " , 10 , 50 , false ) ) ;
vt . missionImportance - > addTerm ( new fl : : ShoulderTerm ( " LOW " , 0 , 3.1 , true ) ) ;
vt . missionImportance - > addTerm ( new fl : : TriangularTerm ( " MEDIUM " , 2 , 9.5 ) ) ;
vt . missionImportance - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , 4.5 , 10 , false ) ) ;
vt . value - > addTerm ( new fl : : ShoulderTerm ( " LOW " , 0 , 1.1 , true ) ) ;
vt . value - > addTerm ( new fl : : ShoulderTerm ( " HIGH " , 1 , 5 , false ) ) ;
for ( auto val : helper )
{
engine . addInputLVar ( val ) ;
}
engine . addOutputLVar ( vt . value ) ;
//vt.rules.addRule (new fl::MamdaniRule("if OurShooters is MANY and EnemySpeed is LOW then Threat is very LOW", engine));
//use unarmed scouts if possible
vt . rules . addRule ( new fl : : MamdaniRule ( " if strengthRatio is HIGH and heroStrength is LOW then Value is very HIGH " , engine ) ) ;
//if medium heroes can't scratch enemy, don't try to arm them
vt . rules . addRule ( new fl : : MamdaniRule ( " if strengthRatio is LOW and heroStrength is MEDIUM then Value is LOW " , engine ) ) ;
//do not cancel important goals
vt . rules . addRule ( new fl : : MamdaniRule ( " if lockedMissionImportance is HIGH then Value is very LOW " , engine ) ) ;
//pick nearby objects if it's easy, avoid long walks
vt . rules . addRule ( new fl : : MamdaniRule ( " if tileDistance is SMALL then Value is HIGH " , engine ) ) ;
vt . rules . addRule ( new fl : : MamdaniRule ( " if tileDistance is LONG then Value is LOW " , engine ) ) ;
engine . addRuleBlock ( & vt . rules ) ;
2013-12-19 23:21:21 +03:00
}
float FuzzyHelper : : evaluate ( Goals : : VisitTile & g )
{
2013-12-20 16:01:44 +03:00
//we assume that hero is already set and we want to choose most suitable one for the mission
2013-12-20 12:43:12 +03:00
if ( ! g . hero )
return 0 ;
float output = 0 ;
cb - > setSelection ( g . hero . h ) ;
int distance = cb - > getDistance ( g . tile ) ; //at this point we already assume tile is reachable
float missionImportance = 0 ;
if ( vstd : : contains ( ai - > lockedHeroes , g . hero ) )
missionImportance = ai - > lockedHeroes [ g . hero ] - > importanceWhenLocked ( ) ;
float strengthRatio = 100 ; //we are much stronger than enemy
ui64 danger = evaluateDanger ( g . tile , g . hero . h ) ;
if ( danger )
strengthRatio = g . hero . h - > getTotalStrength ( ) / danger ;
try
{
vt . strengthRatio - > setInput ( strengthRatio ) ;
vt . heroStrength - > setInput ( g . hero - > getTotalStrength ( ) ) ;
vt . tileDistance - > setInput ( distance ) ;
vt . missionImportance - > setInput ( missionImportance ) ;
engine . process ( VISIT_TILE ) ;
output = vt . value - > output ( ) . defuzzify ( ) ;
}
catch ( fl : : FuzzyException & fe )
{
logAi - > errorStream ( ) < < " evaluate VisitTile " < < fe . name ( ) < < " : " < < fe . message ( ) ;
}
return output ;
2013-12-19 23:21:21 +03:00
}
float FuzzyHelper : : evaluate ( Goals : : VisitHero & g )
{
2013-12-20 16:01:44 +03:00
auto obj = cb - > getObj ( ObjectInstanceID ( g . objid ) ) ; //we assume for now that these goals are similiar
return Goals : : VisitTile ( obj - > pos ) . sethero ( g . hero ) . setisAbstract ( g . isAbstract ) . accept ( this ) ;
//TODO: consider direct copy (constructor?)
2013-12-19 23:21:21 +03:00
}
float FuzzyHelper : : evaluate ( Goals : : BuildThis & g )
{
return 0 ;
}
float FuzzyHelper : : evaluate ( Goals : : DigAtTile & g )
{
return 0 ;
}
float FuzzyHelper : : evaluate ( Goals : : CollectRes & g )
{
return 0 ;
}
float FuzzyHelper : : evaluate ( Goals : : Build & g )
{
return 0 ;
}
float FuzzyHelper : : evaluate ( Goals : : Invalid & g )
{
return - 1e10 ;
}
float FuzzyHelper : : evaluate ( Goals : : AbstractGoal & g )
{
logAi - > debugStream ( ) < < boost : : format ( " Cannot evaluate goal %s " ) % g . name ( ) ;
return - 1e10 ;
2013-12-20 16:07:58 +03:00
}