SpreadQuiz/class/Tasks/NumberConversionTask.php
2025-10-11 18:11:21 +02:00

115 lines
3.8 KiB
PHP

<?php
require_once "OpenEndedTask.php";
require_once "class/LogicUtils.php";
class NumberConversionTask extends OpenEndedTask
{
protected string $instruction; // instruction word
protected string $source; // source
// runtime variables -----
private int $src_base; // source number system
private string $src_rep; // source representation
private int $src_n_digits; // minimum number of digits in the source
private int $dst_base; // destination number system
private string $dst_rep; // destination representation
private int $dst_n_digits; // number of digits in the destination
// -------------------------
public function __construct(array &$a = null)
{
parent::__construct($a);
$this->setType("numberconversion");
// get instruction word
$this->instruction = strtolower(trim($a["instruction"] ?? "10u:2->2u:4"));
// expand it
$pattern = "/([0-9]+)([suc]):([0-9]+)->([0-9]+)([suc]):([0-9]+)/";
preg_match($pattern, $this->instruction, $matches);
// if the instruction was meaningful
if (count($matches) == 7) {
$this->src_base = (int)$matches[1];
$this->src_rep = $matches[2];
$this->src_n_digits = $matches[3];
$this->dst_base = (int)$matches[4];
$this->dst_rep = $matches[5];
$this->dst_n_digits = $matches[6];
} else { // no valid instruction word has been passed
$this->src_base = 10;
$this->src_rep = "u";
$this->src_n_digits = 2;
$this->dst_base = 2;
$this->dst_rep = "u";
$this->dst_n_digits = 4;
$this->instruction = $this->src_base . $this->src_rep . ":" . $this->src_n_digits . "->" . $this->dst_base . $this->dst_rep . ":" . $this->dst_n_digits;
}
$this->source = $a["source"] ?? "---";
$this->correct_answer = $a["correct_answer"] ?? "---";
}
public function toArray(string $mode = "all"): array
{
$a = parent::toArray($mode);
$a["instruction"] = $this->instruction;
$a["source"] = $this->source;
$a["correct_answer"] = $this->correct_answer;
return $a;
}
public function randomize(): void
{
parent::randomize();
// validate representation marks
$invalid = in_array($this->src_rep . $this->dst_rep, ["us", "su"]);
if ($invalid) { // fix invalid representation pairs
$this->dst_rep = "u";
$this->src_rep = "u";
}
// specify the range
$max = 1;
$min = 0;
switch ($this->dst_rep) {
case "u":
$max = pow($this->dst_base, $this->dst_n_digits) - 1;
$min = 0;
break;
case "s":
$max = pow($this->dst_base, $this->dst_n_digits) - 1;
$min = -$max;
break;
case "c":
$max = pow($this->dst_base, $this->dst_n_digits - 1) - 1;
$min = -($max + 1);
break;
}
// randomize a value
$m = random_int($min, $max);
// create the question and the answer
$this->correct_answer = LogicUtils::changeRepresentation($m, $this->dst_base, $this->dst_rep, $this->dst_n_digits);
$this->source = LogicUtils::changeRepresentation($m, $this->src_base, $this->src_rep, $this->src_n_digits);
}
public function staticCheck(): void
{
$mark = 0.0;
if ($this->hasFlag("acceptwithoutleadingzeros")) {
$mark = (ltrim($this->player_answer, " 0") === ltrim($this->correct_answer, "0")) ? 1.0 : 0.0;
} else {
$mark = (trim($this->player_answer) === trim($this->correct_answer)) ? 1.0 : 0.0;
}
$this->setMark($mark);
}
}