From 6e54324d4fa47df3ae02bafd1462926b5ed38dff Mon Sep 17 00:00:00 2001 From: Epagris Date: Tue, 14 Oct 2025 11:25:01 +0200 Subject: [PATCH] - ... --- class/LogicFunction.php | 63 ++++++++++++++++--------------- class/LuaUtils.php | 29 +++++++++++--- class/Task.php | 83 +++++++++++++++++++++++++++++------------ 3 files changed, 115 insertions(+), 60 deletions(-) diff --git a/class/LogicFunction.php b/class/LogicFunction.php index 417734a..b24c674 100644 --- a/class/LogicFunction.php +++ b/class/LogicFunction.php @@ -59,38 +59,38 @@ class LogicFunction implements JsonSerializable return join("", $tt); } + public static function genTerm(array $vars, int $ftn, int $tn, int $mind, int $maxd, bool $top = true, int $opindex = 1): string + { + $term = ""; + $m = max($ftn, random_int(1, $tn)); + if ((($maxd === 0) || ($m === 1)) && ($ftn === 0)) { + $neg = random_int(0, 1) === 1; + $var = $vars[array_rand($vars, 1)]; + $term = ($neg ? "~" : "") . $var; + } else { + $depth = random_int(0, max(0, $maxd - 1)); + + $verilog_ops = [" & ", " | "]; + $verilog_op = $verilog_ops[$opindex]; + $term = !$top ? "(" : ""; + + $nextopindex = ($opindex === 0) ? 1 : 0; + + for ($i = 0; $i < $m; $i++) { + $subterm = self::genTerm($vars, (($mind - 1) > 0) ? $ftn : 0, $tn, $mind - 1, $depth, false, $nextopindex); + $term .= $subterm; + if ($i < $m - 1) { + $term .= $verilog_op; + } + } + $term .= !$top ? ")" : ""; + } + return $term; + } + public static function genRandom(array $input_vars, int $min_depth = 2, int $max_depth = 3): LogicFunction { - function genTerm(array $vars, int $ftn, int $tn, int $mind, int $maxd, bool $top = true, int $opindex = 1): string - { - $term = ""; - $m = max($ftn, random_int(1, $tn)); - if ((($maxd === 0) || ($m === 1)) && ($ftn === 0)) { - $neg = random_int(0, 1) === 1; - $var = $vars[array_rand($vars, 1)]; - $term = ($neg ? "~" : "") . $var; - } else { - $depth = random_int(0, max(0, $maxd - 1)); - - $verilog_ops = [" & ", " | "]; - $verilog_op = $verilog_ops[$opindex]; - $term = !$top ? "(" : ""; - - $nextopindex = ($opindex === 0) ? 1 : 0; - - for ($i = 0; $i < $m; $i++) { - $subterm = genTerm($vars, (($mind - 1) > 0) ? $ftn : 0, $tn, $mind - 1, $depth, false, $nextopindex); - $term .= $subterm; - if ($i < $m - 1) { - $term .= $verilog_op; - } - } - $term .= !$top ? ")" : ""; - } - return $term; - } - - $term = genTerm($input_vars, count($input_vars), count($input_vars), $min_depth, $max_depth); + $term = self::genTerm($input_vars, count($input_vars), count($input_vars), $min_depth, $max_depth); return new LogicFunction($term, $input_vars); } @@ -249,7 +249,8 @@ class LogicFunction implements JsonSerializable } public function drawNetwork(string $outvar = "f"): string { - return PythonUtils::execPy("draw_logic_network.py", [ $this->getExpression(), $outvar ]); + $expr = str_replace(["^"], ["xor"], $this->getExpression()); + return PythonUtils::execPy("draw_logic_network.py", [ $expr, $outvar ]); } } diff --git a/class/LuaUtils.php b/class/LuaUtils.php index 3854111..93a0f72 100644 --- a/class/LuaUtils.php +++ b/class/LuaUtils.php @@ -4,7 +4,11 @@ require_once "LogicFunction.php"; class LuaUtils { - public static function l2pA(array $la): array { + public static function l2pA(array|null $la): array { + if ($la === null) { + return []; + } + $r = []; $i = 0; foreach ($la as $v) { @@ -13,6 +17,19 @@ class LuaUtils return $r; } + public static function p2lA(array|null $pa): array { + if ($pa === null) { + return []; + } + + $r = []; + $i = 1; + foreach ($pa as $v) { + $r[$i++] = $v; + } + return $r; + } + public static function registerLuaLibs(LuaSandbox &$sandbox): void { self::registerLogicUtils($sandbox); } @@ -24,11 +41,11 @@ class LuaUtils "changeRepresentation" => fn() => [ call_user_func(array(LogicUtils::class, "changeRepresentation"), ...func_get_args()) ], "genRandomLogicFunction" => fn($iv, $mind, $maxd) => [ call_user_func(array(LogicFunction::class, "genRandom"), self::l2pA($iv), $mind, $maxd)->getExpression() ], "genRandomLogicFunctionDNF" => fn($iv) => [ call_user_func(array(LogicFunction::class, "genRandomDNF"), self::l2pA($iv))->getExpression() ], - "isLogicFunctionValid" => fn($expr) => [ (new LogicFunction($expr))->isValid() ], - "isLogicFunctionADNF" => fn($iv, $expr) => [ call_user_func(array(LogicFunction::class, "isCorrectDNF"), self::l2pA($iv), $expr) ], - "collectVariablesFromLogicFunction" => fn($expr) => call_user_func(array(LogicFunction::class, "collectVariables"), $expr), - "convertLogicFunctionToTruthTable" => fn($expr, $iv) => [ (new LogicFunction($expr, self::l2pA($iv)))->getTruthTable() ], - "drawLogicFunction" => fn($expr, $iv, $ov) => [ (new LogicFunction($expr, self::l2pA($iv)))->drawNetwork($ov) ], + "isLogicFunctionValid" => fn($expr) => [ (new LogicFunction($expr ?? "0"))->isValid() ], + "isLogicFunctionADNF" => fn($iv, $expr) => [ call_user_func(array(LogicFunction::class, "isCorrectDNF"), self::l2pA($iv), $expr ?? "0") ], + "collectVariablesFromLogicFunction" => fn($expr) => call_user_func(array(LogicFunction::class, "collectVariables"), $expr ?? ""), + "convertLogicFunctionToTruthTable" => fn($expr, $iv) => [ (new LogicFunction($expr ?? "0", self::l2pA($iv)))->getTruthTable() ], + "drawLogicFunction" => fn($expr, $iv, $ov) => [ (new LogicFunction($expr ?? "0", self::l2pA($iv)))->drawNetwork($ov) ], ]); } } \ No newline at end of file diff --git a/class/Task.php b/class/Task.php index 7da929b..0bd1f25 100644 --- a/class/Task.php +++ b/class/Task.php @@ -18,35 +18,54 @@ class Task implements JsonSerializable // ------------- - protected function addLuaLibraries(): void { + protected function addLuaLibraries(): void + { // register member methods $method_names = get_class_methods($this); $methods = []; foreach ($method_names as $method_name) { - $methods[$method_name] = fn() => [ call_user_func(array(&$this, $method_name), ...func_get_args()) ]; + $methods[$method_name] = fn() => [call_user_func(array(&$this, $method_name), ...func_get_args())]; } $this->lua_sandbox->registerLibrary("task", $methods); // register generic functionality $this->lua_sandbox->registerLibrary("php", [ - "print" => function($str) { + "print" => function ($str) { printf("%s\n", $str); }, - "replace" => "str_replace", - "replace_field" => function($field, $replacement, $str) { - return [ str_replace("{{" . $field . "}}", $replacement, $str) ]; - } + "replace" => function ($search, $replace, $str) { + return [str_replace(LuaUtils::l2pA($search), LuaUtils::l2pA($replace), $str)]; + }, + "replace_field" => function ($field, $replacement, $str) { + return [str_replace("{{" . $field . "}}", $replacement, $str)]; + }, + "trim" => function ($str, $chars = " \n\r\t\v\0") { + return [trim($str, $chars)]; + }, + "ltrim" => function ($str, $chars = " \n\r\t\v\0") { + return [ltrim($str, $chars)]; + }, + "rtrim" => function ($str, $chars = " \n\r\t\v\0") { + return [rtrim($str, $chars)]; + }, + "starts_with" => function ($str, $start) { + return [str_starts_with($str, $start)]; + }, ]); LuaUtils::registerLuaLibs($this->lua_sandbox); } - private function createLuaSandbox(): void { + + private function createLuaSandbox(): void + { if ($this->lua_sandbox === null) { $this->lua_sandbox = new LuaSandbox; $this->addLuaLibraries(); } } - private function luaCall(string $lua_function): void { + + private function luaCall(string $lua_function): void + { $this->createLuaSandbox(); $implementation = file_get_contents($this->getGameDir() . DIRECTORY_SEPARATOR . $this->lua_script); $function_call = "$lua_function()"; @@ -97,7 +116,8 @@ class Task implements JsonSerializable } // set task type - function setType(string $type): void { + function setType(string $type): void + { $this->type = $type; } @@ -117,7 +137,8 @@ class Task implements JsonSerializable return $this->max_mark; } - function setMark(float $mark): void { + function setMark(float $mark): void + { $this->mark = max($mark, 0.0); } @@ -126,15 +147,18 @@ class Task implements JsonSerializable return $this->mark; } - private function luaCheck(): void { + private function luaCheck(): void + { $this->luaCall("check"); } - protected function staticCheck(): void { + protected function staticCheck(): void + { $this->mark = $this->max_mark; } - function autoCheck(): void { + function autoCheck(): void + { if ($this->lua_script !== "") { $this->luaCheck(); } else { @@ -207,15 +231,18 @@ class Task implements JsonSerializable return $this->lua_script; } - public function getLuaParams(): array { + public function getLuaParams(): array + { return $this->lua_params; } - public function setLuaParams(array $lua_params): void { + public function setLuaParams(array $lua_params): void + { $this->lua_params = $lua_params; } - function getPlayerAnswer(): mixed { + function getPlayerAnswer(): mixed + { return $this->player_answer; } @@ -234,15 +261,22 @@ class Task implements JsonSerializable return $this->correct_answer; } - function setComment(string $comment): void { + function setComment(string $comment): void + { $this->comment = $comment; } - function getComment(): string { + function addCommentLine(string $cmtl): void { + $this->comment .= $cmtl . "
"; + } + + function getComment(): string + { return $this->comment; } - private function luaRandomize(): void { + private function luaRandomize(): void + { $this->luaCall("randomize"); } @@ -253,15 +287,18 @@ class Task implements JsonSerializable } } - function setGovernor(Game|Test|null &$governor): void { + function setGovernor(Game|Test|null &$governor): void + { $this->governor = &$governor; } - function &getGovernor(): Game|Test|null { + function &getGovernor(): Game|Test|null + { return $this->governor; } - function getGameDir(): string { + function getGameDir(): string + { $gov = $this->getGovernor(); if ($gov == null) { return "";