Explorar o código

ERM VR:M,VR:U

Andrii Danylchenko %!s(int64=4) %!d(string=hai) anos
pai
achega
061941b3ac

+ 5 - 5
AI/VCAI/FuzzyEngines.h

@@ -13,7 +13,7 @@
 
 class CArmedInstance;
 
-class engineBase //subclasses create fuzzylite variables with "new" that are not freed - this is desired as fl::Engine wants to destroy these...
+class DLL_EXPORT engineBase //subclasses create fuzzylite variables with "new" that are not freed - this is desired as fl::Engine wants to destroy these...
 {
 protected:
 	fl::Engine engine;
@@ -24,7 +24,7 @@ public:
 	engineBase();
 };
 
-class TacticalAdvantageEngine : public engineBase //TODO: rework this engine, it does not work well (example: AI hero with 140 beholders attacked 150 beholders - engine lowered danger 50000 -> 35000)
+class DLL_EXPORT TacticalAdvantageEngine : public engineBase //TODO: rework this engine, it does not work well (example: AI hero with 140 beholders attacked 150 beholders - engine lowered danger 50000 -> 35000)
 {
 public:
 	TacticalAdvantageEngine();
@@ -37,7 +37,7 @@ private:
 	fl::OutputVariable * threat;
 };
 
-class HeroMovementGoalEngineBase : public engineBase //in future - maybe derive from some (GoalEngineBase : public engineBase) class for handling non-movement goals with common utility for goal engines
+class DLL_EXPORT HeroMovementGoalEngineBase : public engineBase //in future - maybe derive from some (GoalEngineBase : public engineBase) class for handling non-movement goals with common utility for goal engines
 {
 public:
 	HeroMovementGoalEngineBase();
@@ -55,14 +55,14 @@ private:
 	float calculateTurnDistanceInputValue(const Goals::AbstractGoal & goal) const;
 };
 
-class VisitTileEngine : public HeroMovementGoalEngineBase
+class DLL_EXPORT VisitTileEngine : public HeroMovementGoalEngineBase
 {
 public:
 	VisitTileEngine();
 	float evaluate(Goals::VisitTile & goal);
 };
 
-class VisitObjEngine : public HeroMovementGoalEngineBase
+class DLL_EXPORT VisitObjEngine : public HeroMovementGoalEngineBase
 {
 public:
 	VisitObjEngine();

+ 48 - 12
scripting/erm/ERMInterpreter.cpp

@@ -774,10 +774,48 @@ namespace ERMConverter
 					putLine(fmt.str());
 				}
 				break;
+			case 'U':
+				{
+					if(!trig.params.is_initialized() || trig.params.get().size() != 1)
+						throw EScriptExecError("VR:H/U need 1 parameter!");
+
+					std::string opt = boost::apply_visitor(VR_S(), trig.params.get()[0]);
+					boost::format fmt("ERM.VR(%s):%c(%s)");
+					fmt % v.str() % (trig.optionCode) % opt;
+					putLine(fmt.str());
+				}
+				break;
 			case 'M': //string operations
 				{
-					//TODO
-					putLine("--VR:M not implemented");
+					if(!trig.params.is_initialized() || trig.params.get().size() < 2)
+						throw EScriptExecError("VR:M needs at least 2 parameters!");
+
+					std::string opt = boost::apply_visitor(VR_X(), trig.params.get()[0]);
+					int paramIndex = 1;
+
+					if(opt == "3")
+					{
+						boost::format fmt("%s = ERM.VR(%s):M3(");
+						fmt % v.str() % v.str();
+						put(fmt.str());
+					}
+					else
+					{
+						auto target = boost::apply_visitor(VR_X(), trig.params.get()[paramIndex++]);
+
+						boost::format fmt("%s = ERM.VR(%s):M%s(");
+						fmt % target % v.str() % opt;
+						put(fmt.str());
+					}
+					
+					for(int i = paramIndex; i < trig.params.get().size(); i++)
+					{
+						opt = boost::apply_visitor(VR_X(), trig.params.get()[i]);
+						if(i > paramIndex) put(",");
+						put(opt);
+					}
+					
+					putLine(")");
 				}
 				break;
 			case 'X': //bit xor
@@ -788,8 +826,7 @@ namespace ERMConverter
 					std::string opt = boost::apply_visitor(VR_X(), trig.params.get()[0]);
 
 					boost::format fmt("%s = bit.bxor(%s, %s)");
-					fmt % v.str() % v.str() % opt;
-					putLine(fmt.str());
+					fmt % v.str() % v.str() % opt;putLine(fmt.str());
 				}
 				break;
 			case 'R': //random variables
@@ -816,16 +853,15 @@ namespace ERMConverter
 					putLine("--VR:T not implemented");
 				}
 				break;
-			case 'U': //search for a substring
-				{
-					//TODO
-					putLine("--VR:U not implemented");
-				}
-				break;
 			case 'V': //convert string to value
 				{
-					//TODO
-					putLine("--VR:V not implemented");
+					if(!trig.params.is_initialized() || trig.params.get().size() != 1)
+						throw EScriptExecError("VR:V option takes exactly 1 parameter!");
+
+					std::string opt = boost::apply_visitor(VR_X(), trig.params.get()[0]);
+					boost::format fmt("%s = tostring(%s)");
+					fmt % v.str() % opt;
+					putLine(fmt.str());
 				}
 				break;
 			default:

+ 1 - 1
scripting/lua/StdInc.h

@@ -2,7 +2,7 @@
 
 #include "../../Global.h"
 
-#include <lua.hpp>
+#include <luajit/lua.hpp>
 
 // This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
 

+ 56 - 0
scripts/lib/erm/VR.lua

@@ -18,5 +18,61 @@ function VR:H(flagIndex)
 	self.ERM.F[flagIndex] = v ~= ''
 end
 
+function VR:U(subString)
+	self.ERM.F['1'] = string.find(self.v, subString) > 0
+end
+
+function VR:M1(startIndex, length)
+	return string.sub(self.v, startIndex - 1, startIndex - 1 + length)
+end
+
+function VR:M2(wordIndex)
+	local words = string.gmatch(self.v, "[^%s]+")
+	local i = 0
+
+	for w in words do
+		if i == wordIndex then
+			return w
+		end
+		i = i + 1
+	end
+end
+
+function VR:M3(val, radix)
+	radix = radix or 10
+	
+	if(type(val) ~= "number") then
+		error("The first parameter should be of numeric type")
+	end
+	
+	if(type(radix) ~= "number") then
+		error("The second parameter should be of numeric type. Default value is 10.")
+	end
+	
+	if radix == 10 then
+		return tostring(val)
+	elseif radix == 16 then
+		return string.format("%x", val)
+	else
+		error("The second parameter value is invalid. Only 10 and 16 radix are supported for now.")
+	end
+end
+
+function VR:M4()
+	return string.len(self.v)
+end
+
+function VR:M5()
+	local firstPos = string.find(str, "[^%s]+")
+	
+	return firstPos
+end
+
+function VR:M6()
+	local lastPos = 1 + string.len(self.v) - string.find(string.reverse(self.v), "[^%s]+")
+	
+	return lastPos
+end
+
 
 return VR

+ 19 - 0
test/CMakeLists.txt

@@ -153,11 +153,30 @@ set(mock_HEADERS
 		vcai/mock_VCAI_CGoal.h
 )
 
+if(NOT FORCE_BUNDLED_FL)
+	find_package(FuzzyLite)
+else()
+	set(FL_FOUND FALSE)
+endif()
+
+if(NOT FL_FOUND)
+    set(FL_BUILD_BINARY OFF CACHE BOOL "")
+    set(FL_BUILD_SHARED OFF CACHE BOOL "")
+	set(FL_BUILD_TESTS OFF CACHE BOOL "")
+	add_subdirectory(AI/FuzzyLite/fuzzylite EXCLUDE_FROM_ALL)
+endif()
+
 add_subdirectory_with_folder("3rdparty" googletest EXCLUDE_FROM_ALL)
 
 add_executable(vcmitest ${test_SRCS} ${test_HEADERS} ${mock_HEADERS})
 target_link_libraries(vcmitest PRIVATE gtest gmock vcmi ${SYSTEM_LIBS} VCAI)
 
+if(FL_FOUND)
+	target_link_libraries(vcmitest PRIVATE ${FL_LIBRARIES})
+else()
+	target_link_libraries(vcmitest PRIVATE fl-static)
+endif()
+
 target_include_directories(vcmitest
 		PUBLIC	${CMAKE_CURRENT_SOURCE_DIR}
 		PRIVATE	${GTestSrc}

+ 18 - 0
test/erm/ERM_VR.cpp

@@ -73,6 +73,24 @@ TEST_F(ERM_VR, H)
 	EXPECT_EQ(f["202"], JsonUtils::boolNode(false)) << actualState.toJson(true);
 }
 
+TEST_F(ERM_VR, U)
+{
+	std::stringstream source;
+	source << "VERM" << std::endl;
+	source << "!?PI;" << std::endl;
+	source << "!!VRz100:S^Test!^;" << std::endl;
+	source << "!!VRz101:S^est^;" << std::endl;
+	source << "!!VRz100:Uz101;" << std::endl;
+
+	JsonNode actualState = runScript(VLC->scriptHandler->erm, source.str());
+
+	SCOPED_TRACE("\n" + subject->code);
+
+	const JsonNode & f = actualState["ERM"]["F"];
+
+	EXPECT_EQ(f["1"], JsonUtils::boolNode(true)) << actualState.toJson(true);
+}
+
 }
 }
 

+ 20 - 12
test/erm/interpretter/ERM_VR.cpp

@@ -73,13 +73,21 @@ TEST(ERM_VR_H, CheckEmptyString_ShouldGenerateCheckAndSetStatement)
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
 	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "ERM.VR(z['101']):H('302')");
 }
+/* should it work?
+TEST(ERM_VR_H, CheckEmptyStringWithFlagIndexInVariable_ShouldGenerateCheckAndSetStatement)
+{
+	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:Hy1;"});
 
+	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "ERM.VR(z['101']):H(y['1'])");
+}
+*/
 TEST(ERM_VR_M1, AnyString_ShouldGenerateSubstringAndSetStatement)
 {
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M1/z102/2/5;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "z['102'] = ERM.VR(z['101']):M1(2,5)");
 }
 
 TEST(ERM_VR_M1, WithVariables_ShouldGenerateSubstringAndSetStatement)
@@ -87,7 +95,7 @@ TEST(ERM_VR_M1, WithVariables_ShouldGenerateSubstringAndSetStatement)
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M1/z102/y1/y2;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "z['102'] = ERM.VR(z['101']):M1(y['1'],y['2'])");
 }
 
 TEST(ERM_VR_M2, AnyString_ShouldGenerateWordSplitAndSetStatement)
@@ -95,7 +103,7 @@ TEST(ERM_VR_M2, AnyString_ShouldGenerateWordSplitAndSetStatement)
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M2/z102/2;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "z['102'] = ERM.VR(z['101']):M2(2)");
 }
 
 TEST(ERM_VR_M3, AnyInteger_ShouldGenerateIntToStringConversionAndSetStatement)
@@ -103,7 +111,7 @@ TEST(ERM_VR_M3, AnyInteger_ShouldGenerateIntToStringConversionAndSetStatement)
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M3/102/16;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "z['101'] = ERM.VR(z['101']):M3(102,16)");
 }
 //V
 TEST(ERM_VR_M3, IntegerVariable_ShouldGenerateIntToStringConversionAndSetStatement)
@@ -111,7 +119,7 @@ TEST(ERM_VR_M3, IntegerVariable_ShouldGenerateIntToStringConversionAndSetStateme
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M3/v1/10;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "z['101'] = ERM.VR(z['101']):M3(v['1'],10)");
 }
 
 TEST(ERM_VR_M4, AnyString_ShouldGenerateStringLengthAndSetStatement)
@@ -119,7 +127,7 @@ TEST(ERM_VR_M4, AnyString_ShouldGenerateStringLengthAndSetStatement)
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M4/v2;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "v['2'] = ERM.VR(z['101']):M4()");
 }
 
 TEST(ERM_VR_M5, AnyString_ShouldGenerateFindFirstNonSpaceCharPositionAndSetStatement)
@@ -127,7 +135,7 @@ TEST(ERM_VR_M5, AnyString_ShouldGenerateFindFirstNonSpaceCharPositionAndSetState
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M5/v2;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "v['2'] = ERM.VR(z['101']):M5()");
 }
 
 TEST(ERM_VR_M6, AnyString_ShouldGenerateFindLastNonSpaceCharPositionAndSetStatement)
@@ -135,7 +143,7 @@ TEST(ERM_VR_M6, AnyString_ShouldGenerateFindLastNonSpaceCharPositionAndSetStatem
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz101:M6/v2;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:M not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "v['2'] = ERM.VR(z['101']):M6()");
 }
 
 TEST(ERM_VR_R, AnyVariable_ShouldGenerateRngAndSetStatement)
@@ -174,8 +182,8 @@ TEST(ERM_VR_U, StringVariable_ShouldGenerateSubstringFindAndSetStatement)
 {
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz2:Uz3;"});
 
-	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:U not implemented");
+	ASSERT_EQ(lua.lines.size(), 9) << lua.lines[0];
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "ERM.VR(z['2']):U(z['3'])");
 }
 
 TEST(ERM_VR_U, StringConstant_ShouldGenerateSubstringFindAndSetStatement)
@@ -183,7 +191,7 @@ TEST(ERM_VR_U, StringConstant_ShouldGenerateSubstringFindAndSetStatement)
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRz2:U^teest^;"});
 
 	ASSERT_EQ(lua.lines.size(), 9) << lua.text;
-	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "--VR:U not implemented");
+	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "ERM.VR(z['2']):U([===[teest]===])");
 }
 
 TEST(ERM_VR_BIT, LogicalAndOperator_ShouldGenerateSetStatement)
@@ -234,7 +242,7 @@ TEST(ERM_VR_MINUS, MinusOperator_ShouldGenerateSetStatement)
 	EXPECT_EQ(lua.lines[ErmRunner::REGULAR_INSTRUCTION_FIRST_LINE], "v['1'] = v['1'] - v['2']");
 }
 
-TEST(ERM_VR_MULT, NultiplicationOperator_ShouldGenerateSetStatement)
+TEST(ERM_VR_MULT, MultiplicationOperator_ShouldGenerateSetStatement)
 {
 	LuaStrings lua = ErmRunner::convertErmToLua({"!#VRv1:*vy2;"});