- LogicTask, LogicTaskBase added
- LuaUtils extended ...
This commit is contained in:
		
							parent
							
								
									0c76214bec
								
							
						
					
					
						commit
						4a2079cf10
					
				@ -362,9 +362,18 @@ class Game extends AutoStoring
 | 
			
		||||
        $columns = Game::getTableColumnIndices($header); // fetch column names
 | 
			
		||||
 | 
			
		||||
        // start iterating over tasks
 | 
			
		||||
        $count = 0;
 | 
			
		||||
        for ($i = 1; $i < $n; $i++) {
 | 
			
		||||
            $row = &$table[$i]; // fetch row
 | 
			
		||||
 | 
			
		||||
            $flags = Game::explodeFlags($row[0] ?? ""); // get flags
 | 
			
		||||
            if (in_array("hidden", $flags)) { // skip hidden tasks
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // count in this task
 | 
			
		||||
            $count++;
 | 
			
		||||
 | 
			
		||||
            // prepare a function that looks up the fields referenced by their labels
 | 
			
		||||
            $select_fn = function (array $cols) use (&$row, &$columns) {
 | 
			
		||||
                for ($i = 0; $i < count($cols); $i++) {
 | 
			
		||||
@ -382,7 +391,7 @@ class Game extends AutoStoring
 | 
			
		||||
 | 
			
		||||
            // fetch generic fields
 | 
			
		||||
            $a = [
 | 
			
		||||
                "flags" => Game::explodeFlags($row[0] ?? ""),
 | 
			
		||||
                "flags" => $flags,
 | 
			
		||||
                "type" => strtolower($select_fn(["Típus", "Type"])),
 | 
			
		||||
                "image_data" => $select_fn(["Kép", "Image"]),
 | 
			
		||||
                "question" => $select_fn(["Kérdés", "Question"]),
 | 
			
		||||
@ -403,6 +412,7 @@ class Game extends AutoStoring
 | 
			
		||||
                    $a["instruction"] = $row[$fuc];
 | 
			
		||||
                    break;
 | 
			
		||||
                case "truthtable":
 | 
			
		||||
                case "logicfunction":
 | 
			
		||||
                    $a["input_variables"] = Utils::str2a($row[$fuc]);
 | 
			
		||||
                    $a["output_variable"] = $row[$fuc + 1];
 | 
			
		||||
                    $a["expression"] = $row[$fuc + 2];
 | 
			
		||||
@ -426,9 +436,18 @@ class Game extends AutoStoring
 | 
			
		||||
 | 
			
		||||
            // generate the task
 | 
			
		||||
            $this->tasks[] = TaskFactory::fromArray($a, $this);
 | 
			
		||||
 | 
			
		||||
            // assign scoring strategy
 | 
			
		||||
            $sct = $select_fn(["Pontozás", "Scoring"]);
 | 
			
		||||
            if ($sct !== "") {
 | 
			
		||||
                $sct_fields = Utils::str2kv($sct);
 | 
			
		||||
                foreach ($sct_fields as $key => $value) {
 | 
			
		||||
                    $sct_fields[$key] = $value;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $result["n"] = $n - 1;
 | 
			
		||||
        $result["n"] = $count;
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -51,11 +51,12 @@ class LogicFunction implements JsonSerializable
 | 
			
		||||
//                printf("%d ", $vars[$this->input_vars[$k]]);
 | 
			
		||||
            }
 | 
			
		||||
            $out = self::$EXP_LANG->evaluate($expression, $vars);
 | 
			
		||||
            $out_str = $out ? "1" : "0";
 | 
			
		||||
//            printf("%d\n", $out);
 | 
			
		||||
            $tt[] = $out;
 | 
			
		||||
            $tt[] = $out_str;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return join("", array_map(fn($r) => ($r === True) ? 1 : 0, $tt));
 | 
			
		||||
        return join("", $tt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function genRandom(array $input_vars, int $min_depth = 2, int $max_depth = 3): LogicFunction
 | 
			
		||||
@ -93,7 +94,7 @@ class LogicFunction implements JsonSerializable
 | 
			
		||||
        return new LogicFunction($term, $input_vars);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function genRandomDF($input_vars): LogicFunction
 | 
			
		||||
    public static function genRandomDNF($input_vars): LogicFunction
 | 
			
		||||
    {
 | 
			
		||||
        $N = count($input_vars);
 | 
			
		||||
        $states = pow(2, $N);
 | 
			
		||||
@ -101,7 +102,7 @@ class LogicFunction implements JsonSerializable
 | 
			
		||||
        $verilog_term = "";
 | 
			
		||||
        for ($i = 0; $i < $states; $i++) {
 | 
			
		||||
            $inside = "";
 | 
			
		||||
            $omit = random_int(0, 1); // omit the variable or not?
 | 
			
		||||
            $omit = random_int(0, 1); // omit the term or not?
 | 
			
		||||
            if (!$omit) {
 | 
			
		||||
                for ($j = 0; $j < $N; $j++) {
 | 
			
		||||
                    $neg = !($i & (1 << $j)); // is it an inverted variable?
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								class/LuaUtils.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								class/LuaUtils.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
require_once "LogicFunction.php";
 | 
			
		||||
 | 
			
		||||
class LuaUtils
 | 
			
		||||
{
 | 
			
		||||
    public static function l2pA(array $la): array {
 | 
			
		||||
        $r = [];
 | 
			
		||||
        $i = 0;
 | 
			
		||||
        foreach ($la as $v) {
 | 
			
		||||
            $r[$i++] = $v;
 | 
			
		||||
        }
 | 
			
		||||
        return $r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function registerLuaLibs(LuaSandbox &$sandbox): void {
 | 
			
		||||
        self::registerLogicUtils($sandbox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function registerLogicUtils(LuaSandbox &$sandbox): void {
 | 
			
		||||
        $sandbox->registerLibrary("logic", [
 | 
			
		||||
            "extend" => fn() => [ call_user_func(array(LogicUtils::class, "extend"), ...func_get_args()) ],
 | 
			
		||||
            "complement" => fn() => [ call_user_func(array(LogicUtils::class, "complement"), ...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() ],
 | 
			
		||||
            "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) ],
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -37,6 +37,8 @@ class Task implements JsonSerializable
 | 
			
		||||
                return [ str_replace("{{" . $field . "}}", $replacement, $str) ];
 | 
			
		||||
            }
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        LuaUtils::registerLuaLibs($this->lua_sandbox);
 | 
			
		||||
    }
 | 
			
		||||
    private function createLuaSandbox(): void {
 | 
			
		||||
        if ($this->lua_sandbox === null) {
 | 
			
		||||
@ -116,7 +118,7 @@ class Task implements JsonSerializable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setMark(float $mark): void {
 | 
			
		||||
        $this->mark = $mark;
 | 
			
		||||
        $this->mark = max($mark, 0.0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getMark(): float
 | 
			
		||||
@ -129,7 +131,7 @@ class Task implements JsonSerializable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function staticCheck(): void {
 | 
			
		||||
        return;
 | 
			
		||||
        $this->mark = $this->max_mark;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function autoCheck(): void {
 | 
			
		||||
@ -249,7 +251,6 @@ class Task implements JsonSerializable
 | 
			
		||||
        if ($this->lua_script !== "") {
 | 
			
		||||
            $this->luaRandomize();
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setGovernor(Game|Test|null &$governor): void {
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,8 @@ require_once "Tasks/TruthTableTask.php";
 | 
			
		||||
 | 
			
		||||
require_once "Tasks/VerilogTask.php";
 | 
			
		||||
 | 
			
		||||
require_once "Tasks/LogicFunctionTask.php";
 | 
			
		||||
 | 
			
		||||
class TaskFactory
 | 
			
		||||
{
 | 
			
		||||
    static function fromArray(array $a, Game|Test|null &$governor = null): Task|null
 | 
			
		||||
@ -28,6 +30,9 @@ class TaskFactory
 | 
			
		||||
            case "truthtable":
 | 
			
		||||
                $task = new TruthTableTask($a);
 | 
			
		||||
                break;
 | 
			
		||||
            case "logicfunction":
 | 
			
		||||
                $task = new LogicFunctionTask($a);
 | 
			
		||||
                break;
 | 
			
		||||
            case "verilog":
 | 
			
		||||
                $task = new VerilogTask($a);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								class/Tasks/LogicFunctionTask.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								class/Tasks/LogicFunctionTask.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
require_once "LogicTaskBase.php";
 | 
			
		||||
 | 
			
		||||
class LogicFunctionTask extends LogicTaskBase
 | 
			
		||||
{
 | 
			
		||||
    private float $missing_minterm_score = -1.0; // score for a missing minterm
 | 
			
		||||
    public function __construct(array $a = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct("logicfunction", $a);
 | 
			
		||||
 | 
			
		||||
        $this->missing_minterm_score = $a["missing_minterm_score"] ?? -1.0;
 | 
			
		||||
 | 
			
		||||
        if (!$this->hasFlag("dnf")) {
 | 
			
		||||
            $this->setCorrectAnswer($this->getLogicFunction()->getExpression());
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->setCorrectAnswer($this->getLogicFunction()->toDNF());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toArray(string $mode = "all"): array
 | 
			
		||||
    {
 | 
			
		||||
        $a = parent::toArray($mode);
 | 
			
		||||
 | 
			
		||||
        if ($this->hasFlag("attachtruthtable")) {
 | 
			
		||||
            $a["truthtable"] = $this->getTruthtable();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($mode == "all") {
 | 
			
		||||
            $a["missing_minterm_score"] = $this->missing_minterm_score;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMissingMintermScore(): float
 | 
			
		||||
    {
 | 
			
		||||
        return $this->missing_minterm_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setMissingMintermScore(float $missing_minterm_score): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->missing_minterm_score = $missing_minterm_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function staticCheck(): void
 | 
			
		||||
    {
 | 
			
		||||
        $mark = 0.0;
 | 
			
		||||
        $pa = $this->player_answer ?? "";
 | 
			
		||||
        $iv = $this->getLogicFunction()->getInputVars();
 | 
			
		||||
        $palf = new LogicFunction($pa, $iv);
 | 
			
		||||
        if ($palf->isValid() && ((!$this->hasFlag("dnf")) || LogicFunction::isCorrectDNF($iv, $pa))) { // if the function is valid AND (if enabled) it is a correct DNF
 | 
			
		||||
            $patt = $palf->getTruthTable();
 | 
			
		||||
            $errs = $this->getTTDiffCntToCA($patt);
 | 
			
		||||
            $mark = $this->getMaxMark() + $errs * $this->getMissingMintermScore();
 | 
			
		||||
        }
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										111
									
								
								class/Tasks/LogicTaskBase.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								class/Tasks/LogicTaskBase.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
require_once "PicturedTask.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/LogicFunction.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/Utils.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/LuaUtils.php";
 | 
			
		||||
 | 
			
		||||
class LogicTaskBase extends PicturedTask
 | 
			
		||||
{
 | 
			
		||||
    private LogicFunction $lf; // logic function
 | 
			
		||||
    private string $output_variable; // output variable
 | 
			
		||||
 | 
			
		||||
    public function __construct(string $type, array $a = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($type, $a);
 | 
			
		||||
 | 
			
		||||
        if (isset($a["function"])) { // fetching from a JSON-stored object
 | 
			
		||||
            $this->lf = LogicFunction::fromArray($a["function"]);
 | 
			
		||||
        } else if (isset($a["expression"], $a["input_variables"])) { // building from the scratch
 | 
			
		||||
            $this->lf = new LogicFunction($a["expression"], $a["input_variables"]);
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->lf = new LogicFunction();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->output_variable = $a["output_variable"] ?? "f";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setOutputVariable(string $ovar): void {
 | 
			
		||||
        $this->output_variable = $ovar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOutputVariable(): string {
 | 
			
		||||
        return $this->output_variable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLogicFunction(LogicFunction $lf): void {
 | 
			
		||||
        $this->lf = $lf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunction(): LogicFunction {
 | 
			
		||||
        return $this->lf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getTTDiffCntToCA(string $ott): int {
 | 
			
		||||
        $cans_tt = $this->getTruthTable();
 | 
			
		||||
        $errs = 0;
 | 
			
		||||
        for ($i = 0; $i < $this->getLogicFunction()->getNStates(); $i++) {
 | 
			
		||||
            if (($ott[$i] ?? " ") != $cans_tt[$i]) {
 | 
			
		||||
                $errs++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return $errs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toArray(string $mode = "all"): array
 | 
			
		||||
    {
 | 
			
		||||
        $a = parent::toArray($mode);
 | 
			
		||||
 | 
			
		||||
        if ($mode === "all") {
 | 
			
		||||
            $a["function"] = $this->lf->toArray();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $a["output_variable"] = $this->output_variable;
 | 
			
		||||
        $a["input_variables"] = $this->lf->getInputVars();
 | 
			
		||||
 | 
			
		||||
        return $a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function randomize(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::randomize();
 | 
			
		||||
 | 
			
		||||
        if ($this->hasFlag("drawnetwork")) {
 | 
			
		||||
            $this->setImageData($this->lf->drawNetwork($this->output_variable));
 | 
			
		||||
            $this->setImageType("html");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ---- Lua specific ----
 | 
			
		||||
 | 
			
		||||
    public function generateRandomFunction(array $input_vars, int $min_depth, int $max_depth): void {
 | 
			
		||||
        $this->lf = LogicFunction::genRandom(LuaUtils::l2pA($input_vars), $min_depth, $max_depth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function generateRandomDF(array $input_vars): void {
 | 
			
		||||
        $this->lf = LogicFunction::genRandomDNF(LuaUtils::l2pA($input_vars));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFunctionAsDNF(): string {
 | 
			
		||||
        return $this->lf->toDNF();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLogicFunctionExpr(string $expr, array $input_vars = []): void {
 | 
			
		||||
        $this->lf = new LogicFunction($expr, LuaUtils::l2pA($input_vars));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunctionExpr(string $fmt = "verilog_bitwise"): string {
 | 
			
		||||
        return $this->lf->getExpression($fmt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunctionDNF(): string {
 | 
			
		||||
        return $this->lf->toDNF();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTruthTable(): string {
 | 
			
		||||
        return $this->lf->getTruthTable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -106,9 +106,9 @@ class NumberConversionTask extends OpenEndedTask
 | 
			
		||||
    {
 | 
			
		||||
        $mark = 0.0;
 | 
			
		||||
        if ($this->hasFlag("acceptwithoutleadingzeros")) {
 | 
			
		||||
            $mark = (ltrim($this->player_answer, " 0") === ltrim($this->correct_answer, "0")) ? 1.0 : 0.0;
 | 
			
		||||
            $mark = (ltrim($this->player_answer, " 0") === ltrim($this->correct_answer, "0")) ? $this->getMaxMark() : 0.0;
 | 
			
		||||
        } else {
 | 
			
		||||
            $mark = (trim($this->player_answer) === trim($this->correct_answer)) ? 1.0 : 0.0;
 | 
			
		||||
            $mark = (trim($this->player_answer) === trim($this->correct_answer)) ? $this->getMaxMark() : 0.0;
 | 
			
		||||
        }
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@ class OpenEndedTask extends PicturedTask
 | 
			
		||||
 | 
			
		||||
    public function staticCheck(): void
 | 
			
		||||
    {
 | 
			
		||||
        $mark = in_array($this->player_answer, $this->correct_answer) ? 1.0 : 0.0;
 | 
			
		||||
        $mark = in_array($this->player_answer, $this->correct_answer) ? $this->getMaxMark() : 0.0;
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,16 @@ class PicturedTask extends Task
 | 
			
		||||
        return $this->image_type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setUrlData(string $url_data): void {
 | 
			
		||||
        $this->setImageData($url_data);
 | 
			
		||||
        $this->setImageType("url");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setHtmlData(string $svg_data): void {
 | 
			
		||||
        $this->setImageData($svg_data);
 | 
			
		||||
        $this->setImageType("html");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function toArray(string $mode = "all"): array
 | 
			
		||||
    {
 | 
			
		||||
        $a = parent::toArray($mode);
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ class SingleChoiceTask extends PicturedTask
 | 
			
		||||
 | 
			
		||||
    function staticCheck(): void
 | 
			
		||||
    {
 | 
			
		||||
        $mark = ($this->player_answer == $this->correct_answer) ? 1.0 : 0.0;
 | 
			
		||||
        $mark = ($this->player_answer == $this->correct_answer) ? $this->getMaxMark() : 0.0;
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,119 +1,42 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
require_once "OpenEndedTask.php";
 | 
			
		||||
require_once "LogicTaskBase.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/LogicFunction.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/Utils.php";
 | 
			
		||||
 | 
			
		||||
class TruthTableTask extends PicturedTask
 | 
			
		||||
class TruthTableTask extends LogicTaskBase
 | 
			
		||||
{
 | 
			
		||||
    private LogicFunction $lf; // logic functions
 | 
			
		||||
    private string $output_variable; // output variable
 | 
			
		||||
    private float $bad_line_score; // points for a bad line in the truth table
 | 
			
		||||
    public function __construct(array $a = null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct("truthtable", $a);
 | 
			
		||||
 | 
			
		||||
        if (isset($a["function"])) { // fetching from a JSON-stored object
 | 
			
		||||
            $this->lf = LogicFunction::fromArray($a["function"]);
 | 
			
		||||
        } else if (isset($a["expression"], $a["input_variables"])) { // building from the scratch
 | 
			
		||||
            $this->lf = new LogicFunction($a["expression"], $a["input_variables"]);
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->lf = new LogicFunction();
 | 
			
		||||
        }
 | 
			
		||||
        $this->bad_line_score = $a["bad_line_score"] ?? -1.0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        $this->setOutputVariable($a["output_variable"] ?? "f");
 | 
			
		||||
    function setBadLineScore(float $bad_line_score): void {
 | 
			
		||||
        $this->bad_line_score = $bad_line_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getBadLineScore(): float {
 | 
			
		||||
        return $this->bad_line_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function staticCheck(): void
 | 
			
		||||
    {
 | 
			
		||||
        $ans_tt = $this->player_answer;
 | 
			
		||||
        $cans_tt = $this->lf->getTruthTable();
 | 
			
		||||
        $errs = 0;
 | 
			
		||||
        for ($i = 0; $i < $this->lf->getNStates(); $i++) {
 | 
			
		||||
            if (($ans_tt[$i] ?? " ") != $cans_tt[$i]) {
 | 
			
		||||
                $errs++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $mark = ($errs === 0) ? 1.0 : 0.0;
 | 
			
		||||
        $errs = $this->getTTDiffCntToCA($this->player_answer ?? "");
 | 
			
		||||
        $mark = $this->getMaxMark() + $errs * $this->getBadLineScore();
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setOutputVariable(string $ovar): void {
 | 
			
		||||
        $this->output_variable = $ovar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOutputVariable(): string {
 | 
			
		||||
        return $this->output_variable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLogicFunction(LogicFunction $lf): void {
 | 
			
		||||
        $this->lf = $lf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunction(): LogicFunction {
 | 
			
		||||
        return $this->lf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function sanitizeIndices(array $a): array {
 | 
			
		||||
        $r = [];
 | 
			
		||||
        $i = 0;
 | 
			
		||||
        foreach ($a as $v) {
 | 
			
		||||
            $r[$i++] = $v;
 | 
			
		||||
        }
 | 
			
		||||
        return $r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function generateRandomFunction(array $input_vars, int $min_depth, int $max_depth): void {
 | 
			
		||||
        $this->lf = LogicFunction::genRandom(self::sanitizeIndices($input_vars), $min_depth, $max_depth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function generateRandomDF(array $input_vars): void {
 | 
			
		||||
        $this->lf = LogicFunction::genRandomDF(self::sanitizeIndices($input_vars));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFunctionAsDNF(): string {
 | 
			
		||||
        return $this->lf->toDNF();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isValidDNF(): bool {
 | 
			
		||||
        return LogicFunction::isCorrectDNF($this->lf->getInputVars(), $this->lf->getExpression());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLogicFunctionExpr(string $expr, array $input_vars = []): void {
 | 
			
		||||
        $this->lf = new LogicFunction($expr, self::sanitizeIndices($input_vars));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunctionExpr(string $fmt = "verilog_bitwise"): string {
 | 
			
		||||
        return $this->lf->getExpression($fmt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLogicFunctionDNF(): string {
 | 
			
		||||
        return $this->lf->toDNF();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toArray(string $mode = "all"): array
 | 
			
		||||
    {
 | 
			
		||||
        $a = parent::toArray($mode);
 | 
			
		||||
 | 
			
		||||
        if ($mode === "all") {
 | 
			
		||||
            $a["function"] = $this->lf->toArray();
 | 
			
		||||
            $a["bad_line_score"] = $this->bad_line_score;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $a["correct_answer"] = $this->lf->getTruthTable();
 | 
			
		||||
        $a["input_variables"] = $this->lf->getInputVars();
 | 
			
		||||
        $a["output_variable"] = $this->output_variable;
 | 
			
		||||
        $a["correct_answer"] = $this->getLogicFunction()->getTruthTable();
 | 
			
		||||
 | 
			
		||||
        return $a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function randomize(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::randomize();
 | 
			
		||||
 | 
			
		||||
        if ($this->hasFlag("drawnetwork")) {
 | 
			
		||||
            $this->setImageData($this->lf->drawNetwork($this->output_variable));
 | 
			
		||||
            $this->setImageType("svg");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -6,6 +6,7 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
{
 | 
			
		||||
    private string $test_bench_fn; // test bench file name
 | 
			
		||||
    private string $compile_log; // short explanation for the marking
 | 
			
		||||
    private float $error_score; // points received for an error
 | 
			
		||||
    private const FAILED_MARK = "[FAILED]"; // mark at the beginning of testbench results indicating a failed combination
 | 
			
		||||
 | 
			
		||||
    public function __construct(array &$a = null)
 | 
			
		||||
@ -14,6 +15,7 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
 | 
			
		||||
        $this->compile_log = $a["compile_log"] ?? "";
 | 
			
		||||
        $this->test_bench_fn = $a["test_bench_fn"] ?? "";
 | 
			
		||||
        $this->error_score = $a["error_score"] ?? -1.0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function verifyCode(): bool
 | 
			
		||||
@ -26,7 +28,7 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function executeTest(): bool
 | 
			
		||||
    private function executeTest(): int
 | 
			
		||||
    {
 | 
			
		||||
        // store the user's answer
 | 
			
		||||
        $module_code_fn = tempnam(sys_get_temp_dir(), "verilogtask_user_module_");
 | 
			
		||||
@ -74,7 +76,17 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
        @unlink($test_bench_fn);
 | 
			
		||||
        @unlink($output_fn);
 | 
			
		||||
 | 
			
		||||
        return $failed_count == 0;
 | 
			
		||||
        return $failed_count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setErrorScore(float $error_score): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->error_score = $error_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getErrorScore(): float
 | 
			
		||||
    {
 | 
			
		||||
        return $this->error_score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function staticCheck(): void
 | 
			
		||||
@ -85,10 +97,12 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
        $mark = 0.0;
 | 
			
		||||
        if ($this->verifyCode()) {
 | 
			
		||||
            // run the simulation
 | 
			
		||||
            $test_ok = $this->executeTest();
 | 
			
		||||
 | 
			
		||||
            $mark = $test_ok ? 1.0 : 0.0;  // FIXME
 | 
			
		||||
            $failed_count = $this->executeTest();
 | 
			
		||||
            if ($failed_count != PHP_INT_MAX) {
 | 
			
		||||
                $mark = $this->getMaxMark() + $failed_count * $this->error_score;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->setMark($mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -100,6 +114,7 @@ class VerilogTask extends PicturedTask
 | 
			
		||||
 | 
			
		||||
        if ($mode == "all") {
 | 
			
		||||
            $a["test_bench_fn"] = $this->test_bench_fn;
 | 
			
		||||
            $a["error_score"] = $this->error_score;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $a;
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,22 @@ class Utils
 | 
			
		||||
    public static function str2kv(string $str): array
 | 
			
		||||
    {
 | 
			
		||||
        preg_match_all("/([^,= ]+)=([^,= ]+)/", $str, $r);
 | 
			
		||||
        return array_combine($r[1], $r[2]);
 | 
			
		||||
        $a = array_combine($r[1], $r[2]);
 | 
			
		||||
 | 
			
		||||
        foreach ($a as &$v) {
 | 
			
		||||
            if (is_numeric($v)) { // is it a numeric value?
 | 
			
		||||
                if (((int)$v) == ((double)$v)) { // is it an integer?
 | 
			
		||||
                    $v = (int)$v;
 | 
			
		||||
                } else { // is it a float?
 | 
			
		||||
                    $v = (double)$v;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (in_array(strtolower($v), ["true", "false"]) ) { // it's a boolean
 | 
			
		||||
                $v = $v === "true";
 | 
			
		||||
            } else if (str_starts_with($v, '"') && str_ends_with($v, '"')) { // it's a string
 | 
			
		||||
                $v = substr($v, 1, strlen($v) - 2); // strip leading and trailing quotes
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return $a;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function str2a(string $str): array {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										188
									
								
								js/tasks.js
									
									
									
									
									
								
							
							
						
						
									
										188
									
								
								js/tasks.js
									
									
									
									
									
								
							@ -36,19 +36,26 @@ class Task extends HTMLElement {
 | 
			
		||||
                margin-bottom: 0.5em;
 | 
			
		||||
                border-radius: 0.3em;
 | 
			
		||||
            }
 | 
			
		||||
            section.seq-num {
 | 
			
		||||
            section.seq-num, section.mark {
 | 
			
		||||
                display: block;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                right: 0;
 | 
			
		||||
                padding: 0.5em;
 | 
			
		||||
                bottom: 0;
 | 
			
		||||
                background-color: #176767;
 | 
			
		||||
                color: whitesmoke;
 | 
			
		||||
                border-bottom-right-radius: 0.3em;
 | 
			
		||||
                border-top-left-radius: 0.3em;
 | 
			
		||||
                width: 2em;
 | 
			
		||||
                z-index: 10;
 | 
			
		||||
            }
 | 
			
		||||
            section.seq-num {
 | 
			
		||||
                bottom: 0;
 | 
			
		||||
                border-bottom-right-radius: 0.3em;
 | 
			
		||||
                border-top-left-radius: 0.3em;
 | 
			
		||||
            }
 | 
			
		||||
            section.mark {
 | 
			
		||||
                top: 0;
 | 
			
		||||
                border-top-right-radius: 0.3em;
 | 
			
		||||
                border-bottom-left-radius: 0.3em;
 | 
			
		||||
            }
 | 
			
		||||
            section.answer-container {
 | 
			
		||||
                /* (empty) */
 | 
			
		||||
            }
 | 
			
		||||
@ -56,7 +63,7 @@ class Task extends HTMLElement {
 | 
			
		||||
                background-color: #e5d8d3;
 | 
			
		||||
            }
 | 
			
		||||
            code {
 | 
			
		||||
                font-family: 'Monaco', monospace;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            section#correct-answer {
 | 
			
		||||
@ -96,6 +103,8 @@ class Task extends HTMLElement {
 | 
			
		||||
        question_span.classList.add("question");
 | 
			
		||||
        let answer_container = document.createElement("section");
 | 
			
		||||
        answer_container.classList.add("answer-container");
 | 
			
		||||
        let mark_section = document.createElement("section");
 | 
			
		||||
        mark_section.classList.add("mark");
 | 
			
		||||
        let seq_num_section = document.createElement("section");
 | 
			
		||||
        seq_num_section.classList.add("seq-num");
 | 
			
		||||
        seq_num_section.innerText = `${this.sequence_number + 1}.`;
 | 
			
		||||
@ -106,6 +115,7 @@ class Task extends HTMLElement {
 | 
			
		||||
 | 
			
		||||
        task_box.append(question_span);
 | 
			
		||||
        task_box.append(answer_container);
 | 
			
		||||
        task_box.append(mark_section);
 | 
			
		||||
        task_box.append(seq_num_section);
 | 
			
		||||
        task_box.append(ca_section);
 | 
			
		||||
        task_box.append(comment_sec);
 | 
			
		||||
@ -115,6 +125,7 @@ class Task extends HTMLElement {
 | 
			
		||||
        this.task_box = task_box;
 | 
			
		||||
        this.question_span = question_span;
 | 
			
		||||
        this.answer_container = answer_container;
 | 
			
		||||
        this.mark_section = mark_section;
 | 
			
		||||
        this.seq_num_section = seq_num_section;
 | 
			
		||||
        this.ca_section = ca_section;
 | 
			
		||||
        this.comment_sec = comment_sec;
 | 
			
		||||
@ -198,10 +209,21 @@ class Task extends HTMLElement {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    displayMarking() {
 | 
			
		||||
        if (this.isConcluded) {
 | 
			
		||||
            this.mark_section.innerText = `${this.mark}/${this.max_mark}`;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.mark_section.innerText = `${this.max_mark}`;
 | 
			
		||||
        }
 | 
			
		||||
        this.mark_section.innerHTML += `<span style="font-size: 70%">p</span>`
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fromArray(a) {
 | 
			
		||||
        this.setQuestion(a["question"]);
 | 
			
		||||
        this.playerAnswer = a["player_answer"];
 | 
			
		||||
        this.correctAnswer = a["correct_answer"];
 | 
			
		||||
        this.max_mark = a["max_mark"];
 | 
			
		||||
        this.mark = a["mark"];
 | 
			
		||||
 | 
			
		||||
        let comment = a["comment"];
 | 
			
		||||
        if ((comment !== undefined) && (comment !== null) && (comment !== "")) {
 | 
			
		||||
@ -217,6 +239,8 @@ class Task extends HTMLElement {
 | 
			
		||||
        if (this.isConcluded) {
 | 
			
		||||
            this.displayCorrectAnswer();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.displayMarking();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -258,7 +282,7 @@ class PicturedTask extends Task {
 | 
			
		||||
                this.img.src = data.trim();
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
            case "svg":
 | 
			
		||||
            case "html":
 | 
			
		||||
            {
 | 
			
		||||
                this.img = document.createElement("section");
 | 
			
		||||
                this.img.classList.add("question-image");
 | 
			
		||||
@ -393,6 +417,8 @@ class SingleChoiceTask extends PicturedTask {
 | 
			
		||||
class OpenEndedTask extends PicturedTask {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super("openended");
 | 
			
		||||
 | 
			
		||||
        this.ca_prefix = "<b>Lehetséges megoldások:</b>";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createStyle() {
 | 
			
		||||
@ -400,7 +426,7 @@ class OpenEndedTask extends PicturedTask {
 | 
			
		||||
 | 
			
		||||
        this.css.innerHTML += `
 | 
			
		||||
            input[type="text"] {
 | 
			
		||||
                font-family: 'Monaco', monospaced;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
                border-width: 0 0 2.2pt 0;
 | 
			
		||||
                background-color: transparent;
 | 
			
		||||
                width: calc(100% - 4em);
 | 
			
		||||
@ -434,7 +460,9 @@ class OpenEndedTask extends PicturedTask {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    displayCorrectAnswer() {
 | 
			
		||||
        this.ca_section.innerHTML = "<b>Lehetséges megoldások:</b><br style='margin-bottom: 0.3em'>" + this.correctAnswer.join(", <i>VAGY</i><br>");
 | 
			
		||||
        if (this.correctAnswer !== null) {
 | 
			
		||||
            this.ca_section.innerHTML = this.ca_prefix + "<br style='margin-bottom: 0.3em'>" + this.correctAnswer.join(", <i>VAGY</i><br>");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fromArray(a) {
 | 
			
		||||
@ -442,12 +470,15 @@ class OpenEndedTask extends PicturedTask {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set playerAnswer(player_answer) {
 | 
			
		||||
        if (player_answer === null) {
 | 
			
		||||
            player_answer = "";
 | 
			
		||||
        }
 | 
			
		||||
        super.playerAnswer = player_answer;
 | 
			
		||||
        this.answer_tf.value = player_answer;
 | 
			
		||||
        this.answer_tf.value = this.playerAnswer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get playerAnswer() {
 | 
			
		||||
        return this.player_answer;
 | 
			
		||||
        return super.playerAnswer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateAnswerFieldState() {
 | 
			
		||||
@ -489,7 +520,7 @@ class NumberConversionTask extends OpenEndedTask {
 | 
			
		||||
            section#src, section#dst {
 | 
			
		||||
                position: relative;
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
                font-family: 'Monaco', monospace;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
                color: #176767;
 | 
			
		||||
            }
 | 
			
		||||
            section#src {
 | 
			
		||||
@ -574,7 +605,7 @@ class Switch extends HTMLElement {
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
                padding: 0.2em 0.5em;
 | 
			
		||||
                cursor: pointer;
 | 
			
		||||
                font-family: 'Monaco', monospace;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
            }
 | 
			
		||||
            section.button[disabled="false"]:hover {
 | 
			
		||||
                background-color: #408d8d;
 | 
			
		||||
@ -651,6 +682,28 @@ class Switch extends HTMLElement {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var truth_table_css = `
 | 
			
		||||
    table#tt {
 | 
			
		||||
        border: 1.5pt solid #176767;
 | 
			
		||||
        margin: 0.5em auto;
 | 
			
		||||
        border-spacing: 0;
 | 
			
		||||
        font-family: 'Source Code Pro', monospace;
 | 
			
		||||
    }
 | 
			
		||||
    table#tt tr:not(:last-child) td {
 | 
			
		||||
        border-bottom: 1.2pt solid black;
 | 
			
		||||
    }
 | 
			
		||||
    table#tt th {
 | 
			
		||||
        border-bottom: 1.5pt dotted black
 | 
			
		||||
    }
 | 
			
		||||
    table#tt td, table#tt th {
 | 
			
		||||
        min-width: 3ch;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
    table#tt td:last-child, table#tt th:last-child {
 | 
			
		||||
        border-left: 1.5pt dashed black;
 | 
			
		||||
    }
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
class TruthTableTask extends PicturedTask {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super("truthtable");
 | 
			
		||||
@ -663,27 +716,7 @@ class TruthTableTask extends PicturedTask {
 | 
			
		||||
    createStyle() {
 | 
			
		||||
        super.createStyle();
 | 
			
		||||
 | 
			
		||||
        this.css.innerHTML += `
 | 
			
		||||
            table#tt {
 | 
			
		||||
                border: 1.5pt solid #176767;
 | 
			
		||||
                margin: 0.5em auto;
 | 
			
		||||
                border-spacing: 0;
 | 
			
		||||
                font-family: 'Monaco', monospace;
 | 
			
		||||
            }
 | 
			
		||||
            table#tt tr:not(:last-child) td {
 | 
			
		||||
                border-bottom: 1.2pt solid black;
 | 
			
		||||
            }
 | 
			
		||||
            table#tt th {
 | 
			
		||||
                border-bottom: 1.5pt dotted black
 | 
			
		||||
            }
 | 
			
		||||
            table#tt td, table#tt th {
 | 
			
		||||
                min-width: 3ch;
 | 
			
		||||
                text-align: center;
 | 
			
		||||
            }
 | 
			
		||||
            table#tt td:last-child, table#tt th:last-child {
 | 
			
		||||
                border-left: 1.5pt dashed black;
 | 
			
		||||
            }
 | 
			
		||||
        `;
 | 
			
		||||
        this.css.innerHTML += truth_table_css;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createElements() {
 | 
			
		||||
@ -775,6 +808,91 @@ class TruthTableTask extends PicturedTask {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class LogicFunctionTask extends OpenEndedTask {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
        this.type = "logicfunction";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createStyle() {
 | 
			
		||||
        super.createStyle();
 | 
			
		||||
 | 
			
		||||
        this.css.innerHTML += truth_table_css;
 | 
			
		||||
        this.css.innerHTML += `
 | 
			
		||||
            section#assignment-sec {
 | 
			
		||||
                position: relative;
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
                color: #176767;
 | 
			
		||||
                margin-right: 1ch;
 | 
			
		||||
            }
 | 
			
		||||
            input[type="text"] {
 | 
			
		||||
                min-width: 5em;
 | 
			
		||||
                width: 85%;
 | 
			
		||||
                font-family: 'Source Code Pro', monospace;
 | 
			
		||||
            }
 | 
			
		||||
        `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createElements() {
 | 
			
		||||
        super.createElements();
 | 
			
		||||
 | 
			
		||||
        let assignment_sec = document.createElement("section");
 | 
			
		||||
        assignment_sec.id = "assignment-sec";
 | 
			
		||||
 | 
			
		||||
        this.answer_container.insertBefore(assignment_sec, this.answer_tf);
 | 
			
		||||
 | 
			
		||||
        this.assignment_sec = assignment_sec;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drawTruthTable() {
 | 
			
		||||
        let N = this.input_variables.length;
 | 
			
		||||
        let M = (1 << N);
 | 
			
		||||
 | 
			
		||||
        let table = "<table id='tt'>";
 | 
			
		||||
        table += "<tr>";
 | 
			
		||||
        for (let i = 0; i < N; i++) {
 | 
			
		||||
            table += "<th>" + this.input_variables[i] + "</th>";
 | 
			
		||||
        }
 | 
			
		||||
        table += "<th>" + this.output_variable + "</th>";
 | 
			
		||||
        table += "</tr>";
 | 
			
		||||
        for (let i = 0; i < M; i++) {
 | 
			
		||||
            table += "<tr>";
 | 
			
		||||
            for (let j = 0; j < N; j++) {
 | 
			
		||||
                table += "<td>" + ((i >> (N - j - 1)) & 1).toString() + "</td>";
 | 
			
		||||
            }
 | 
			
		||||
            table += "<td>" + this.truth_table.charAt(i) + "</td>"
 | 
			
		||||
            table += "</tr>";
 | 
			
		||||
        }
 | 
			
		||||
        table += "</table>";
 | 
			
		||||
 | 
			
		||||
        this.imgType = "html";
 | 
			
		||||
        this.imgData = table;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fromArray(a) {
 | 
			
		||||
        super.fromArray(a);
 | 
			
		||||
 | 
			
		||||
        this.input_variables = a["input_variables"];
 | 
			
		||||
        this.output_variable = a["output_variable"];
 | 
			
		||||
        this.truth_table = a["truthtable"];
 | 
			
		||||
 | 
			
		||||
        this.assignment_sec.innerHTML = `${a["output_variable"]} = `;
 | 
			
		||||
 | 
			
		||||
        if ((this.truth_table !== undefined) && (this.truth_table !== null) && (this.truth_table !== "")) {
 | 
			
		||||
            this.drawTruthTable();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set correctAnswer(correct_answer) {
 | 
			
		||||
        super.correctAnswer = [ "<code>" + correct_answer + "</code>" ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get correctAnswer() {
 | 
			
		||||
        return super.correctAnswer;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class VerilogTask extends PicturedTask {
 | 
			
		||||
    //static observedAttributes = ["language"]
 | 
			
		||||
    constructor() {
 | 
			
		||||
@ -920,7 +1038,9 @@ class VerilogTask extends PicturedTask {
 | 
			
		||||
customElements.define('singlechoice-task', SingleChoiceTask);
 | 
			
		||||
customElements.define('openended-task', OpenEndedTask);
 | 
			
		||||
customElements.define('numberconversion-task', NumberConversionTask);
 | 
			
		||||
customElements.define('truthtable-task', TruthTableTask);
 | 
			
		||||
customElements.define('slide-switch', Switch);
 | 
			
		||||
customElements.define('truthtable-task', TruthTableTask);
 | 
			
		||||
customElements.define('logicfunction-task', LogicFunctionTask);
 | 
			
		||||
customElements.define('verilog-task', VerilogTask);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
<body>
 | 
			
		||||
<section style="margin: 0 auto; padding-top: 10ex; text-align: center">
 | 
			
		||||
    <img src="media/maintenance.png" style="width: 16vw">
 | 
			
		||||
    <h3 style="font-family: 'Monaco', monospace"> Az oldal karbantartás alatt áll!</h3>
 | 
			
		||||
    <h3 style="font-family: 'Courier New', monospace"> Az oldal karbantartás alatt áll!</h3>
 | 
			
		||||
</section>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -47,9 +47,9 @@ if (!$gameMgr->getGame($game_id)->isUserContributorOrOwner($user_data["nickname"
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<section style="margin-bottom: 0.3em">
 | 
			
		||||
    <input type="text" placeholder="Szűrőfeltétel" id="filter" style="font-family: 'Monaco', monospace; width: 50em;">
 | 
			
		||||
    <input type="text" placeholder="Csoportok" id="groups" style="font-family: 'Monaco', monospace; width: 30em;">
 | 
			
		||||
    <input type="text" placeholder="Rendezés" id="orderby" style="font-family: 'Monaco', monospace; width: 30em;">
 | 
			
		||||
    <input type="text" placeholder="Szűrőfeltétel" id="filter" style="font-family: 'Source Code Pro', monospace; width: 50em;">
 | 
			
		||||
    <input type="text" placeholder="Csoportok" id="groups" style="font-family: 'Source Code Pro', monospace; width: 30em;">
 | 
			
		||||
    <input type="text" placeholder="Rendezés" id="orderby" style="font-family: 'Source Code Pro', monospace; width: 30em;">
 | 
			
		||||
    <input type="button" value="Szűrés" onclick="fetch_results()">
 | 
			
		||||
    <input type="button" value="Jelentés előállítása" onclick="generate_report()">
 | 
			
		||||
    <input type="button" value="Kijelöltek törlése" onclick="delete_tests()"><br>
 | 
			
		||||
 | 
			
		||||
@ -135,7 +135,7 @@ span.answer[correct=true] {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.terminal-style {
 | 
			
		||||
    font-family: 'Monaco', monospace;
 | 
			
		||||
    font-family: 'Source Code Pro', monospace;
 | 
			
		||||
    width: 40em;
 | 
			
		||||
    font-size: 12pt;
 | 
			
		||||
}
 | 
			
		||||
@ -49,7 +49,7 @@ section.answer input[type="radio"]:checked+label:not(.correct-answer) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code {
 | 
			
		||||
    font-family: 'Monaco', monospace;
 | 
			
		||||
    font-family: 'Source Code Pro', monospace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img.question-image {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
@import url('https://fonts.googleapis.com/css2?family=Autour+One&family=Kanit:wght@500&display=swap');
 | 
			
		||||
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0");
 | 
			
		||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
 | 
			
		||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap');
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
    font-family: 'Autour One', sans-serif;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user