diff --git a/class/Game.php b/class/Game.php index 16141bb..f8535b2 100644 --- a/class/Game.php +++ b/class/Game.php @@ -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; } diff --git a/class/LogicFunction.php b/class/LogicFunction.php index ed8eea5..417734a 100644 --- a/class/LogicFunction.php +++ b/class/LogicFunction.php @@ -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? diff --git a/class/LuaUtils.php b/class/LuaUtils.php new file mode 100644 index 0000000..3854111 --- /dev/null +++ b/class/LuaUtils.php @@ -0,0 +1,34 @@ +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) ], + ]); + } +} \ No newline at end of file diff --git a/class/Task.php b/class/Task.php index 3e245df..7da929b 100644 --- a/class/Task.php +++ b/class/Task.php @@ -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 { diff --git a/class/TaskFactory.php b/class/TaskFactory.php index aca9126..3e7a71f 100644 --- a/class/TaskFactory.php +++ b/class/TaskFactory.php @@ -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; diff --git a/class/Tasks/LogicFunctionTask.php b/class/Tasks/LogicFunctionTask.php new file mode 100644 index 0000000..701a16c --- /dev/null +++ b/class/Tasks/LogicFunctionTask.php @@ -0,0 +1,59 @@ +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); + } +} \ No newline at end of file diff --git a/class/Tasks/LogicTaskBase.php b/class/Tasks/LogicTaskBase.php new file mode 100644 index 0000000..3317a4a --- /dev/null +++ b/class/Tasks/LogicTaskBase.php @@ -0,0 +1,111 @@ +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(); + } +} \ No newline at end of file diff --git a/class/Tasks/NumberConversionTask.php b/class/Tasks/NumberConversionTask.php index 21bc9e0..8afc0c8 100644 --- a/class/Tasks/NumberConversionTask.php +++ b/class/Tasks/NumberConversionTask.php @@ -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); } diff --git a/class/Tasks/OpenEndedTask.php b/class/Tasks/OpenEndedTask.php index ff83c8e..9276f80 100644 --- a/class/Tasks/OpenEndedTask.php +++ b/class/Tasks/OpenEndedTask.php @@ -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); } diff --git a/class/Tasks/PicturedTask.php b/class/Tasks/PicturedTask.php index ddab455..e572e76 100644 --- a/class/Tasks/PicturedTask.php +++ b/class/Tasks/PicturedTask.php @@ -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); diff --git a/class/Tasks/SingleChoiceTask.php b/class/Tasks/SingleChoiceTask.php index 16f01c0..c915b9d 100644 --- a/class/Tasks/SingleChoiceTask.php +++ b/class/Tasks/SingleChoiceTask.php @@ -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); } diff --git a/class/Tasks/TruthTableTask.php b/class/Tasks/TruthTableTask.php index 75676fc..40f3751 100644 --- a/class/Tasks/TruthTableTask.php +++ b/class/Tasks/TruthTableTask.php @@ -1,119 +1,42 @@ 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"); - } - } } \ No newline at end of file diff --git a/class/Tasks/VerilogTask.php b/class/Tasks/VerilogTask.php index 405e200..42ff210 100644 --- a/class/Tasks/VerilogTask.php +++ b/class/Tasks/VerilogTask.php @@ -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; diff --git a/class/Utils.php b/class/Utils.php index f494eb8..2abc6f5 100644 --- a/class/Utils.php +++ b/class/Utils.php @@ -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 { diff --git a/js/tasks.js b/js/tasks.js index 316763b..7e780cf 100644 --- a/js/tasks.js +++ b/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 += `p` + } + 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 = "Lehetséges megoldások:"; } 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 = "Lehetséges megoldások:
" + this.correctAnswer.join(", VAGY
"); + if (this.correctAnswer !== null) { + this.ca_section.innerHTML = this.ca_prefix + "
" + this.correctAnswer.join(", VAGY
"); + } } 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 += ""; + for (let i = 0; i < N; i++) { + table += ""; + } + table += ""; + table += ""; + for (let i = 0; i < M; i++) { + table += ""; + for (let j = 0; j < N; j++) { + table += ""; + } + table += "" + table += ""; + } + table += "
" + this.input_variables[i] + "" + this.output_variable + "
" + ((i >> (N - j - 1)) & 1).toString() + "" + this.truth_table.charAt(i) + "
"; + + 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 = [ "" + correct_answer + "" ]; + } + + 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); + diff --git a/maintenance.html b/maintenance.html index f97b79a..5eb4d15 100644 --- a/maintenance.html +++ b/maintenance.html @@ -7,7 +7,7 @@
-

Az oldal karbantartás alatt áll!

+

Az oldal karbantartás alatt áll!

\ No newline at end of file diff --git a/result_analyzer.php b/result_analyzer.php index 46d02b6..3baf0f5 100644 --- a/result_analyzer.php +++ b/result_analyzer.php @@ -47,9 +47,9 @@ if (!$gameMgr->getGame($game_id)->isUserContributorOrOwner($user_data["nickname"
- - - + + +
diff --git a/style/quizmaster_area.css b/style/quizmaster_area.css index 478ed3a..4e70526 100644 --- a/style/quizmaster_area.css +++ b/style/quizmaster_area.css @@ -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; } \ No newline at end of file diff --git a/style/report.css b/style/report.css index b2ac9d0..9b0d3e7 100644 --- a/style/report.css +++ b/style/report.css @@ -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 { diff --git a/style/spreadquiz.css b/style/spreadquiz.css index 29b2320..e19293e 100644 --- a/style/spreadquiz.css +++ b/style/spreadquiz.css @@ -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;