This commit is contained in:
Wiesner András 2025-10-14 11:25:01 +02:00
parent cf8c7a3e21
commit 6e54324d4f
3 changed files with 115 additions and 60 deletions

View File

@ -59,38 +59,38 @@ class LogicFunction implements JsonSerializable
return join("", $tt); 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 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 = self::genTerm($input_vars, count($input_vars), count($input_vars), $min_depth, $max_depth);
{
$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);
return new LogicFunction($term, $input_vars); return new LogicFunction($term, $input_vars);
} }
@ -249,7 +249,8 @@ class LogicFunction implements JsonSerializable
} }
public function drawNetwork(string $outvar = "f"): string { 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 ]);
} }
} }

View File

@ -4,7 +4,11 @@ require_once "LogicFunction.php";
class LuaUtils class LuaUtils
{ {
public static function l2pA(array $la): array { public static function l2pA(array|null $la): array {
if ($la === null) {
return [];
}
$r = []; $r = [];
$i = 0; $i = 0;
foreach ($la as $v) { foreach ($la as $v) {
@ -13,6 +17,19 @@ class LuaUtils
return $r; 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 { public static function registerLuaLibs(LuaSandbox &$sandbox): void {
self::registerLogicUtils($sandbox); self::registerLogicUtils($sandbox);
} }
@ -24,11 +41,11 @@ class LuaUtils
"changeRepresentation" => fn() => [ call_user_func(array(LogicUtils::class, "changeRepresentation"), ...func_get_args()) ], "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() ], "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() ], "genRandomLogicFunctionDNF" => fn($iv) => [ call_user_func(array(LogicFunction::class, "genRandomDNF"), self::l2pA($iv))->getExpression() ],
"isLogicFunctionValid" => fn($expr) => [ (new LogicFunction($expr))->isValid() ], "isLogicFunctionValid" => fn($expr) => [ (new LogicFunction($expr ?? "0"))->isValid() ],
"isLogicFunctionADNF" => fn($iv, $expr) => [ call_user_func(array(LogicFunction::class, "isCorrectDNF"), self::l2pA($iv), $expr) ], "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), "collectVariablesFromLogicFunction" => fn($expr) => call_user_func(array(LogicFunction::class, "collectVariables"), $expr ?? ""),
"convertLogicFunctionToTruthTable" => fn($expr, $iv) => [ (new LogicFunction($expr, self::l2pA($iv)))->getTruthTable() ], "convertLogicFunctionToTruthTable" => fn($expr, $iv) => [ (new LogicFunction($expr ?? "0", self::l2pA($iv)))->getTruthTable() ],
"drawLogicFunction" => fn($expr, $iv, $ov) => [ (new LogicFunction($expr, self::l2pA($iv)))->drawNetwork($ov) ], "drawLogicFunction" => fn($expr, $iv, $ov) => [ (new LogicFunction($expr ?? "0", self::l2pA($iv)))->drawNetwork($ov) ],
]); ]);
} }
} }

View File

@ -18,35 +18,54 @@ class Task implements JsonSerializable
// ------------- // -------------
protected function addLuaLibraries(): void { protected function addLuaLibraries(): void
{
// register member methods // register member methods
$method_names = get_class_methods($this); $method_names = get_class_methods($this);
$methods = []; $methods = [];
foreach ($method_names as $method_name) { 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); $this->lua_sandbox->registerLibrary("task", $methods);
// register generic functionality // register generic functionality
$this->lua_sandbox->registerLibrary("php", [ $this->lua_sandbox->registerLibrary("php", [
"print" => function($str) { "print" => function ($str) {
printf("%s\n", $str); printf("%s\n", $str);
}, },
"replace" => "str_replace", "replace" => function ($search, $replace, $str) {
"replace_field" => function($field, $replacement, $str) { return [str_replace(LuaUtils::l2pA($search), LuaUtils::l2pA($replace), $str)];
return [ str_replace("{{" . $field . "}}", $replacement, $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); LuaUtils::registerLuaLibs($this->lua_sandbox);
} }
private function createLuaSandbox(): void {
private function createLuaSandbox(): void
{
if ($this->lua_sandbox === null) { if ($this->lua_sandbox === null) {
$this->lua_sandbox = new LuaSandbox; $this->lua_sandbox = new LuaSandbox;
$this->addLuaLibraries(); $this->addLuaLibraries();
} }
} }
private function luaCall(string $lua_function): void {
private function luaCall(string $lua_function): void
{
$this->createLuaSandbox(); $this->createLuaSandbox();
$implementation = file_get_contents($this->getGameDir() . DIRECTORY_SEPARATOR . $this->lua_script); $implementation = file_get_contents($this->getGameDir() . DIRECTORY_SEPARATOR . $this->lua_script);
$function_call = "$lua_function()"; $function_call = "$lua_function()";
@ -97,7 +116,8 @@ class Task implements JsonSerializable
} }
// set task type // set task type
function setType(string $type): void { function setType(string $type): void
{
$this->type = $type; $this->type = $type;
} }
@ -117,7 +137,8 @@ class Task implements JsonSerializable
return $this->max_mark; return $this->max_mark;
} }
function setMark(float $mark): void { function setMark(float $mark): void
{
$this->mark = max($mark, 0.0); $this->mark = max($mark, 0.0);
} }
@ -126,15 +147,18 @@ class Task implements JsonSerializable
return $this->mark; return $this->mark;
} }
private function luaCheck(): void { private function luaCheck(): void
{
$this->luaCall("check"); $this->luaCall("check");
} }
protected function staticCheck(): void { protected function staticCheck(): void
{
$this->mark = $this->max_mark; $this->mark = $this->max_mark;
} }
function autoCheck(): void { function autoCheck(): void
{
if ($this->lua_script !== "") { if ($this->lua_script !== "") {
$this->luaCheck(); $this->luaCheck();
} else { } else {
@ -207,15 +231,18 @@ class Task implements JsonSerializable
return $this->lua_script; return $this->lua_script;
} }
public function getLuaParams(): array { public function getLuaParams(): array
{
return $this->lua_params; return $this->lua_params;
} }
public function setLuaParams(array $lua_params): void { public function setLuaParams(array $lua_params): void
{
$this->lua_params = $lua_params; $this->lua_params = $lua_params;
} }
function getPlayerAnswer(): mixed { function getPlayerAnswer(): mixed
{
return $this->player_answer; return $this->player_answer;
} }
@ -234,15 +261,22 @@ class Task implements JsonSerializable
return $this->correct_answer; return $this->correct_answer;
} }
function setComment(string $comment): void { function setComment(string $comment): void
{
$this->comment = $comment; $this->comment = $comment;
} }
function getComment(): string { function addCommentLine(string $cmtl): void {
$this->comment .= $cmtl . "<br>";
}
function getComment(): string
{
return $this->comment; return $this->comment;
} }
private function luaRandomize(): void { private function luaRandomize(): void
{
$this->luaCall("randomize"); $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; $this->governor = &$governor;
} }
function &getGovernor(): Game|Test|null { function &getGovernor(): Game|Test|null
{
return $this->governor; return $this->governor;
} }
function getGameDir(): string { function getGameDir(): string
{
$gov = $this->getGovernor(); $gov = $this->getGovernor();
if ($gov == null) { if ($gov == null) {
return ""; return "";