293 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			293 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace local_treestudyplan\local;
 | 
						|
 | 
						|
use Exception;
 | 
						|
 | 
						|
class gradegenerator {
 | 
						|
    private $table = [];
 | 
						|
 | 
						|
    private static $loremipsum = [
 | 
						|
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
 | 
						|
        "Etiam scelerisque ligula porttitor velit sollicitudin blandit.",
 | 
						|
        "Praesent laoreet nisi id lacus laoreet volutpat.",
 | 
						|
        "Donec rutrum tortor tempus lectus malesuada, ut pretium eros vehicula.",
 | 
						|
        "Phasellus vulputate tortor vehicula mauris porta ultricies.",
 | 
						|
        "Ut et lacus sit amet nisl facilisis elementum.",
 | 
						|
        "Vestibulum ut mauris ac justo tincidunt hendrerit.",
 | 
						|
        "Fusce congue nulla quis elit facilisis malesuada.",
 | 
						|
        "Aenean ornare eros placerat ipsum fringilla, sed imperdiet felis imperdiet.",
 | 
						|
        "Ut malesuada risus ultricies arcu dapibus, quis lobortis eros maximus.",
 | 
						|
        "Nam ullamcorper dolor ac est tristique, vel blandit tortor tristique.",
 | 
						|
        "Quisque quis lorem vitae leo lobortis posuere.",
 | 
						|
        "Nulla ac enim consectetur, rhoncus eros sed, malesuada enim.",
 | 
						|
        "Vestibulum lobortis lacus ac dolor pulvinar, gravida tincidunt dolor bibendum.",
 | 
						|
        "Maecenas fringilla urna eget sem bibendum, non lacinia lorem tempus.",
 | 
						|
        "Nullam quis metus sagittis, pharetra orci eget, ultrices nunc.",
 | 
						|
        "Morbi et ante at ipsum sodales porta.",
 | 
						|
        "Morbi vel neque in urna vestibulum vestibulum eu quis lectus.",
 | 
						|
        "Nam consequat dolor at enim vestibulum, ac gravida nisl consequat.",
 | 
						|
        "Phasellus ac libero vestibulum, vulputate tellus at, viverra dui.",
 | 
						|
        "Vivamus venenatis magna a nunc cursus, eget laoreet velit malesuada.",
 | 
						|
        "Cras fermentum velit vitae tellus sodales, vulputate semper purus porta.",
 | 
						|
        "Cras ultricies orci in est elementum, at laoreet erat tempus.",
 | 
						|
        "In non magna et lorem sagittis sollicitudin sit amet et est.",
 | 
						|
        "Etiam vitae augue ac turpis volutpat iaculis a vitae enim.",
 | 
						|
        "Integer pharetra quam ac tortor porta dignissim.",
 | 
						|
        "Pellentesque ullamcorper neque vitae ligula rhoncus accumsan.",
 | 
						|
        "Nullam in lectus sit amet est faucibus elementum vitae vel risus.",
 | 
						|
        "Aenean vehicula libero ut convallis blandit.",
 | 
						|
        "Aenean id mi facilisis, tristique enim vel, egestas lorem.",
 | 
						|
        "Mauris suscipit dui eget neque gravida, vel pellentesque leo gravida.",
 | 
						|
        "Quisque quis elit at velit maximus viverra ultricies in nisi.",
 | 
						|
        "Vivamus et orci nec magna hendrerit egestas sed quis arcu.",
 | 
						|
        "Suspendisse semper tortor sed justo iaculis volutpat.",
 | 
						|
        "Praesent interdum dolor nec ultricies imperdiet.",
 | 
						|
        "Vivamus tristique justo quis tellus commodo, at faucibus justo auctor.",
 | 
						|
        "Praesent pharetra tellus vel nunc mattis pharetra.",
 | 
						|
        "Cras a dui quis arcu rutrum ullamcorper sit amet et sem.",
 | 
						|
        "Aenean porttitor risus ac enim tempor posuere.",
 | 
						|
        "Mauris bibendum augue ac vehicula mattis.",
 | 
						|
        "Vestibulum nec justo vehicula, euismod enim sed, convallis magna.",
 | 
						|
        "Praesent ultrices elit vitae velit dignissim dignissim.",
 | 
						|
        "Curabitur vehicula velit vitae tortor consequat consectetur sit amet at leo.",
 | 
						|
        "Sed lobortis neque a magna facilisis aliquam.",
 | 
						|
        "Phasellus a libero in sem aliquam varius.",
 | 
						|
        "Mauris tincidunt ligula a risus efficitur euismod.",
 | 
						|
        "Sed pharetra diam ac neque tempus convallis.",
 | 
						|
        "Donec at ipsum elementum ex hendrerit laoreet mollis non elit.",
 | 
						|
        "Praesent eu arcu sollicitudin, fermentum tellus at, blandit dolor.",
 | 
						|
        "Curabitur in lectus consequat, bibendum ligula vitae, semper lacus.",
 | 
						|
        "Aenean eu risus non sem pretium dictum.",
 | 
						|
        "Praesent nec risus vestibulum quam venenatis tempor.",
 | 
						|
        "Nullam rhoncus ex a quam egestas, eu auctor enim lobortis.",
 | 
						|
        "Nam luctus ante id lacus scelerisque, quis blandit ante elementum.",
 | 
						|
    
 | 
						|
    ];
 | 
						|
 | 
						|
    private function generatedfeedback(){
 | 
						|
        if(file_exists("/usr/games/fortune")){
 | 
						|
            // get a fortune if it is available
 | 
						|
            return shell_exec("/usr/games/fortune -n 160 -e disclaimer literature science pratchett wisdom education");
 | 
						|
        } else {
 | 
						|
            // get a random loremipsum string
 | 
						|
            return self::$loremipsum[rand(0,count(self::$loremipsum)-1)];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function __construct(){
 | 
						|
        
 | 
						|
    }
 | 
						|
 | 
						|
    public function addstudent(string $student){
 | 
						|
        if(!array_key_exists($student,$this->table)){
 | 
						|
            $this->table[$student] = [ 
 | 
						|
                "intelligence" => rand(70,100),
 | 
						|
                "endurance" => rand(70,100),
 | 
						|
                "skills" => [],
 | 
						|
            ];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function addskill(string $student, string $skill){
 | 
						|
        $this->addstudent($student);
 | 
						|
        if(!array_key_exists($skill,$this->table[$student]["skills"])){
 | 
						|
            $int = $this->table[$student]["intelligence"];
 | 
						|
            $end = $this->table[$student]["endurance"];
 | 
						|
            $this->table[$student]["skills"][$skill] = [ 
 | 
						|
                "intelligence" => min(100, $int + rand(-30,30)),
 | 
						|
                "endurance" => min(100, $end + rand(-10,10)),
 | 
						|
            ];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Below is mostly just for reference in the json file
 | 
						|
    public function addUserNameInfo(string $student, $firstname,$lastname){
 | 
						|
        $this->addstudent($student);
 | 
						|
        $this->table[$student]["firstname"] = $firstname;
 | 
						|
        $this->table[$student]["lastname"] = $lastname;
 | 
						|
    }
 | 
						|
 | 
						|
    public function generateraw($student,$skill, $count )
 | 
						|
    {
 | 
						|
        $this->addskill($student,$skill);
 | 
						|
        $int = $this->table[$student]["skills"][$skill]["intelligence"];
 | 
						|
        $end = $this->table[$student]["skills"][$skill]["endurance"];
 | 
						|
 | 
						|
        $results = [];
 | 
						|
        $gaveup = false;
 | 
						|
        for($i=0; $i < $count; $i++){
 | 
						|
            $r = new \stdClass;
 | 
						|
            if($gaveup) {
 | 
						|
                $r->done = !$gaveup;
 | 
						|
            } else {
 | 
						|
                $r->done = (rand(0, $end) > 20); // Determine if the assignment was done
 | 
						|
            }
 | 
						|
            if($r->done){
 | 
						|
                $score = rand(0,$int) ;
 | 
						|
                $r->result = ($score > 20); // determine if the assignment was successful
 | 
						|
                if(!$r->result){
 | 
						|
                    $r->failed = !($score > 10); 
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                $r->result = false; // make sure a result property is always there
 | 
						|
                $r->failed = true;
 | 
						|
            }
 | 
						|
            // Aways generate a little feedback
 | 
						|
            $r->fb = $this->generatedfeedback();
 | 
						|
            $results[] = $r;
 | 
						|
 | 
						|
            if(!$gaveup && $i >= 3) {
 | 
						|
                // There is a slight chance the students with low endurance for this course will stop with this course's work entirely
 | 
						|
                $gaveup = (rand(0,$end) < 15);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $results;
 | 
						|
    }
 | 
						|
 | 
						|
    public function generate($student,$skill, array $gradeinfos ){
 | 
						|
        global $DB;
 | 
						|
        $table ="local_treestudyplan_gradecfg";
 | 
						|
 | 
						|
        $rlist = [];
 | 
						|
        $gen = $this->generateraw($student,$skill, count($gradeinfos));
 | 
						|
 | 
						|
        for($i=0; $i < count($gradeinfos); $i++){
 | 
						|
            $g = $gradeinfos[$i];
 | 
						|
            $gi = $g->getGradeitem();
 | 
						|
            $gr = $gen[$i];
 | 
						|
 | 
						|
            // First get the configured interpretation for this scale or grade
 | 
						|
            $scale = $gi->load_scale();
 | 
						|
            if( isset($scale)){
 | 
						|
                $gradecfg = $DB->get_record($table,["scale_id"=>$scale->id]);
 | 
						|
            }
 | 
						|
            else if($gi->grademin == 0)
 | 
						|
            {
 | 
						|
                $gradecfg = $DB->get_record($table,["grade_points"=>$gi->grademax]);
 | 
						|
            }
 | 
						|
            else 
 | 
						|
            {
 | 
						|
                $gradecfg = null;
 | 
						|
            }
 | 
						|
 | 
						|
            // next generate the grade
 | 
						|
            if($gradecfg)
 | 
						|
            {
 | 
						|
                if(!$gr->done){
 | 
						|
                    // INCOMPLETE
 | 
						|
                    // fair chance of teacher forgetting to set incomplete to "no evidence"
 | 
						|
                    $grade = 0;// $grade =  (rand(0,100) > 15)?max(1, $gradecfg->min_progress-1):"0";
 | 
						|
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>"" ];
 | 
						|
                }
 | 
						|
                else if(!$gr->result){
 | 
						|
                    $grade =  rand($gradecfg->min_progress, $gradecfg->min_completed -1 );
 | 
						|
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
                else{
 | 
						|
                    // COMPLETED
 | 
						|
                    $r = (object)["gi" => $g, "grade" => rand( $gradecfg->min_completed, $gi->grademax ), "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
 | 
						|
                $r->gradetext = $r->grade;
 | 
						|
                if( isset($scale)){
 | 
						|
                    $scaleitems = $scale->load_items();
 | 
						|
                    if($r->grade > 0){
 | 
						|
                        $r->gradetext = trim($scale->get_nearest_item($r->grade));
 | 
						|
                    } else {
 | 
						|
                        $r->gradetext = "-";
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                
 | 
						|
            }
 | 
						|
            else if($gi->gradepass > 0)
 | 
						|
            {
 | 
						|
                if(!$gr->done){
 | 
						|
                    // INCOMPLETe or FAILED
 | 
						|
                    $grade =  rand(0, $gi->gradepass/2);
 | 
						|
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>($grade > 0)?$gr->fb:"" ];
 | 
						|
                }
 | 
						|
                else if(!$gr->result){
 | 
						|
                    //PROGRESS
 | 
						|
                    $r = (object)["gi" => $g, "grade" => rand( round($gi->gradepass/2), $gi->gradepass -1 ), "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
                else{
 | 
						|
                    // COMPLETED
 | 
						|
                    $r = (object)["gi" => $g, "grade" => rand(  $gi->gradepass, $gi->grademax ), "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
               
 | 
						|
                $r->gradetext = $r->grade;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                // Blind assumptions if nothing is provided
 | 
						|
                // over 55% of range is completed
 | 
						|
                // under 35% is not done
 | 
						|
                $range = floatval($gi->grademax - $gi->grademin);
 | 
						|
 | 
						|
                if(!$gr->done){
 | 
						|
                    // INCOMPLETe or FAILED
 | 
						|
                    $grade =  rand(0, round($range * 0.35) - 1);
 | 
						|
                    $r = (object)["gi" => $g, "grade" =>  $gi->grademin+$grade, "fb" =>($grade > 0)?$gr->fb:"" ];
 | 
						|
                }
 | 
						|
                else if(!$gr->result){
 | 
						|
                    //PROGRESS
 | 
						|
                    $r = (object)["gi" => $g, "grade" => $gi->grademin+rand(round($range * 0.35),round($range * 0.55) - 1 ), "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
                else{
 | 
						|
                    // COMPLETED
 | 
						|
                    $r = (object)["gi" => $g, "grade" => $gi->grademin+rand(round($range * 0.55) , $range  ), "fb" =>$gr->fb ];
 | 
						|
                }
 | 
						|
 | 
						|
                $r->gradetext = $r->grade;
 | 
						|
            }
 | 
						|
 | 
						|
            $rlist[] = $r;
 | 
						|
          
 | 
						|
        }
 | 
						|
 | 
						|
        return $rlist;
 | 
						|
    }
 | 
						|
 | 
						|
    public function getstats($student){
 | 
						|
        return $this->table[$student];
 | 
						|
    }
 | 
						|
    public function serialize(): ?string{
 | 
						|
        return json_encode([
 | 
						|
            "table" => $this->table],JSON_PRETTY_PRINT);
 | 
						|
    }
 | 
						|
 | 
						|
    public function unserialize(string $data): void {
 | 
						|
        $o = json_decode($data,true);
 | 
						|
        $this->table = $o["table"];
 | 
						|
    }
 | 
						|
 | 
						|
    public function toFile(string $filename){
 | 
						|
        $filename = self::expand_tilde($filename);
 | 
						|
        file_put_contents($filename,$this->serialize());
 | 
						|
    }
 | 
						|
 | 
						|
    public function fromFile(string $filename){
 | 
						|
        $filename = self::expand_tilde($filename);
 | 
						|
        if(file_exists($filename)){
 | 
						|
            try{
 | 
						|
                $json = file_get_contents($filename);
 | 
						|
                $this->unserialize($json);
 | 
						|
            } catch(Exception $x){
 | 
						|
                cli_problem("ERROR loading from file");
 | 
						|
                throw $x; // Throw X up again to show the output
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private static function expand_tilde($path)
 | 
						|
    {
 | 
						|
        if (function_exists('posix_getuid') && strpos($path, '~') !== false) {
 | 
						|
            $info = posix_getpwuid(posix_getuid());
 | 
						|
            $path = str_replace('~', $info['dir'], $path);
 | 
						|
        }
 | 
						|
    
 | 
						|
        return $path;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
}
 |