mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Merge pull request #211 from Chocimier/iss2321
Tested. Everthing looks fine so merging.
This commit is contained in:
		| @@ -520,6 +520,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow | ||||
| 	if(vstd::contains(t->forbiddenBuildings, ID)) | ||||
| 		return EBuildingState::FORBIDDEN; //forbidden | ||||
|  | ||||
| 	auto possiblyNotBuiltTest = [&](BuildingID id) -> bool | ||||
| 	{ | ||||
| 		return ((id == BuildingID::CAPITOL) ? true : !t->hasBuilt(id)); | ||||
| 	}; | ||||
|  | ||||
| 	std::function<bool(BuildingID id)> allowedTest = [&](BuildingID id) -> bool | ||||
| 	{ | ||||
| 		if (vstd::contains(t->forbiddenBuildings, id)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		return t->genBuildingRequirements(id, true).satisfiable(allowedTest, possiblyNotBuiltTest); | ||||
| 	}; | ||||
|  | ||||
| 	if (!t->genBuildingRequirements(ID, true).satisfiable(allowedTest, possiblyNotBuiltTest)) | ||||
| 		return EBuildingState::FORBIDDEN; | ||||
|  | ||||
| 	if(ID == BuildingID::CAPITOL) | ||||
| 	{ | ||||
| 		const PlayerState *ps = getPlayer(t->tempOwner, false); | ||||
|   | ||||
| @@ -99,6 +99,129 @@ namespace LogicalExpressionDetail | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	template <typename ContainedClass> | ||||
| 	class SatisfiabilityVisitor; | ||||
|  | ||||
| 	template <typename ContainedClass> | ||||
| 	class FalsifiabilityVisitor; | ||||
|  | ||||
| 	template <typename ContainedClass> | ||||
| 	class PossibilityVisitor : public boost::static_visitor<bool> | ||||
| 	{ | ||||
| 		typedef ExpressionBase<ContainedClass> Base; | ||||
|  | ||||
| 	protected: | ||||
| 		std::function<bool(const typename Base::Value &)> satisfiabilityTest; | ||||
| 		std::function<bool(const typename Base::Value &)> falsifiabilityTest; | ||||
| 		SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor; | ||||
| 		FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor; | ||||
|  | ||||
| 		size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const | ||||
| 		{ | ||||
| 			return boost::range::count_if(element, [&](const typename Base::Variant & expr) | ||||
| 			{ | ||||
| 				return boost::apply_visitor(*satisfiabilityVisitor, expr); | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const | ||||
| 		{ | ||||
| 			return boost::range::count_if(element, [&](const typename Base::Variant & expr) | ||||
| 			{ | ||||
| 				return boost::apply_visitor(*falsifiabilityVisitor, expr); | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 	public: | ||||
| 		PossibilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest, | ||||
| 		                   std::function<bool (const typename Base::Value &)> falsifiabilityTest): | ||||
| 			satisfiabilityTest(satisfiabilityTest), | ||||
| 			falsifiabilityTest(falsifiabilityTest), | ||||
| 			satisfiabilityVisitor(nullptr), | ||||
| 			falsifiabilityVisitor(nullptr) | ||||
| 		{} | ||||
|  | ||||
| 		void setSatisfiabilityVisitor(SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor) | ||||
| 		{ | ||||
| 			this->satisfiabilityVisitor = satisfiabilityVisitor; | ||||
| 		} | ||||
|  | ||||
| 		void setFalsifiabilityVisitor(FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor) | ||||
| 		{ | ||||
| 			this->falsifiabilityVisitor = falsifiabilityVisitor; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// Visitor to test whether expression's value can be true | ||||
| 	template <typename ContainedClass> | ||||
| 	class SatisfiabilityVisitor : public PossibilityVisitor<ContainedClass> | ||||
| 	{ | ||||
| 		typedef ExpressionBase<ContainedClass> Base; | ||||
|  | ||||
| 	public: | ||||
| 		SatisfiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest, | ||||
| 		                      std::function<bool (const typename Base::Value &)> falsifiabilityTest): | ||||
| 			PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest) | ||||
| 		{ | ||||
| 			this->setSatisfiabilityVisitor(this); | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorAny & element) const | ||||
| 		{ | ||||
| 			return this->countSatisfiable(element.expressions) != 0; | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorAll & element) const | ||||
| 		{ | ||||
| 			return this->countSatisfiable(element.expressions) == element.expressions.size(); | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorNone & element) const | ||||
| 		{ | ||||
| 			return this->countFalsifiable(element.expressions) == element.expressions.size(); | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::Value & element) const | ||||
| 		{ | ||||
| 			return this->satisfiabilityTest(element); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// Visitor to test whether expression's value can be false | ||||
| 	template <typename ContainedClass> | ||||
| 	class FalsifiabilityVisitor : public PossibilityVisitor<ContainedClass> | ||||
| 	{ | ||||
| 		typedef ExpressionBase<ContainedClass> Base; | ||||
|  | ||||
| 	public: | ||||
| 		FalsifiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest, | ||||
| 		                      std::function<bool (const typename Base::Value &)> falsifiabilityTest): | ||||
| 			PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest) | ||||
| 		{ | ||||
| 			this->setFalsifiabilityVisitor(this); | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorAny & element) const | ||||
| 		{ | ||||
| 			return this->countFalsifiable(element.expressions) == element.expressions.size(); | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorAll & element) const | ||||
| 		{ | ||||
| 			return this->countFalsifiable(element.expressions) != 0; | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::OperatorNone & element) const | ||||
| 		{ | ||||
| 			return this->countSatisfiable(element.expressions) != 0; | ||||
| 		} | ||||
|  | ||||
| 		bool operator()(const typename Base::Value & element) const | ||||
| 		{ | ||||
| 			return this->falsifiabilityTest(element); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// visitor that is trying to generates candidates that must be fulfilled | ||||
| 	/// to complete this expression | ||||
| 	template <typename ContainedClass> | ||||
| @@ -436,6 +559,30 @@ public: | ||||
| 		return boost::apply_visitor(testVisitor, data); | ||||
| 	} | ||||
|  | ||||
| 	/// calculates if expression can evaluate to "true". | ||||
| 	bool satisfiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const | ||||
| 	{ | ||||
| 		LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest, falsifiabilityTest); | ||||
| 		LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(satisfiabilityTest, falsifiabilityTest); | ||||
|  | ||||
| 		satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor); | ||||
| 		falsifiabilityVisitor.setSatisfiabilityVisitor(&satisfiabilityVisitor); | ||||
|  | ||||
| 		return boost::apply_visitor(satisfiabilityVisitor, data); | ||||
| 	} | ||||
|  | ||||
| 	/// calculates if expression can evaluate to "false". | ||||
| 	bool falsifiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const | ||||
| 	{ | ||||
| 		LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest); | ||||
| 		LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest); | ||||
|  | ||||
| 		satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor); | ||||
| 		falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor); | ||||
|  | ||||
| 		return boost::apply_visitor(falsifiabilityVisitor, data); | ||||
| 	} | ||||
|  | ||||
| 	/// generates list of candidates that can be fulfilled by caller (like AI) | ||||
| 	std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const | ||||
| 	{ | ||||
|   | ||||
| @@ -1124,7 +1124,7 @@ bool CGTownInstance::hasBuilt(BuildingID buildingID) const | ||||
| 	return vstd::contains(builtBuildings, buildingID); | ||||
| } | ||||
|  | ||||
| CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID) const | ||||
| CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID, bool deep) const | ||||
| { | ||||
| 	const CBuilding * building = town->buildings.at(buildID); | ||||
|  | ||||
| @@ -1132,17 +1132,22 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID) | ||||
| 	[&](const BuildingID & id) -> CBuilding::TRequired::Variant | ||||
| 	{ | ||||
| 		const CBuilding * build = town->buildings.at(id); | ||||
| 		CBuilding::TRequired::OperatorAll requirements; | ||||
|  | ||||
| 		if (!hasBuilt(id)) | ||||
| 			return id; | ||||
| 		{ | ||||
| 			requirements.expressions.push_back(id); | ||||
|  | ||||
| 		CBuilding::TRequired::OperatorAll requirements; | ||||
| 			if (!deep) | ||||
| 			{ | ||||
| 				return requirements; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (build->upgrade != BuildingID::NONE) | ||||
| 			requirements.expressions.push_back(dependTest(build->upgrade)); | ||||
|  | ||||
| 		requirements.expressions.push_back(build->requirements.morph(dependTest)); | ||||
|  | ||||
| 		return requirements; | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -238,7 +238,7 @@ public: | ||||
| 	bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero | ||||
| 	int getTownLevel() const; | ||||
|  | ||||
| 	CBuilding::TRequired genBuildingRequirements(BuildingID build) const; | ||||
| 	CBuilding::TRequired genBuildingRequirements(BuildingID build, bool deep = false) const; | ||||
|  | ||||
| 	void mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero | ||||
| 	void removeCapitols (PlayerColor owner) const; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user