CONTRIB-490 Added support for scripted generation of questions. Calculated type not yet supported (datasets too complicated ;)

This commit is contained in:
nicolasconnault
2008-06-12 04:48:20 +00:00
parent 2bf5901494
commit 933f6db4b9
7 changed files with 294 additions and 93 deletions
+117 -67
View File
@@ -40,13 +40,13 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if (!$options = get_records('question_calculated', 'question', $question->id)) {
notify("No options were found for calculated question
#{$question->id}! Proceeding with defaults.");
// $options = new Array();
// $options = new Array();
$options= new stdClass;
$options->tolerance = 0.01;
$options->tolerancetype = 1; // relative
$options->correctanswerlength = 2;
$options->correctanswerformat = 1; // decimals
}
}
// For historic reasons we also need these fields in the answer objects.
// This should eventually be removed and related code changed to use
@@ -62,13 +62,13 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$virtualqtype = $this->get_virtual_qtype();
$virtualqtype->get_numerical_units($question);
if( isset($question->export_process)&&$question->export_process){
$question->options->datasets = $this->get_datasets_for_export($question);
}
}
return true;
}
function get_datasets_for_export(&$question){
$datasetdefs = array();
if (!empty($question->id)) {
@@ -79,25 +79,25 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
WHERE d.question = '$question->id'
AND d.datasetdefinition = i.id
";
if ($records = get_records_sql($sql)) {
if ($records = get_records_sql($sql)) {
foreach ($records as $r) {
$def = $r ;
if ($def->category=='0'){
$def->status='private';
} else {
} else {
$def->status='shared';
}
}
$def->type ='calculated' ;
list($distribution, $min, $max,$dec) = explode(':', $def->options, 4);
$def->distribution=$distribution;
$def->minimum=$min;
$def->maximum=$max;
$def->decimals=$dec ;
$def->decimals=$dec ;
if ($def->itemcount > 0 ) {
// get the datasetitems
$def->items = array();
$sql1= (" SELECT itemnumber, definition, id, value
FROM {$CFG->prefix}question_dataset_items
FROM {$CFG->prefix}question_dataset_items
WHERE definition = '$def->id' order by itemnumber ASC ");
if ($items = get_records_sql($sql1)){
$n = 0;
@@ -110,18 +110,18 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$def->number_of_items=$n ;
}
}
$datasetdefs["1-$r->category-$r->name"] = $def;
$datasetdefs["1-$r->category-$r->name"] = $def;
}
}
}
return $datasetdefs ;
}
}
function save_question_options($question) {
//$options = $question->subtypeoptions;
// Get old answers:
global $CFG;
// Get old versions of the objects
if (!$oldanswers = get_records('question_answers', 'question', $question->id, 'id ASC')) {
$oldanswers = array();
@@ -141,13 +141,13 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
// Insert all the new answers
foreach ($question->answers as $key => $dataanswer) {
if ( trim($dataanswer) != '' ) {
if ( trim($dataanswer) != '' ) {
$answer = new stdClass;
$answer->question = $question->id;
$answer->answer = trim($dataanswer);
$answer->fraction = $question->fraction[$key];
$answer->feedback = trim($question->feedback[$key]);
if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it
$answer->id = $oldanswer->id;
if (! update_record("question_answers", $answer)) {
@@ -171,7 +171,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$options->tolerancetype = trim($question->tolerancetype[$key]);
$options->correctanswerlength = trim($question->correctanswerlength[$key]);
$options->correctanswerformat = trim($question->correctanswerformat[$key]);
// Save options
if (isset($options->id)) { // reusing existing record
if (! update_record('question_calculated', $options)) {
@@ -203,7 +203,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if( isset($question->import_process)&&$question->import_process){
$this->import_datasets($question);
}
}
// Report any problems.
if (!empty($result->notice)) {
return $result;
@@ -214,12 +214,12 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
function import_datasets($question){
$n = count($question->dataset);
foreach ($question->dataset as $dataset) {
// name, type, option,
// name, type, option,
$datasetdef = new stdClass();
$datasetdef->name = $dataset->name;
$datasetdef->type = 1 ;
$datasetdef->options = $dataset->distribution.':'.$dataset->min.':'.$dataset->max.':'.$dataset->length;
$datasetdef->itemcount=$dataset->itemcount;
$datasetdef->itemcount=$dataset->itemcount;
if ( $dataset->status =='private'){
$datasetdef->category = 0;
$todo='create' ;
@@ -238,18 +238,18 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
} else { // different so create a private one
$datasetdef->category = 0;
$todo='create' ;
}
}
}else { // no so create one
$datasetdef->category =$question->category ;
$todo='create' ;
}
}
}
}
if ( $todo=='create'){
if (!$datasetdef->id = insert_record(
'question_dataset_definitions', $datasetdef)) {
error("Unable to create dataset $defid");
}
}
}
}
// Create relation to the dataset:
$questiondataset = new stdClass;
$questiondataset->question = $question->id;
@@ -267,11 +267,11 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if (!insert_record('question_dataset_items', $datasetitem)) {
error("Unable to insert dataset item $item->itemnumber with $item->value for $datasetdef->name");
}
}
}
}
}
}
}
function create_runtime_question($question, $form) {
$question = parent::create_runtime_question($question, $form);
$question->options->answers = array();
@@ -360,7 +360,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$unit = $unit->unit;
} else {
$unit = '';
}
}
// We modify the question to look like a numerical question
$numericalquestion = fullclone($question);
foreach ($numericalquestion->options->answers as $key => $answer) {
@@ -373,7 +373,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
$numericalquestion->questiontext = parent::substitute_variables(
$numericalquestion->questiontext, $state->options->dataset);
//evaluate the equations i.e {=5+4)
//evaluate the equations i.e {=5+4)
$qtext = "";
$qtextremaining = $numericalquestion->questiontext ;
while (ereg('\{=([^[:space:]}]*)}', $qtextremaining, $regs1)) {
@@ -385,17 +385,17 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
} else {
if( $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])){
$str=$formulaerrors ;
}else {
eval('$str = '.$regs1[1].';');
}else {
eval('$str = '.$regs1[1].';');
}
}
$qtext = $qtext.$str ;
}
$qtext = $qtext.$str ;
}
$numericalquestion->questiontext = $qtext.$qtextremaining ; // end replace equations
$virtualqtype->print_question_formulation_and_controls($numericalquestion, $state, $cmoptions, $options);
}
function grade_responses(&$question, &$state, $cmoptions) {
// Forward the grading to the virtual qtype
// Forward the grading to the virtual qtype
// We modify the question to look like a numerical question
$numericalquestion = fullclone($question);
foreach ($numericalquestion->options->answers as $key => $answer) {
@@ -579,7 +579,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
global $CFG ;
// max datasets = 100 items
$max100 = 100 ;
if(isset($fromform->nextpageparam["forceregeneration"])) {
if(isset($fromform->nextpageparam["forceregeneration"])) {
$regenerate = $fromform->nextpageparam["forceregeneration"];
}else{
$regenerate = 0 ;
@@ -589,6 +589,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
//get the old datasets for this question
$datasetdefs = $this->get_dataset_definitions($question->id, array());
// Handle generator options...
$olddatasetdefs = fullclone($datasetdefs);
$datasetdefs = $this->update_dataset_options($datasetdefs, $fromform);
@@ -675,7 +676,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
//pp echo "<pre>"; print_r( $datasetitem );
if (!insert_record('question_dataset_items', $datasetitem)) {
error("Error: Unable to insert new dataset item");
}
}
}
}//for number added
}// datasetsdefs end
@@ -687,7 +688,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
update_record('question_dataset_definitions', $newdef);
}
}
}
}
if (isset($fromform->deletebutton)) {
if(isset($fromform->selectdelete)) $newmaxnumber = $maxnumber-$fromform->selectdelete ;
@@ -695,7 +696,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if ($newmaxnumber < 0 ) $newmaxnumber = 0 ;
foreach ($datasetdefs as $datasetdef) {
if ($datasetdef->itemcount == $maxnumber) {
$datasetdef->itemcount= $newmaxnumber ;
$datasetdef->itemcount= $newmaxnumber ;
if (!update_record('question_dataset_definitions',
$datasetdef)) {
error("Error: Unable to update itemcount");
@@ -705,6 +706,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
}
function generate_dataset_item($options) {
if (!ereg('^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$',
$options, $regs)) {
// Unknown options...
@@ -775,7 +777,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$virtualqtype->get_tolerance_interval($calculated);
if ($calculated->min === '') {
// This should mean that something is wrong
$stranswers .= " -$calculated->answer".'<br/><br/>';
$stranswers .= " -$calculated->answer".'<br/><br/>';
} else {
$stranswers .= $formula.' = '.$calculated->answer.'<br/>' ;
$stranswers .= $strmin. $delimiter.$calculated->min.'---';
@@ -796,7 +798,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
// Takes datasets from the parent implementation but
// filters options that are currently not accepted by calculated
// It also determines a default selection...
//$renameabledatasets not implemented anmywhere
//$renameabledatasets not implemented anmywhere
list($options, $selected) = parent::dataset_options($form, $name,'','qtype_calculated');
// list($options, $selected) = $this->dataset_optionsa($form, $name);
@@ -806,11 +808,11 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
}
if (!$selected) {
if ($mandatory){
if ($mandatory){
$selected = LITERAL . "-0-$name"; // Default
}else {
$selected = "0"; // Default
}
}
}
return array($options, $selected);
}
@@ -849,7 +851,7 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$unit = $unit->unit;
} else {
$unit = '';
}
}
foreach ($question->options->answers as $answer) {
if (((int) $answer->fraction) === 1) {
$answernumerical = qtype_calculated_calculate_answer(
@@ -871,24 +873,24 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if (empty($formula)) {
$str = '';
} else {
eval('$str = '.$formula.';');
eval('$str = '.$formula.';');
}
return $str;
}
/**
* This function retrieve the item count of the available category shareable
* wild cards that is added as a comment displayed when a wild card with
* wild cards that is added as a comment displayed when a wild card with
* the same name is displayed in datasetdefinitions_form.php
*/
*/
function get_dataset_definitions_category($form) {
global $CFG;
$datasetdefs = array();
$lnamemax = 30;
if (!empty($form->category)) {
if (!empty($form->category)) {
$sql = "SELECT i.*,d.*
FROM {$CFG->prefix}question_datasets d,
{$CFG->prefix}question_dataset_definitions i
{$CFG->prefix}question_dataset_definitions i
WHERE i.id = d.datasetdefinition
AND i.category = '$form->category'
;
@@ -898,18 +900,18 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
if ( !isset ($datasetdefs["$r->name"])) $datasetdefs["$r->name"] = $r->itemcount;
}
}
}
}
return $datasetdefs ;
}
}
/**
* This function build a table showing the available category shareable
* wild cards, their name, their definition (Min, Max, Decimal) , the item count
* and the name of the question where they are used.
* This table is intended to be add before the question text to help the user use
* This table is intended to be add before the question text to help the user use
* these wild cards
*/
*/
function print_dataset_definitions_category($form) {
global $CFG;
$datasetdefs = array();
@@ -921,20 +923,20 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
$questionusingstr = get_string('usedinquestion','qtype_calculated');
$itemscountstr = get_string('itemscount','qtype_datasetdependent');
$text ='';
if (!empty($form->category)) {
if (!empty($form->category)) {
list($category) = explode(',', $form->category);
$sql = "SELECT i.*,d.*
FROM {$CFG->prefix}question_datasets d,
{$CFG->prefix}question_dataset_definitions i
{$CFG->prefix}question_dataset_definitions i
WHERE i.id = d.datasetdefinition
AND i.category = $category;
AND i.category = $category;
" ;
if ($records = get_records_sql($sql)) {
foreach ($records as $r) {
$sql1 = "SELECT q.*
FROM {$CFG->prefix}question q
WHERE q.id = $r->question
";
FROM {$CFG->prefix}question q
WHERE q.id = $r->question
";
if ( !isset ($datasetdefs["$r->type-$r->category-$r->name"])){
$datasetdefs["$r->type-$r->category-$r->name"]= $r;
}
@@ -945,8 +947,8 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
}
}
if (!empty ($datasetdefs)){
$text ="<table width=\"100%\" border=\"1\"><tr><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\" >$namestr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$rangeofvaluestr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$itemscountstr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$questionusingstr</th></tr>";
$text ="<table width=\"100%\" border=\"1\"><tr><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\" >$namestr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$rangeofvaluestr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$itemscountstr</th><th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$questionusingstr</th></tr>";
foreach ($datasetdefs as $datasetdef){
list($distribution, $min, $max,$dec) = explode(':', $datasetdef->options, 4);
$text .="<tr><td valign=\"top\" align=\"center\"> $datasetdef->name </td><td align=\"center\" valign=\"top\"> $min <strong>-</strong> $max </td><td align=\"right\" valign=\"top\">$datasetdef->itemcount&nbsp;&nbsp;</td><td align=\"left\">";
@@ -958,16 +960,16 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
} else {
$qu->name = '';
}
$text .=" &nbsp;&nbsp; $qu->name <br/>";
}
$text .=" &nbsp;&nbsp; $qu->name <br/>";
}
$text .="</td></tr>";
}
$text .="</table>";
}else{
$text .=get_string('nosharedwildcard', 'qtype_calculated');
$text .=get_string('nosharedwildcard', 'qtype_calculated');
}
return $text ;
}
}
/// BACKUP FUNCTIONS ////////////////////////////
@@ -1070,6 +1072,54 @@ class question_calculated_qtype extends question_dataset_dependent_questiontype
return $status;
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$form->feedback = 1;
$form->multiplier = array(1, 1);
$form->shuffleanswers = 1;
$form->noanswers = 1;
$form->answers = array('{a} + {b}');
$form->fraction = array(1);
$form->tolerance = array(0.01);
$form->tolerancetype = array(1);
$form->correctanswerlength = array(2);
$form->correctanswerformat = array(1);
$form->questiontext = "What is {a} + {b}?";
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
$new_question = $this->save_question($question, $form, $course);
$dataset_form = new stdClass();
$dataset_form->number = array(1 => 2.4, 2 => 7.2, 3 => 6.7, 4 => 6.3);
$dataset_form->calcmin = array(1 => 1.0, 2 => 1.0);
$dataset_form->calcmax = array(1 => 10.0, 2 => 10.0);
$dataset_form->calclength = array(1 => 1, 2 => 1);
$dataset_form->calcdistribution = array(1 => 'uniform', 2 => 'uniform');
$dataset_form->definition = array(1 => "1-$new_question->category-b",
2 => "1-$new_question->category-a",
3 => "1-$new_question->category-b",
4 => "1-$new_question->category-a");
$dataset_form->itemid = array(1 => 2, 2 => 1, 3 => 0, 4 => 0);
$dataset_form->nextpageparam = array('forceregeneration' => false);
$dataset_form->addbutton = 1;
$dataset_form->selectadd = 1;
$dataset_form->selectdelete = 1;
$dataset_form->courseid = $courseid;
$dataset_form->cmid = 0;
$this->save_dataset_items($new_question, $dataset_form);
return $new_question;
}
}
//// END OF CLASS ////
+19
View File
@@ -133,6 +133,25 @@ class question_essay_qtype extends default_questiontype {
return question_backup_answers($bf, $preferences, $questionid, $level);
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$form->questiontext = "What is the purpose of life?";
$form->feedback = "feedback";
$form->generalfeedback = "General feedback";
$form->fraction = 0;
$form->penalty = 0;
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
// Restore method not needed.
}
//// END OF CLASS ////
+42 -15
View File
@@ -37,7 +37,7 @@ class embedded_cloze_qtype extends default_questiontype {
// We want an array with question ids as index and the positions as values
$sequence = array_flip(explode(',', $sequence));
array_walk($sequence, create_function('&$val', '$val++;'));
//si une question est manquante l,indice est nul
//si une question est manquante l,indice est nul
foreach($sequence as $seq){
$question->options->questions[$seq]= '';
}
@@ -79,7 +79,7 @@ class embedded_cloze_qtype extends default_questiontype {
if ($wrapped != ''){
// if we still have some old wrapped question ids, reuse the next of them
if (is_array($oldwrappedids) && $oldwrappedid = array_shift($oldwrappedids)) {
if( $oldqtype = get_field('question', 'qtype', 'id',$oldwrappedid->id)){
$wrapped->id = $oldwrappedid->id;
if($oldqtype != $wrapped->qtype ) {
@@ -115,7 +115,7 @@ class embedded_cloze_qtype extends default_questiontype {
}
// Delete redundant wrapped questions
if(is_array($oldwrappedids) && count($oldwrappedids)){
if(is_array($oldwrappedids) && count($oldwrappedids)){
foreach ($oldwrappedids as $id) {
delete_question($id) ;
}
@@ -282,9 +282,9 @@ class embedded_cloze_qtype extends default_questiontype {
$feedbackimg = '';
$feedback = '' ;
$correctanswer = '';
$strfeedbackwrapped = $strfeedback;
$strfeedbackwrapped = $strfeedback;
// if($wrapped->qtype == 'numerical' ||$wrapped->qtype == 'shortanswer'){
$testedstate = clone($state);
$testedstate = clone($state);
if ($correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $testedstate)) {
if ($options->readonly && $options->correct_responses) {
$delimiter = '';
@@ -292,7 +292,7 @@ class embedded_cloze_qtype extends default_questiontype {
foreach ($correctanswers as $ca) {
switch($wrapped->qtype){
case 'numerical':
case 'shortanswer':
case 'shortanswer':
$correctanswer .= $delimiter.$ca;
break ;
case 'multichoice':
@@ -300,7 +300,7 @@ class embedded_cloze_qtype extends default_questiontype {
$correctanswer .= $delimiter.$answers[$ca]->answer;
}
break ;
}
}
$delimiter = ', ';
}
}
@@ -364,7 +364,7 @@ class embedded_cloze_qtype extends default_questiontype {
}
}
if ($feedback !='' && $popup == ''){
$strfeedbackwrapped = get_string('correctanswer', 'qtype_multianswer');
$strfeedbackwrapped = get_string('correctanswer', 'qtype_multianswer');
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback));
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
" onmouseout=\"return nd();\" ";
@@ -379,18 +379,18 @@ class embedded_cloze_qtype extends default_questiontype {
if (strlen(trim($answer->answer)) > $size ){
$size = strlen(trim($answer->answer));
}
}
}
if (strlen(trim($response))> $size ){
$size = strlen(trim($response))+1;
}
$size = $size + rand(0,$size*0.15);
$size > 60 ? $size = 60 : $size = $size;
$size > 60 ? $size = 60 : $size = $size;
$styleinfo = "size=\"$size\"";
/**
* Uncomment the following lines if you want to limit for small sizes.
* Results may vary with browsers see MDL-3274
* Results may vary with browsers see MDL-3274
*/
/*
/*
if ($size < 2) {
$styleinfo = 'style="width: 1.1em;"';
}
@@ -404,7 +404,7 @@ class embedded_cloze_qtype extends default_questiontype {
$styleinfo = 'style="width: 2.8em;"';
}
*/
echo "<input $style $readonly $popup name=\"$inputname\"";
echo " type=\"text\" value=\"".s($response, true)."\" ".$styleinfo." /> ";
if (!empty($feedback) && !empty($USER->screenreader)) {
@@ -448,7 +448,7 @@ class embedded_cloze_qtype extends default_questiontype {
if(! isset($question->options->questions[$positionkey])){
echo $regs[0];
}else {
echo '<div class="error" >'.get_string('questionnotfound','qtype_multianswer',$positionkey).'</div>';
echo '<div class="error" >'.get_string('questionnotfound','qtype_multianswer',$positionkey).'</div>';
}
}
}
@@ -456,7 +456,7 @@ class embedded_cloze_qtype extends default_questiontype {
// Print the final piece of question text:
echo $qtextremaining;
$this->print_question_submit_buttons($question, $state, $cmoptions, $options);
echo '</div>';
echo '</div>';
}
function grade_responses(&$question, &$state, $cmoptions) {
@@ -702,6 +702,33 @@ class embedded_cloze_qtype extends default_questiontype {
return $answer_field;
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "This question consists of some text with an answer embedded right here {1:MULTICHOICE:Wrong answer#Feedback for this wrong answer~Another wrong answer#Feedback for the other wrong answer~=Correct answer#Feedback for correct answer~%50%Answer that gives half the credit#Feedback for half credit answer} and right after that you will have to deal with this short answer {1:SHORTANSWER:Wrong answer#Feedback for this wrong answer~=Correct answer#Feedback for correct answer~%50%Answer that gives half the credit#Feedback for half credit answer} and finally we have a floating point number {2:NUMERICAL:=23.8:0.1#Feedback for correct answer 23.8~%50%23.8:2#Feedback for half credit answer in the nearby region of the correct answer}.
Note that addresses like www.moodle.org and smileys :-) all work as normal:
a) How good is this? {:MULTICHOICE:=Yes#Correct~No#We have a different opinion}
b) What grade would you give it? {3:NUMERICAL:=3:2}
Good luck!
";
$form->feedback = "feedback";
$form->generalfeedback = "General feedback";
$form->fraction = 0;
$form->penalty = 0.1;
$form->versioning = 0;
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
}
//// END OF CLASS ////
@@ -669,6 +669,34 @@ class question_multichoice_qtype extends default_questiontype {
}
}
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "How old is the sun?";
$form->generalfeedback = "General feedback";
$form->penalty = 0.1;
$form->single = 1;
$form->shuffleanswers = 1;
$form->answernumbering = 'abc';
$form->noanswers = 3;
$form->answer = array('Ancient', '5 billion years old', '4.5 billion years old');
$form->fraction = array(0.3, 0.9, 1);
$form->feedback = array('True, but lacking in accuracy', 'Close, but no cigar!', 'Yep, that is it!');
$form->correctfeedback = 'Excellent!';
$form->incorrectfeedback = 'Nope!';
$form->partiallycorrectfeedback = 'Not bad';
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
}
// Register this question type with the question bank.
+39 -11
View File
@@ -107,7 +107,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
// Insert all the new answers
foreach ($question->answer as $key => $dataanswer) {
if (!isset( $question->deleteanswer[$key] ) && !( trim($dataanswer) == 0 && $question->fraction[$key]== 0 &&trim($question->feedback[$key])=='')) {
if (!isset( $question->deleteanswer[$key] ) && !( trim($dataanswer) == 0 && $question->fraction[$key]== 0 &&trim($question->feedback[$key])=='')) {
$answer = new stdClass;
$answer->question = $question->id;
if (trim($dataanswer) == '*') {
@@ -148,7 +148,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$result->notice = get_string('invalidnumerictolerance', 'quiz');
}
}
// Save options
if (isset($options->id)) { // reusing existing record
if (! update_record('question_numerical', $options)) {
@@ -181,7 +181,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
if (!empty($result->notice)) {
return $result;
}
return true;
}
@@ -329,11 +329,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$tolerance = abs($tolerance); // important - otherwise min and max are swapped
// $answer->tolerance 0 or something else
if ((float)$answer->tolerance == 0.0 && abs((float)$answer->answer) <= $tolerance ){
$tolerance = (float) ("1.0e-".ini_get('precision')) * abs((float)$answer->answer) ; //tiny fraction
$tolerance = (float) ("1.0e-".ini_get('precision')) * abs((float)$answer->answer) ; //tiny fraction
} else if ((float)$answer->tolerance != 0.0 && abs((float)$answer->tolerance) < abs((float)$answer->answer) && abs((float)$answer->answer) <= $tolerance){
$tolerance = (1+("1.0e-".ini_get('precision')) )* abs((float) $answer->tolerance) ;//tiny fraction
}
$tolerance = (1+("1.0e-".ini_get('precision')) )* abs((float) $answer->tolerance) ;//tiny fraction
}
$max = $answer->answer + $tolerance;
$min = $answer->answer - $tolerance;
break;
@@ -370,13 +370,13 @@ class question_numerical_qtype extends question_shortanswer_qtype {
$search = array(' ', ',');
$replace = array('', '.');
$rawresponse = str_replace($search, $replace, trim($rawresponse));
// Apply any unit that is present.
if (ereg('^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$',
$rawresponse, $responseparts)) {
if (!empty($responseparts[5])) {
if (isset($tmpunits[$responseparts[5]])) {
// Valid number with unit.
return (float)$responseparts[1] / $tmpunits[$responseparts[5]];
@@ -393,7 +393,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
// Invalid number. Must be wrong.
return false;
}
/// BACKUP FUNCTIONS ////////////////////////////
/**
@@ -483,6 +483,34 @@ class question_numerical_qtype extends question_shortanswer_qtype {
return $status;
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = default_questiontype::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "What is 674 * 36?";
$form->generalfeedback = "Thank you";
$form->penalty = 0.1;
$form->defaultgrade = 1;
$form->noanswers = 3;
$form->answer = array('24264', '24264', '1');
$form->tolerance = array(10, 100, 0);
$form->fraction = array(1, 0.5, 0);
$form->nounits = 2;
$form->unit = array(0 => null, 1 => null);
$form->multiplier = array(1, 0);
$form->feedback = array('Very good', 'Close, but not quite there', 'Well at least you tried....');
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
}
// INITIATION - Without this line the question type is not in use.
@@ -440,6 +440,34 @@ class question_shortanswer_qtype extends default_questiontype {
}
}
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "What is the purpose of life, the universe, and everything";
$form->generalfeedback = "Congratulations, you may have solved my biggest problem!";
$form->penalty = 0.1;
$form->usecase = false;
$form->defaultgrade = 1;
$form->noanswers = 3;
$form->answer = array('42', 'who cares?', 'Be happy');
$form->fraction = array(1, 0.6, 0.8);
$form->feedback = array('True, but what does that mean?', 'Well you do, dont you?', 'Yes, but thats not funny...');
$form->correctfeedback = 'Excellent!';
$form->incorrectfeedback = 'Nope!';
$form->partiallycorrectfeedback = 'Not bad';
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
}
//// END OF CLASS ////
+21
View File
@@ -345,6 +345,27 @@ class question_truefalse_qtype extends default_questiontype {
}
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
list($form, $question) = parent::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "This question is really stupid";
$form->penalty = 1;
$form->defaultgrade = 1;
$form->correctanswer = 0;
$form->feedbacktrue = array('Can you justify such a hasty judgment?');
$form->feedbackfalse = array('Wisdom has spoken!');
if ($courseid) {
$course = get_record('course', 'id', $courseid);
}
return $this->save_question($question, $form, $course);
}
}
//// END OF CLASS ////