mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			623 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			623 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * LogicalExpression.h, 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
 | |
|  *
 | |
|  */
 | |
| #pragma once
 | |
| 
 | |
| #include "json/JsonNode.h"
 | |
| 
 | |
| VCMI_LIB_NAMESPACE_BEGIN
 | |
| 
 | |
| namespace LogicalExpressionDetail
 | |
| {
 | |
| 	/// class that defines required types for logical expressions
 | |
| 	template<typename ContainedClass>
 | |
| 	class ExpressionBase
 | |
| 	{
 | |
| 	public:
 | |
| 		/// Possible logical operations, mostly needed to create different types for std::variant
 | |
| 		enum EOperations
 | |
| 		{
 | |
| 			ANY_OF,
 | |
| 			ALL_OF,
 | |
| 			NONE_OF
 | |
| 		};
 | |
| 		template<EOperations tag> class Element;
 | |
| 
 | |
| 		using OperatorAny = Element<ANY_OF>;
 | |
| 		using OperatorAll = Element<ALL_OF>;
 | |
| 		using OperatorNone = Element<NONE_OF>;
 | |
| 
 | |
| 		using Value = ContainedClass;
 | |
| 
 | |
| 		/// Variant that contains all possible elements from logical expression
 | |
| 		using Variant = std::variant<OperatorAll, OperatorAny, OperatorNone, Value>;
 | |
| 
 | |
| 		/// Variant element, contains list of expressions to which operation "tag" should be applied
 | |
| 		template<EOperations tag>
 | |
| 		class Element
 | |
| 		{
 | |
| 		public:
 | |
| 			Element() {}
 | |
| 			Element(std::vector<Variant> expressions):
 | |
| 				expressions(expressions)
 | |
| 			{}
 | |
| 
 | |
| 			std::vector<Variant> expressions;
 | |
| 
 | |
| 			bool operator == (const Element & other) const
 | |
| 			{
 | |
| 				return expressions == other.expressions;
 | |
| 			}
 | |
| 
 | |
| 			template <typename Handler>
 | |
| 			void serialize(Handler & h)
 | |
| 			{
 | |
| 				h & expressions;
 | |
| 			}
 | |
| 		};
 | |
| 	};
 | |
| 
 | |
| 	/// Visitor to test result (true/false) of the expression
 | |
| 	template<typename ContainedClass>
 | |
| 	class TestVisitor
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 		std::function<bool(const typename Base::Value &)> classTest;
 | |
| 
 | |
| 		size_t countPassed(const std::vector<typename Base::Variant> & element) const
 | |
| 		{
 | |
| 			return boost::range::count_if(element, [&](const typename Base::Variant & expr)
 | |
| 			{
 | |
| 				return std::visit(*this, expr);
 | |
| 			});
 | |
| 		}
 | |
| 	public:
 | |
| 		TestVisitor(std::function<bool (const typename Base::Value &)> classTest):
 | |
| 			classTest(classTest)
 | |
| 		{}
 | |
| 
 | |
| 		bool operator()(const typename Base::OperatorAny & element) const
 | |
| 		{
 | |
| 			return countPassed(element.expressions) != 0;
 | |
| 		}
 | |
| 
 | |
| 		bool operator()(const typename Base::OperatorAll & element) const
 | |
| 		{
 | |
| 			return countPassed(element.expressions) == element.expressions.size();
 | |
| 		}
 | |
| 
 | |
| 		bool operator()(const typename Base::OperatorNone & element) const
 | |
| 		{
 | |
| 			return countPassed(element.expressions) == 0;
 | |
| 		}
 | |
| 
 | |
| 		bool operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			return classTest(element);
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	template <typename ContainedClass>
 | |
| 	class SatisfiabilityVisitor;
 | |
| 
 | |
| 	template <typename ContainedClass>
 | |
| 	class FalsifiabilityVisitor;
 | |
| 
 | |
| 	template<typename ContainedClass>
 | |
| 	class PossibilityVisitor
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 	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 std::visit(*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 std::visit(*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>
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 	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>
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 	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>
 | |
| 	class CandidatesVisitor
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 		using TValueList = std::vector<typename Base::Value>;
 | |
| 
 | |
| 		TestVisitor<ContainedClass> classTest;
 | |
| 
 | |
| 	public:
 | |
| 		CandidatesVisitor(std::function<bool(const typename Base::Value &)> classTest):
 | |
| 			classTest(classTest)
 | |
| 		{}
 | |
| 
 | |
| 		TValueList operator()(const typename Base::OperatorAny & element) const
 | |
| 		{
 | |
| 			TValueList ret;
 | |
| 			if (!classTest(element))
 | |
| 			{
 | |
| 				for (auto & elem : element.expressions)
 | |
| 					boost::range::copy(std::visit(*this, elem), std::back_inserter(ret));
 | |
| 			}
 | |
| 			return ret;
 | |
| 		}
 | |
| 
 | |
| 		TValueList operator()(const typename Base::OperatorAll & element) const
 | |
| 		{
 | |
| 			TValueList ret;
 | |
| 			if (!classTest(element))
 | |
| 			{
 | |
| 				for (auto & elem : element.expressions)
 | |
| 					boost::range::copy(std::visit(*this, elem), std::back_inserter(ret));
 | |
| 			}
 | |
| 			return ret;
 | |
| 		}
 | |
| 
 | |
| 		TValueList operator()(const typename Base::OperatorNone & element) const
 | |
| 		{
 | |
| 			return TValueList(); //TODO. Implementing this one is not straightforward, if ever possible
 | |
| 		}
 | |
| 
 | |
| 		TValueList operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			if (classTest(element))
 | |
| 				return TValueList();
 | |
| 			else
 | |
| 				return TValueList(1, element);
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	/// Simple foreach visitor
 | |
| 	template<typename ContainedClass>
 | |
| 	class ForEachVisitor
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 		std::function<typename Base::Variant(const typename Base::Value &)> visitor;
 | |
| 
 | |
| 	public:
 | |
| 		ForEachVisitor(std::function<typename Base::Variant(const typename Base::Value &)> visitor):
 | |
| 			visitor(visitor)
 | |
| 		{}
 | |
| 
 | |
| 		typename Base::Variant operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			return visitor(element);
 | |
| 		}
 | |
| 
 | |
| 		template <typename Type>
 | |
| 		typename Base::Variant operator()(Type element) const
 | |
| 		{
 | |
| 			for (auto & entry : element.expressions)
 | |
| 				entry = std::visit(*this, entry);
 | |
| 			return element;
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	/// Minimizing visitor that removes all redundant elements from variant (e.g. AllOf inside another AllOf can be merged safely)
 | |
| 	template<typename ContainedClass>
 | |
| 	class MinimizingVisitor
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 	public:
 | |
| 		typename Base::Variant operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			return element;
 | |
| 		}
 | |
| 
 | |
| 		template <typename Type>
 | |
| 		typename Base::Variant operator()(const Type & element) const
 | |
| 		{
 | |
| 			Type ret;
 | |
| 
 | |
| 			for (auto & entryRO : element.expressions)
 | |
| 			{
 | |
| 				auto entry = std::visit(*this, entryRO);
 | |
| 
 | |
| 				try
 | |
| 				{
 | |
| 					// copy entries from child of this type
 | |
| 					auto sublist = std::get<Type>(entry).expressions;
 | |
| 					std::move(sublist.begin(), sublist.end(), std::back_inserter(ret.expressions));
 | |
| 				}
 | |
| 				catch (std::bad_variant_access &)
 | |
| 				{
 | |
| 					// different type (e.g. allOf vs oneOf) just copy
 | |
| 					ret.expressions.push_back(entry);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			for ( auto it = ret.expressions.begin(); it != ret.expressions.end();)
 | |
| 			{
 | |
| 				if (std::find(ret.expressions.begin(), it, *it) != it)
 | |
| 					it = ret.expressions.erase(it); // erase duplicate
 | |
| 				else
 | |
| 					it++; // goto next
 | |
| 			}
 | |
| 			return ret;
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	/// Json parser for expressions
 | |
| 	template <typename ContainedClass>
 | |
| 	class Reader
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 		std::function<typename Base::Value(const JsonNode &)> classParser;
 | |
| 
 | |
| 		typename Base::Variant readExpression(const JsonNode & node)
 | |
| 		{
 | |
| 			assert(!node.Vector().empty());
 | |
| 
 | |
| 			std::string type = node.Vector()[0].String();
 | |
| 			if (type == "anyOf")
 | |
| 				return typename Base::OperatorAny(readVector(node));
 | |
| 			if (type == "allOf")
 | |
| 				return typename Base::OperatorAll(readVector(node));
 | |
| 			if (type == "noneOf")
 | |
| 				return typename Base::OperatorNone(readVector(node));
 | |
| 			return classParser(node);
 | |
| 		}
 | |
| 
 | |
| 		std::vector<typename Base::Variant> readVector(const JsonNode & node)
 | |
| 		{
 | |
| 			std::vector<typename Base::Variant> ret;
 | |
| 			ret.reserve(node.Vector().size()-1);
 | |
| 			for (size_t i=1; i < node.Vector().size(); i++)
 | |
| 				ret.push_back(readExpression(node.Vector()[i]));
 | |
| 			return ret;
 | |
| 		}
 | |
| 	public:
 | |
| 		Reader(std::function<typename Base::Value(const JsonNode &)> classParser):
 | |
| 			classParser(classParser)
 | |
| 		{}
 | |
| 		typename Base::Variant operator ()(const JsonNode & node)
 | |
| 		{
 | |
| 			return readExpression(node);
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	/// Serializes expression in JSON format. Part of map format.
 | |
| 	template<typename ContainedClass>
 | |
| 	class Writer
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 		std::function<JsonNode(const typename Base::Value &)> classPrinter;
 | |
| 
 | |
| 		JsonNode printExpressionList(std::string name, const std::vector<typename Base::Variant> & element) const
 | |
| 		{
 | |
| 			JsonNode ret;
 | |
| 			ret.Vector().resize(1);
 | |
| 			ret.Vector().back().String() = name;
 | |
| 			for (auto & expr : element)
 | |
| 				ret.Vector().push_back(std::visit(*this, expr));
 | |
| 			return ret;
 | |
| 		}
 | |
| 	public:
 | |
| 		Writer(std::function<JsonNode(const typename Base::Value &)> classPrinter):
 | |
| 			classPrinter(classPrinter)
 | |
| 		{}
 | |
| 
 | |
| 		JsonNode operator()(const typename Base::OperatorAny & element) const
 | |
| 		{
 | |
| 			return printExpressionList("anyOf", element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		JsonNode operator()(const typename Base::OperatorAll & element) const
 | |
| 		{
 | |
| 			return printExpressionList("allOf", element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		JsonNode operator()(const typename Base::OperatorNone & element) const
 | |
| 		{
 | |
| 			return printExpressionList("noneOf", element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		JsonNode operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			return classPrinter(element);
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	std::string DLL_LINKAGE getTextForOperator(const std::string & operation);
 | |
| 
 | |
| 	/// Prints expression in human-readable format
 | |
| 	template<typename ContainedClass>
 | |
| 	class Printer
 | |
| 	{
 | |
| 		using Base = ExpressionBase<ContainedClass>;
 | |
| 
 | |
| 		std::function<std::string(const typename Base::Value &)> classPrinter;
 | |
| 		std::unique_ptr<TestVisitor<ContainedClass>> statusTest;
 | |
| 		mutable std::string prefix;
 | |
| 
 | |
| 		template<typename Operator>
 | |
| 		std::string formatString(std::string toFormat, const Operator & expr) const
 | |
| 		{
 | |
| 			// highlight not fulfilled expressions, if pretty formatting is on
 | |
| 			if (statusTest && !(*statusTest)(expr))
 | |
| 				return "{" + toFormat + "}";
 | |
| 			return toFormat;
 | |
| 		}
 | |
| 
 | |
| 		std::string printExpressionList(const std::vector<typename Base::Variant> & element) const
 | |
| 		{
 | |
| 			std::string ret;
 | |
| 			prefix.push_back('\t');
 | |
| 			for (auto & expr : element)
 | |
| 				ret += prefix + std::visit(*this, expr) + "\n";
 | |
| 			prefix.pop_back();
 | |
| 			return ret;
 | |
| 		}
 | |
| 	public:
 | |
| 		Printer(std::function<std::string(const typename Base::Value &)> classPrinter):
 | |
| 			classPrinter(classPrinter)
 | |
| 		{}
 | |
| 
 | |
| 		Printer(std::function<std::string(const typename Base::Value &)> classPrinter, std::function<bool(const typename Base::Value &)> toBool):
 | |
| 			classPrinter(classPrinter),
 | |
| 			statusTest(new TestVisitor<ContainedClass>(toBool))
 | |
| 		{}
 | |
| 
 | |
| 		std::string operator()(const typename Base::OperatorAny & element) const
 | |
| 		{
 | |
| 			return formatString(getTextForOperator("anyOf"), element) + "\n"
 | |
| 					+ printExpressionList(element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		std::string operator()(const typename Base::OperatorAll & element) const
 | |
| 		{
 | |
| 			return formatString(getTextForOperator("allOf"), element) + "\n"
 | |
| 					+ printExpressionList(element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		std::string operator()(const typename Base::OperatorNone & element) const
 | |
| 		{
 | |
| 			return formatString(getTextForOperator("noneOf"), element) + "\n"
 | |
| 					+ printExpressionList(element.expressions);
 | |
| 		}
 | |
| 
 | |
| 		std::string operator()(const typename Base::Value & element) const
 | |
| 		{
 | |
| 			return formatString(classPrinter(element), element);
 | |
| 		}
 | |
| 	};
 | |
| }
 | |
| 
 | |
| ///
 | |
| /// Class for evaluation of logical expressions generated in runtime
 | |
| ///
 | |
| template<typename ContainedClass>
 | |
| class LogicalExpression
 | |
| {
 | |
| 	using Base = LogicalExpressionDetail::ExpressionBase<ContainedClass>;
 | |
| 
 | |
| public:
 | |
| 	/// Type of values used in expressions, same as ContainedClass
 | |
| 	using Value = typename Base::Value;
 | |
| 	/// Operators for use in expressions, all include vectors with operands
 | |
| 	using OperatorAny = typename Base::OperatorAny;
 | |
| 	using OperatorAll = typename Base::OperatorAll;
 | |
| 	using OperatorNone = typename Base::OperatorNone;
 | |
| 	/// one expression entry
 | |
| 	using Variant = typename Base::Variant;
 | |
| 
 | |
| private:
 | |
| 	Variant data;
 | |
| 
 | |
| public:
 | |
| 	/// Base constructor
 | |
| 	LogicalExpression() = default;
 | |
| 
 | |
| 	/// Constructor from variant or (implicitly) from Operator* types
 | |
| 	LogicalExpression(const Variant & data): data(data) {}
 | |
| 
 | |
| 	/// Constructor that receives JsonNode as input and function that can parse Value instances
 | |
| 	LogicalExpression(const JsonNode & input, std::function<Value(const JsonNode &)> parser)
 | |
| 	{
 | |
| 		LogicalExpressionDetail::Reader<Value> reader(parser);
 | |
| 		LogicalExpression expr(reader(input));
 | |
| 		std::swap(data, expr.data);
 | |
| 	}
 | |
| 
 | |
| 	Variant get() const
 | |
| 	{
 | |
| 		return data;
 | |
| 	}
 | |
| 
 | |
| 	/// Simple visitor that visits all entries in expression
 | |
| 	Variant morph(std::function<Variant(const Value &)> morpher) const
 | |
| 	{
 | |
| 		LogicalExpressionDetail::ForEachVisitor<Value> visitor(morpher);
 | |
| 		return std::visit(visitor, data);
 | |
| 	}
 | |
| 
 | |
| 	/// Minimizes expression, removing any redundant elements
 | |
| 	void minimize()
 | |
| 	{
 | |
| 		LogicalExpressionDetail::MinimizingVisitor<Value> visitor;
 | |
| 		data = std::visit(visitor, data);
 | |
| 	}
 | |
| 
 | |
| 	/// calculates if expression evaluates to "true".
 | |
| 	/// Note: empty expressions always return true
 | |
| 	bool test(std::function<bool(const Value &)> toBool) const
 | |
| 	{
 | |
| 		LogicalExpressionDetail::TestVisitor<Value> testVisitor(toBool);
 | |
| 		return std::visit(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 std::visit(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 std::visit(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
 | |
| 	{
 | |
| 		LogicalExpressionDetail::CandidatesVisitor<Value> candidateVisitor(toBool);
 | |
| 		return std::visit(candidateVisitor, data);
 | |
| 	}
 | |
| 
 | |
| 	/// Converts expression in human-readable form
 | |
| 	/// Second version will try to do some pretty printing using H3 text formatting "{}"
 | |
| 	/// to indicate fulfilled components of an expression
 | |
| 	std::string toString(std::function<std::string(const Value &)> toStr) const
 | |
| 	{
 | |
| 		LogicalExpressionDetail::Printer<Value> printVisitor(toStr);
 | |
| 		return std::visit(printVisitor, data);
 | |
| 	}
 | |
| 	std::string toString(std::function<std::string(const Value &)> toStr, std::function<bool(const Value &)> toBool) const
 | |
| 	{
 | |
| 		LogicalExpressionDetail::Printer<Value> printVisitor(toStr, toBool);
 | |
| 		return std::visit(printVisitor, data);
 | |
| 	}
 | |
| 
 | |
| 	JsonNode toJson(std::function<JsonNode(const Value &)> toJson) const
 | |
| 	{
 | |
| 		LogicalExpressionDetail::Writer<Value> writeVisitor(toJson);
 | |
| 		return std::visit(writeVisitor, data);
 | |
| 	}
 | |
| 
 | |
| 	template <typename Handler>
 | |
| 	void serialize(Handler & h)
 | |
| 	{
 | |
| 		h & data;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| VCMI_LIB_NAMESPACE_END
 |