From 67baa3d8e4feba1bcf1cda47002155847480ad69 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Sat, 13 Nov 2010 19:25:21 +0000 Subject: [PATCH] I hope that's final shape of universal Expert System, now it's time to add some functionality. --- AI/GeniusAI/ExpertSystem.cpp | 106 +++++++++++++++++++++++++++++++++-- AI/GeniusAI/ExpertSystem.h | 95 ++++++++++++++++++++++++------- 2 files changed, 178 insertions(+), 23 deletions(-) diff --git a/AI/GeniusAI/ExpertSystem.cpp b/AI/GeniusAI/ExpertSystem.cpp index 23d6420c1..446fc2bfd 100644 --- a/AI/GeniusAI/ExpertSystem.cpp +++ b/AI/GeniusAI/ExpertSystem.cpp @@ -12,15 +12,113 @@ * */ -template void ExpertSystemShell::DataDrivenReasoning(runType type) +template template void ExpertSystemShell::DataDrivenReasoning(runType type) { + std::set::iterator ir; + std::list::iterator iF; + std::set>::iterator ic; + bool factWasAdded = false; //carry it over inner loop switch (type) { case ANY_GOAL: //first produced decision ends reasoning { - for (std::list::iterator it = factList.begin(); it != factList.end(); it++) - {}; + int goalCounter = 0; + while(!goalCounter) //we reach goal or can't modify knowledge anymore + { + for (ir = knowledge.begin(); ir != knowledge.end(); ir++) + { + for (iF = factList.begin(); iF != factList.end(); iF++) + { + for (ic = ir->conditions.begin(); ic != ir->conditions.end(), ic++) + { + if (ic->first.object.matchesFact(iF->object)) //condition matches held object + { + (ic->second = *iF); + ++(ir->conditionCounter); + } + } + if (ir->conditions.size() >= ir->conditionCounter()); + { + ir->fireRule(); //all conditions matched + ir->conditionCounter = 0; //do it here or in rule itself? + if (dynamic_cast<&Goal>(*ir)) + ++goalCounter; + } + } + matchedConditions = 0; + //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++) + factList.insert(*iF); + if (factsToAdd.size()) + { + factsToAdd.clear(); + factWasAdded = true; + } + } + for (ir = rulesToErase.begin(); ir != rulesToErase.end(); ir++) + knowledge.erase(knowledge.find(*ir)); + rulesToErase.clear(); + for (ir = rulesToAdd.begin(); ir != rulesToAdd.end(); ir++) + knowledge.insert(*ir); + if (!(factWasAdded || rulesToAdd.size())) //we can't do anything more + break; + rulesToAdd.clear(); + }; } break; } -} \ No newline at end of file +} +void BonusRule::fireRule() +{ + for (std::set>::iterator it = cons.begin(); it != cons.end(); it++) + { + switch (it->first.parameter) + { //compare fact with condition + case BonusCondition::type: + if (!it->first.functor(it->second->object->type, it->first.value)) return; + break; + case BonusCondition::subtype: //probably suprfluous, Selector already handles that + if (!it->first.functor(it->second->object->subtype, it->first.value)) return; + break; + case BonusCondition::val: + if (!it->first.functor(it->second->object->val, it->first.value)) return; + break; + case BonusCondition::duration: + if (!it->first.functor(it->second->object->duration, it->first.value)) return; + break; + case BonusCondition::source: + if (!it->first.functor(it->second->object->source, it->first.value)) return; + break; + case BonusCondition::id: + if (!it->first.functor(it->second->object->id, it->first.value)) return; + break; + case BonusCondition::valType: + if (!it->first.functor(it->second->object->valType, it->first.value)) return; + break; + case BonusCondition::additionalInfo: + if (!it->first.functor(it->second->object->additionalInfo, it->first.value)) return; + break; + case BonusCondition::effectRange: + if (!it->first.functor(it->second->object->effectRange, it->first.value)) return; + break; + default: //ignore or accept? + break; + }; + } + //TODO: add new fact or modify existing one +} +//template void Rule::refreshRule(std::set &conditionSet) +//{ +// cons.clear(); +// for (std::set::iterator it = conditionSet.begin(); it != conditionSet.end(); it++) +// cons.insert(std::make_pair(*it, NULL)); //pointer to condition and null fact +//} +bool BonusCondition::matchesFact(Bonus &fact) +{ + if (object(fact)) //Bonus(fact) matches local Selector(object) + return true; + return false; +} diff --git a/AI/GeniusAI/ExpertSystem.h b/AI/GeniusAI/ExpertSystem.h index a4207123d..996212c69 100644 --- a/AI/GeniusAI/ExpertSystem.h +++ b/AI/GeniusAI/ExpertSystem.h @@ -14,54 +14,72 @@ * */ struct Bonus; +template class AIholder; template class Rule; typedef Rule BRule; +bool greaterThan (int prop, si32 val); -template class ExpertSystemShell +enum conditionType {LESS_THAN, EQUAL, GREATER_THAN, UNEQUAL, PRESENT}; + +template class ExpertSystemShell { enum runType {ANY_GOAL, TRESHOLD, FULL}; private: ICallback* m_cb; protected: std::set knowledge; + std::set rulesToErase; + std::set rulesToAdd; + std::set factsToErase; + std::set factsToAdd; ui16 goalCounter; //count / evaluate achieved goals for runType public: ExpertSystemShell(){goalCounter = 0;}; - std::list factList; + std::list facts; //facts are AIholders with actual game objects, for eg. "my bonus is worthless" template void getKnowledge(const t1 &a1){}; - template void getNextRule(){}; + void getNextRule(){}; + void addRule(ruleType &rule){rulesToAdd.insert(rule);}; + void removeRule(ruleType &rule){rulesToErase.insert(rule);}; template void returnGoals(const t2 &a2){}; - virtual void DataDrivenReasoning(runType type); + template void DataDrivenReasoning(runType type); }; -template class Blackboard : public ExpertSystemShell +template class Blackboard : public ExpertSystemShell //handle Bonus info coming from different sections of the game { public: - Blackboard(){this->goalCounter = 0;}; + Blackboard(){this->goalCounter = 0;}; //template magic, do not touch! std::vector experts; //modules responsible for different tasks }; template class condition -{ - enum conditionType {LESS_THAN, EQUAL, GREATER_THAN, UNEQUAL, PRESENT}; +{//determines selected object parameter with value using functor public: - input object; - ui16 value; - conditionType conType; + input object; //what the fact is, or what it's like (CSelector) + si32 value; + ui8 parameter; + boost::function functor; //value of selected parameter, condition value + + condition(){object = NULL; value = 0; parameter = 0; functor = greaterThan;}; + + bool matchesFact(input &fact){return false;}; }; -template class Rule +template class Rule { -friend class ExpertSystemShell ; +friend class ExpertSystemShell ; public: bool fired; //if conditions of rule were met and it produces some output + ui8 conditionCounter; protected: - std::set conditions; - output decision; + std::set> cons; //conditions and matching facts + input decision; virtual void canBeFired(); //if this data makes any sense for rule - virtual void fireRule(); + virtual void fireRule(std::set &feed); + virtual void fireRule(); //use paired conditions and facts by default + virtual void refreshRule(std::set &conditionSet); //in case conditions were erased public: + Rule(){fired = false; conditionCounter = 0; decision = NULL;}; template bool matchesInput() //if condition and data match type {return dynamic_cast(&givenInput);}; }; @@ -77,11 +95,50 @@ public: template class Weight : public Rule { public: - float value; //multiply input by value and return to output + float multiplier; //multiply input by value and return to output void fireTule(){}; }; +template class AIholder +{ //stores certain condition and its temporal value +public: + si32 aiValue; + input *object; + + AIholder(){object = NULL; aiValue = 0;} + AIholder(input &o){object = o; aiValue = 0;} + AIholder(input &o, si32 val){object = 0; aiValue = val;} +}; + class BonusSystemExpert : public ExpertSystemShell { //TODO: less templates? - enum effectType {POSITIVE=1, NEGATIVE=2, EXCLUDING=4, ENEMY=8, ALLY=16}; //what is the influencce of bonus and for who -}; \ No newline at end of file + enum effectType {POSITIVE=1, NEGATIVE=2, EXCLUDING=4, ENEMY=8, ALLY=16}; //what is the influence of bonus and for who +}; + +class BonusCondition : public condition //used to test rule +{ +public: + enum Parameter + { + type, subtype, val, duration, source, id, valType, additionalInfo, effectRange, limiter //? + }; + bool matchesFact(Bonus &fact); +}; +class BonusHolder : public AIholder +{ +public: + BonusHolder(Bonus &bonus){object = &bonus; aiValue = bonus.val;} + BonusHolder(Bonus &bonus, si32 val){object = &bonus; aiValue = val;} +}; +class BonusRule : public Rule +{ +protected: + void fireRule(); +}; + +bool greaterThan (int prop, si32 val) +{ + if ((si32)prop > val) + return true; + return false; +} \ No newline at end of file