1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-17 01:32:21 +02:00

Some work towards useful AI:

-It is possible to toggle adventure AI on / off typing "ai" in the console (default is true)
-General cleaning and formatting of code
-Some minor optimizations
-Teal console log for AI

AI tends to hang in the maze of mutexes and current player interface, further investigation is needed.

Fixed #580
minor tweaks
This commit is contained in:
DjWarmonger
2010-11-28 16:39:13 +00:00
parent 73a4c2e446
commit ea03273c8e
11 changed files with 555 additions and 493 deletions

View File

@ -100,11 +100,11 @@ void Priorities::fillFeatures(const CGeniusAI::HypotheticalGameState & hgs)
float Priorities::getCost(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay) float Priorities::getCost(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay)
{ {
if(resourceCosts.size()==0)return -1; if(!resourceCosts.size())return -1;
//TODO: replace with ann //TODO: replace with ann
float cost = resourceCosts[0]/4.0+resourceCosts[1]/2.0+resourceCosts[2]/4.0+resourceCosts[3]/2.0+resourceCosts[4]/2.0+resourceCosts[5]/2.0+resourceCosts[6]/3000.0; float cost = resourceCosts[0]/4.0+resourceCosts[1]/2.0+resourceCosts[2]/4.0+resourceCosts[3]/2.0+resourceCosts[4]/2.0+resourceCosts[5]/2.0+resourceCosts[6]/3000.0;
if(moved!=NULL) //TODO: multiply by importance of hero if(moved) //TODO: multiply by importance of hero
cost+=distOutOfTheWay/10000.0; cost+=distOutOfTheWay/10000.0;
return cost; return cost;
} }
@ -210,25 +210,24 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj)
//objectNetworks[53][hobj->object->subID].feedForward(stateFeatures); //objectNetworks[53][hobj->object->subID].feedForward(stateFeatures);
case 113://TODO: replace with value of skill for the hero case 113://TODO: replace with value of skill for the hero
return 0; return 0;
case 103:case 58://TODO: replace with value of seeing x number of new tiles case 103: case 58://TODO: replace with value of seeing x number of new tiles
return 0; return 0;
default: default:
if(objectNetworks[hobj->object->ID].size()!=0) if (objectNetworks[hobj->object->ID].size())
return objectNetworks[hobj->object->ID][0].feedForward(stateFeatures); return objectNetworks[hobj->object->ID][0].feedForward(stateFeatures);
cout << "don't know the value of "; tlog6 << "don't know the value of ";
switch(obj.type) switch(obj.type)
{ {
case CGeniusAI::AIObjective::visit: case CGeniusAI::AIObjective::visit:
cout << "visiting " << hobj->object->ID; tlog6 << "visiting " << hobj->object->ID;
break; break;
case CGeniusAI::AIObjective::attack: tlog6 << "attacking " << hobj->object->ID;
cout << "attacking " << hobj->object->ID;
break; break;
case CGeniusAI::AIObjective::finishTurn: case CGeniusAI::AIObjective::finishTurn:
obj.print(); obj.print();
break; break;
} }
cout << endl; tlog6 << endl;
} }
} }
else //town objective else //town objective
@ -240,9 +239,9 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj)
return buildingNetworks[tnObj->whichTown->t->subID][tnObj->which].feedForward(stateFeatures); return buildingNetworks[tnObj->whichTown->t->subID][tnObj->which].feedForward(stateFeatures);
else else
{ {
cout << "don't know the value of "; tlog6 << "don't know the value of ";
obj.print(); obj.print();
cout << endl; tlog6 << endl;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,11 +28,10 @@ class CGeniusAI : public CGlobalAI
{ {
private: private:
// TODO: cb... come back, croach busters!? // TODO: cb... come back, croach busters!?
ICallback* m_cb; ICallback* m_cb;
geniusai::BattleAI::CBattleLogic* m_battleLogic; geniusai::BattleAI::CBattleLogic* m_battleLogic;
geniusai::GeneralAI::CGeneralAI m_generalAI; geniusai::GeneralAI::CGeneralAI m_generalAI;
geniusai::Priorities* m_priorities; geniusai::Priorities* m_priorities;
CondSh<BattleState> m_state; //are we engaged into battle? CondSh<BattleState> m_state; //are we engaged into battle?
@ -71,7 +70,7 @@ private:
void update(CGeniusAI & ai); void update(CGeniusAI & ai);
CGeniusAI * AI; CGeniusAI * AI;
std::vector<const CGHeroInstance *> AvailableHeroesToBuy; std::vector<const CGHeroInstance *> AvailableHeroesToBuy;
std::vector<int> resourceAmounts; std::vector<ui32> resourceAmounts;
std::vector<HeroModel> heroModels; std::vector<HeroModel> heroModels;
std::vector<TownModel> townModels; std::vector<TownModel> townModels;
std::set< AIObjectContainer > knownVisitableObjects; std::set< AIObjectContainer > knownVisitableObjects;
@ -110,7 +109,7 @@ private:
public: public:
HypotheticalGameState hgs; HypotheticalGameState hgs;
int3 pos; int3 pos;
const CGObjectInstance * object; const CGObjectInstance * object; //interactive object
mutable std::vector<HypotheticalGameState::HeroModel*> whoCanAchieve; mutable std::vector<HypotheticalGameState::HeroModel*> whoCanAchieve;
//HeroObjective(){} //HeroObjective(){}

View File

@ -45,11 +45,7 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
++goalCounter; ++goalCounter;
} }
} }
matchedConditions = 0;
//modify set until something happens (hopefully!) //modify set until something happens (hopefully!)
for (iF = factsToErase.begin(); iF != factsToErase.end(); iF++)
factList.erase(knowledge.find(*iF));
factsToErase.clear(); //TODO: what if fact is remembered by rule, yet already erased?
for (iF = factsToAdd.begin(); iF != factsToAdd.end(); iF++) for (iF = factsToAdd.begin(); iF != factsToAdd.end(); iF++)
factList.insert(*iF); factList.insert(*iF);
if (factsToAdd.size()) if (factsToAdd.size())
@ -58,6 +54,9 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
factWasAdded = true; factWasAdded = true;
} }
} }
for (iF = factsToErase.begin(); iF != factsToErase.end(); iF++) //remove facts discarded in this run
factList.erase(knowledge.find(*iF));
factsToErase.clear(); //erase only after all rules had a chance to trigger
for (ir = rulesToErase.begin(); ir != rulesToErase.end(); ir++) for (ir = rulesToErase.begin(); ir != rulesToErase.end(); ir++)
knowledge.erase(knowledge.find(*ir)); knowledge.erase(knowledge.find(*ir));
rulesToErase.clear(); rulesToErase.clear();
@ -89,13 +88,13 @@ void BonusRule::fireRule()
case BonusCondition::duration: case BonusCondition::duration:
if (!it->first.functor(it->second->object->duration, it->first.value)) return; if (!it->first.functor(it->second->object->duration, it->first.value)) return;
break; break;
case BonusCondition::source: case BonusCondition::source: //likely to handle by selector
if (!it->first.functor(it->second->object->source, it->first.value)) return; if (!it->first.functor(it->second->object->source, it->first.value)) return;
break; break;
case BonusCondition::id: case BonusCondition::id:
if (!it->first.functor(it->second->object->id, it->first.value)) return; if (!it->first.functor(it->second->object->id, it->first.value)) return;
break; break;
case BonusCondition::valType: case BonusCondition::valType: //ever needed?
if (!it->first.functor(it->second->object->valType, it->first.value)) return; if (!it->first.functor(it->second->object->valType, it->first.value)) return;
break; break;
case BonusCondition::additionalInfo: case BonusCondition::additionalInfo:
@ -110,12 +109,18 @@ void BonusRule::fireRule()
} }
//TODO: add new fact or modify existing one //TODO: add new fact or modify existing one
} }
//TODO: find out why it does not compile
//template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::set<conType> &conditionSet) //template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::set<conType> &conditionSet)
//{ //{
// cons.clear(); // cons.clear();
// for (std::set<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++) // for (std::set<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
// cons.insert(std::make_pair<conType,input*>(*it, NULL)); //pointer to condition and null fact // cons.insert(std::make_pair<conType,input*>(*it, NULL)); //pointer to condition and null fact
//} //}
//template <typename input, typename conType> void Rule<input, conType>::refreshRule()
//{
// for (std::set<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
// *it->second = NULL;
//}
bool BonusCondition::matchesFact(Bonus &fact) bool BonusCondition::matchesFact(Bonus &fact)
{ {
if (object(fact)) //Bonus(fact) matches local Selector(object) if (object(fact)) //Bonus(fact) matches local Selector(object)

View File

@ -53,7 +53,7 @@ public:
}; };
template <typename input> class condition template <typename input> class condition
{//determines selected object parameter with value using functor {//compares selected object parameter with value using functor. universal logic handler
public: public:
input object; //what the fact is, or what it's like (CSelector) input object; //what the fact is, or what it's like (CSelector)
si32 value; si32 value;
@ -74,9 +74,13 @@ public:
protected: protected:
std::set<std::pair<conType, input*>> cons; //conditions and matching facts std::set<std::pair<conType, input*>> cons; //conditions and matching facts
input decision; input decision;
virtual void canBeFired(); //if this data makes any sense for rule virtual void canBeFired(); //if this data makes any sense for rule - type check
virtual void fireRule(std::set<input*> &feed); virtual bool checkCondition(); //if condition is true or false
virtual bool checkCondition(std::set<input*> &feed);
virtual void fireRule(); //use paired conditions and facts by default virtual void fireRule(); //use paired conditions and facts by default
virtual void fireRule(ExpertSystemShell<input, conType> &system);
virtual void fireRule(std::set<input*> &feed);
virtual void refreshRule();
virtual void refreshRule(std::set<conType> &conditionSet); //in case conditions were erased virtual void refreshRule(std::set<conType> &conditionSet); //in case conditions were erased
public: public:
Rule(){fired = false; conditionCounter = 0; decision = NULL;}; Rule(){fired = false; conditionCounter = 0; decision = NULL;};
@ -124,21 +128,56 @@ public:
}; };
bool matchesFact(Bonus &fact); bool matchesFact(Bonus &fact);
}; };
class BonusHolder : public AIholder<Bonus> class BonusHolder : public AIholder<Bonus>
{ {
public: public:
BonusHolder(Bonus &bonus){object = &bonus; aiValue = bonus.val;} BonusHolder(Bonus &bonus){object = &bonus; aiValue = bonus.val;}
BonusHolder(Bonus &bonus, si32 val){object = &bonus; aiValue = val;} BonusHolder(Bonus &bonus, si32 val){object = &bonus; aiValue = val;}
}; };
class BonusRule : public Rule <BonusHolder, BonusCondition> class BonusRule : public Rule <BonusHolder, BonusCondition>
{ {
protected: protected:
void fireRule(); void fireRule();
}; };
bool greaterThan (int prop, si32 val) inline bool greaterThan (int prop, si32 val)
{ {
if ((si32)prop > val) if ((si32)prop > val)
return true; return true;
return false; return false;
} }
inline bool lessThan (int prop, si32 val)
{
if ((si32)prop < val)
return true;
return false;
}
inline bool eqal (int prop, si32 val)
{
if ((si32)prop == val)
return true;
return false;
}
inline bool unequal (int prop, si32 val)
{
if ((si32)prop != val)
return true;
return false;
}
inline bool present (int prop, si32 val=0)
//inline bool present (int prop) //TODO: can we use function with less arguments?
{
return(prop); //unfixable warning :(
}
class KnowledgeHandler///I'd opt for one omniscent knowledge manager, so no templates here
{
public:
std::list<BonusRule> knowledge; //permanent storage of rules
void parseKnowledge(std::string &filename){};
void addKnowledge(ExpertSystemShell<BRule,Bonus> &expert);
void addFacts(ExpertSystemShell<BRule,Bonus> &expert);
};

View File

@ -42,6 +42,7 @@
#define CONSOLE_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY #define CONSOLE_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY #define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE #define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#endif #endif
TColor defColor; TColor defColor;
@ -168,6 +169,9 @@ void CConsoleHandler::setColor(int level)
case 5: case 5:
color = CONSOLE_GRAY; color = CONSOLE_GRAY;
break; break;
case -2:
color = CONSOLE_TEAL;
break;
default: default:
color = defColor; color = defColor;
break; break;

View File

@ -75,7 +75,6 @@ Point screenLT = Point(0, 0); //position of top left corner of the screen
Point screenLTmax = Point(0, 0); //,maximal values for screenLT coordinates Point screenLTmax = Point(0, 0); //,maximal values for screenLT coordinates
static boost::thread *mainGUIThread; static boost::thread *mainGUIThread;
SystemOptions GDefaultOptions; SystemOptions GDefaultOptions;
VCMIDirs GVCMIDirs; VCMIDirs GVCMIDirs;
std::queue<SDL_Event*> events; std::queue<SDL_Event*> events;
@ -428,6 +427,11 @@ void processCommand(const std::string &message)
{ {
gOnlyAI = true; gOnlyAI = true;
} }
else if (cn == "ai")
{
VLC->IS_AI_ENABLED = !VLC->IS_AI_ENABLED;
tlog4 << "Current AI status: " << (VLC->IS_AI_ENABLED ? "enabled" : "disabled") << std::endl;
}
else if(cn == "mp" && adventureInt) else if(cn == "mp" && adventureInt)
{ {
if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection)) if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))

View File

@ -1676,7 +1676,7 @@ void CRecruitmentWindow::Buy()
int crid = creatures[which].ID, int crid = creatures[which].ID,
dstslot = dst-> getSlotFor(crid); dstslot = dst-> getSlotFor(crid);
if(dstslot < 0) //no available slot if(dstslot < 0 && !vstd::contains(CGI->arth->bigArtifacts,CGI->arth->convertMachineID(crid, true))) //no available slot
{ {
std::string txt; std::string txt;
if(dst->ID == HEROI_TYPE) if(dst->ID == HEROI_TYPE)

View File

@ -358,6 +358,7 @@ extern DLL_EXPORT CLogger tlog2; //magenta - major warnings
extern DLL_EXPORT CLogger tlog3; //yellow - minor warnings extern DLL_EXPORT CLogger tlog3; //yellow - minor warnings
extern DLL_EXPORT CLogger tlog4; //white - detailed log info extern DLL_EXPORT CLogger tlog4; //white - detailed log info
extern DLL_EXPORT CLogger tlog5; //gray - minor log info extern DLL_EXPORT CLogger tlog5; //gray - minor log info
extern DLL_EXPORT CLogger tlog6; //teal - AI info
//XXX pls dont - 'debug macros' are usually more trouble than it's worth //XXX pls dont - 'debug macros' are usually more trouble than it's worth
#define HANDLE_EXCEPTION \ #define HANDLE_EXCEPTION \

View File

@ -34,6 +34,7 @@ DLL_EXPORT CLogger tlog2(2);
DLL_EXPORT CLogger tlog3(3); DLL_EXPORT CLogger tlog3(3);
DLL_EXPORT CLogger tlog4(4); DLL_EXPORT CLogger tlog4(4);
DLL_EXPORT CLogger tlog5(5); DLL_EXPORT CLogger tlog5(5);
DLL_EXPORT CLogger tlog6(-2);
DLL_EXPORT CConsoleHandler *console = NULL; DLL_EXPORT CConsoleHandler *console = NULL;
DLL_EXPORT std::ostream *logfile = NULL DLL_EXPORT std::ostream *logfile = NULL
@ -205,6 +206,8 @@ void LibClasses::init()
spellh = new CSpellHandler; spellh = new CSpellHandler;
spellh->loadSpells(); spellh->loadSpells();
tlog0<<"\tSpell handler: "<<pomtime.getDif()<<std::endl; tlog0<<"\tSpell handler: "<<pomtime.getDif()<<std::endl;
IS_AI_ENABLED = true;
} }
void LibClasses::clear() void LibClasses::clear()

View File

@ -26,6 +26,7 @@ class CGeneralTextHandler;
class DLL_EXPORT LibClasses class DLL_EXPORT LibClasses
{ {
public: public:
bool IS_AI_ENABLED; //VLC is teh only object visible from both CMT and GeniusAI
CArtHandler * arth; CArtHandler * arth;
CHeroHandler * heroh; CHeroHandler * heroh;
CCreatureHandler * creh; CCreatureHandler * creh;
@ -45,7 +46,7 @@ public:
void callWhenDeserializing(); //should be called only by serialize !!! void callWhenDeserializing(); //should be called only by serialize !!!
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh; h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh & IS_AI_ENABLED;;
if(!h.saving) if(!h.saving)
{ {
callWhenDeserializing(); callWhenDeserializing();