133 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			4.2 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";
 | 
						|
        }
 | 
						|
 | 
						|
        // switch between source and destination constrains
 | 
						|
        if ($this->hasFlag("sourceconstrain")) {
 | 
						|
            $base = $this->src_base;
 | 
						|
            $n_digits = $this->src_n_digits;
 | 
						|
            $rep = $this->src_rep;
 | 
						|
        } else {
 | 
						|
            $base = $this->dst_base;
 | 
						|
            $n_digits = $this->dst_n_digits;
 | 
						|
            $rep = $this->dst_rep;
 | 
						|
        }
 | 
						|
 | 
						|
        // specify the range
 | 
						|
        $max = 1;
 | 
						|
        $min = 0;
 | 
						|
        switch ($rep) {
 | 
						|
            case "u":
 | 
						|
                $max = pow($base, $n_digits) - 1;
 | 
						|
                $min = 0;
 | 
						|
                break;
 | 
						|
            case "s":
 | 
						|
                $max = pow($base, $n_digits) - 1;
 | 
						|
                $min = -$max;
 | 
						|
                break;
 | 
						|
            case "c":
 | 
						|
                $max = pow($base, $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;
 | 
						|
        $pa = strtolower($this->player_answer);
 | 
						|
        $ca = $this->correct_answer;
 | 
						|
        if (($ca[0] === "-") && ($pa[0] !== "-")) {
 | 
						|
            goto setmark;
 | 
						|
        }
 | 
						|
        if ($this->hasFlag("acceptwithoutleadingzeros")) {
 | 
						|
            $mark = (ltrim($pa, "+- 0") === ltrim($ca, "-0")) ? $this->getMaxMark() : 0.0;
 | 
						|
        } else {
 | 
						|
            $mark = (trim($pa) === trim($ca)) ? $this->getMaxMark() : 0.0;
 | 
						|
        }
 | 
						|
 | 
						|
        setmark:
 | 
						|
        $this->setMark($mark);
 | 
						|
    }
 | 
						|
} |