280 lines
11 KiB
PHP
280 lines
11 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){
|
|
file_put_contents($filename,$this->serialize());
|
|
}
|
|
|
|
public function fromFile(string $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
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|