mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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:
		| @@ -100,11 +100,11 @@ void Priorities::fillFeatures(const CGeniusAI::HypotheticalGameState & hgs) | ||||
|  | ||||
| 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 | ||||
| 	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; | ||||
| 	return cost; | ||||
| } | ||||
| @@ -210,25 +210,24 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj) | ||||
| 			//objectNetworks[53][hobj->object->subID].feedForward(stateFeatures); | ||||
| 		case 113://TODO: replace with value of skill for the hero | ||||
| 			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; | ||||
| 		default: | ||||
| 			if(objectNetworks[hobj->object->ID].size()!=0) | ||||
| 			if (objectNetworks[hobj->object->ID].size()) | ||||
| 				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) | ||||
| 			{ | ||||
| 			case CGeniusAI::AIObjective::visit: | ||||
| 				cout << "visiting " << hobj->object->ID; | ||||
| 				tlog6 << "visiting " << hobj->object->ID; | ||||
| 				break; | ||||
| 			case CGeniusAI::AIObjective::attack: | ||||
| 				cout << "attacking " << hobj->object->ID; | ||||
| 				tlog6 << "attacking " << hobj->object->ID; | ||||
| 				break; | ||||
| 			case CGeniusAI::AIObjective::finishTurn: | ||||
| 				obj.print(); | ||||
| 				break; | ||||
| 			} | ||||
| 			cout << endl; | ||||
| 			tlog6 << endl; | ||||
| 		} | ||||
| 	} | ||||
| 	else	//town objective | ||||
| @@ -240,9 +239,9 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj) | ||||
| 				return buildingNetworks[tnObj->whichTown->t->subID][tnObj->which].feedForward(stateFeatures); | ||||
| 			else | ||||
| 			{ | ||||
| 				cout << "don't know the value of "; | ||||
| 				tlog6 << "don't know the value of "; | ||||
| 				obj.print(); | ||||
| 				cout << endl; | ||||
| 				tlog6 << endl; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -28,11 +28,10 @@ class CGeniusAI : public CGlobalAI | ||||
| { | ||||
| private: | ||||
|   // TODO: cb... come back, croach busters!? | ||||
| 	ICallback*							          m_cb; | ||||
| 	ICallback*							m_cb; | ||||
| 	geniusai::BattleAI::CBattleLogic*	m_battleLogic; | ||||
| 	geniusai::GeneralAI::CGeneralAI		m_generalAI; | ||||
| 	geniusai::Priorities*				      m_priorities; | ||||
|  | ||||
| 	geniusai::Priorities*				m_priorities; | ||||
| 	 | ||||
| 	CondSh<BattleState> m_state; //are we engaged into battle? | ||||
|  | ||||
| @@ -71,7 +70,7 @@ private: | ||||
| 		void update(CGeniusAI & ai); | ||||
| 		CGeniusAI * AI; | ||||
| 		std::vector<const CGHeroInstance *> AvailableHeroesToBuy; | ||||
| 		std::vector<int> resourceAmounts; | ||||
| 		std::vector<ui32> resourceAmounts; | ||||
| 		std::vector<HeroModel> heroModels; | ||||
| 		std::vector<TownModel> townModels; | ||||
| 		std::set< AIObjectContainer > knownVisitableObjects; | ||||
| @@ -110,7 +109,7 @@ private: | ||||
| 	public: | ||||
| 		HypotheticalGameState hgs; | ||||
| 		int3 pos; | ||||
| 		const CGObjectInstance * object; | ||||
| 		const CGObjectInstance * object; //interactive object | ||||
| 		mutable std::vector<HypotheticalGameState::HeroModel*> whoCanAchieve; | ||||
| 		 | ||||
| 		//HeroObjective(){} | ||||
|   | ||||
| @@ -45,11 +45,7 @@ template <typename ruleType, typename facts> template <typename cond> void Exper | ||||
| 								++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()) | ||||
| @@ -58,6 +54,9 @@ template <typename ruleType, typename facts> template <typename cond> void Exper | ||||
| 						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++) | ||||
| 					knowledge.erase(knowledge.find(*ir)); | ||||
| 				rulesToErase.clear(); | ||||
| @@ -89,13 +88,13 @@ void BonusRule::fireRule() | ||||
| 			case BonusCondition::duration: | ||||
| 				if (!it->first.functor(it->second->object->duration, it->first.value)) return; | ||||
| 			break; | ||||
| 			case BonusCondition::source: | ||||
| 			case BonusCondition::source: //likely to handle by selector | ||||
| 				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: | ||||
| 			case BonusCondition::valType: //ever needed? | ||||
| 				if (!it->first.functor(it->second->object->valType, it->first.value)) return; | ||||
| 			break; | ||||
| 			case BonusCondition::additionalInfo: | ||||
| @@ -110,12 +109,18 @@ void BonusRule::fireRule() | ||||
| 	} | ||||
| 	//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) | ||||
| //{ | ||||
| //	cons.clear(); | ||||
| //	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 | ||||
| //} | ||||
| //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) | ||||
| { | ||||
| 	if (object(fact)) //Bonus(fact) matches local Selector(object) | ||||
|   | ||||
| @@ -53,7 +53,7 @@ public: | ||||
| }; | ||||
|  | ||||
| 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: | ||||
| 	input object; //what the fact is, or what it's like (CSelector) | ||||
| 	si32 value; | ||||
| @@ -74,9 +74,13 @@ public: | ||||
| protected: | ||||
| 	std::set<std::pair<conType, input*>> cons; //conditions and matching facts | ||||
| 	input decision; | ||||
| 	virtual void canBeFired(); //if this data makes any sense for rule | ||||
| 	virtual void fireRule(std::set<input*> &feed); | ||||
| 	virtual void canBeFired(); //if this data makes any sense for rule - type check | ||||
| 	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(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 | ||||
| public: | ||||
| 	Rule(){fired = false; conditionCounter = 0; decision = NULL;}; | ||||
| @@ -124,21 +128,56 @@ public: | ||||
| 	}; | ||||
| 	bool matchesFact(Bonus &fact); | ||||
| }; | ||||
|  | ||||
| class BonusHolder : public AIholder<Bonus> | ||||
| { | ||||
| public: | ||||
| 	BonusHolder(Bonus &bonus){object = &bonus; aiValue = bonus.val;} | ||||
| 	BonusHolder(Bonus &bonus, si32 val){object = &bonus; aiValue = val;} | ||||
| }; | ||||
|  | ||||
| class BonusRule : public Rule <BonusHolder, BonusCondition> | ||||
| { | ||||
| protected: | ||||
| 	void fireRule(); | ||||
| }; | ||||
|  | ||||
| bool greaterThan (int prop, si32 val) | ||||
| inline bool greaterThan (int prop, si32 val) | ||||
| { | ||||
| 	if ((si32)prop > val) | ||||
| 		return true; | ||||
| 	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); | ||||
| }; | ||||
| @@ -42,6 +42,7 @@ | ||||
| 	#define CONSOLE_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY | ||||
| 	#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | ||||
| 	#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | ||||
| 	#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | ||||
| #endif | ||||
|  | ||||
| TColor defColor; | ||||
| @@ -168,6 +169,9 @@ void CConsoleHandler::setColor(int level) | ||||
| 	case 5: | ||||
| 		color = CONSOLE_GRAY; | ||||
| 		break; | ||||
| 	case -2: | ||||
| 		color = CONSOLE_TEAL; | ||||
| 		break; | ||||
| 	default: | ||||
| 		color = defColor; | ||||
| 		break; | ||||
|   | ||||
| @@ -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 | ||||
| static boost::thread *mainGUIThread; | ||||
|  | ||||
|  | ||||
| SystemOptions GDefaultOptions;  | ||||
| VCMIDirs GVCMIDirs; | ||||
| std::queue<SDL_Event*> events; | ||||
| @@ -428,6 +427,11 @@ void processCommand(const std::string &message) | ||||
| 	{ | ||||
| 		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) | ||||
| 	{ | ||||
| 		if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection)) | ||||
|   | ||||
| @@ -1676,7 +1676,7 @@ void CRecruitmentWindow::Buy() | ||||
| 	int crid = creatures[which].ID, | ||||
| 		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; | ||||
| 		if(dst->ID == HEROI_TYPE) | ||||
|   | ||||
							
								
								
									
										1
									
								
								global.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								global.h
									
									
									
									
									
								
							| @@ -358,6 +358,7 @@ extern DLL_EXPORT CLogger tlog2; //magenta - major warnings | ||||
| extern DLL_EXPORT CLogger tlog3; //yellow - minor warnings | ||||
| extern DLL_EXPORT CLogger tlog4; //white - detailed 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 | ||||
| #define HANDLE_EXCEPTION  \ | ||||
|   | ||||
| @@ -34,6 +34,7 @@ DLL_EXPORT CLogger tlog2(2); | ||||
| DLL_EXPORT CLogger tlog3(3); | ||||
| DLL_EXPORT CLogger tlog4(4); | ||||
| DLL_EXPORT CLogger tlog5(5); | ||||
| DLL_EXPORT CLogger tlog6(-2); | ||||
|  | ||||
| DLL_EXPORT CConsoleHandler *console = NULL; | ||||
| DLL_EXPORT std::ostream *logfile = NULL | ||||
| @@ -205,6 +206,8 @@ void LibClasses::init() | ||||
| 	spellh = new CSpellHandler; | ||||
| 	spellh->loadSpells(); | ||||
| 	tlog0<<"\tSpell handler: "<<pomtime.getDif()<<std::endl; | ||||
|  | ||||
| 	IS_AI_ENABLED = true; | ||||
| } | ||||
|  | ||||
| void LibClasses::clear() | ||||
|   | ||||
| @@ -26,6 +26,7 @@ class CGeneralTextHandler; | ||||
| class DLL_EXPORT LibClasses | ||||
| { | ||||
| public: | ||||
| 	bool IS_AI_ENABLED; //VLC is teh only object visible from both CMT and GeniusAI | ||||
| 	CArtHandler * arth; | ||||
| 	CHeroHandler * heroh; | ||||
| 	CCreatureHandler * creh; | ||||
| @@ -45,7 +46,7 @@ public: | ||||
| 	void callWhenDeserializing(); //should be called only by serialize !!! | ||||
| 	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) | ||||
| 		{ | ||||
| 			callWhenDeserializing(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user