created. Works OK after limited testing.
I've also renamed some strings to do with "Random Match", so that this
question type is now called "Random Short-Answer Match".
Later there will be a new 'Random Match' which randomly selects one of the
existing "Match" questions.
--- /dev/null
+<p align=center><b>Matching questions</b></p>
+
+<p>After an optional introduction, the respondent is presented with
+ several sub-questions and several jumbled answers. There is one
+ correct answer for each question.
+
+<p>The respondent must select an answer to match each sub-question.
+
+<p>Each sub-question is equally weighted to contibute towards the
+ grade for the total question.
+
-<p align=center><b>Random Matching questions</b></p>
+<p align=center><b>Random Short-Answer Matching questions</b></p>
<p>After an optional introduction, the respondent is presented with
several sub-questions and several jumbled answers. There is one
$string['defaultinfo'] = "The default category for questions.";
$string['deletequestioncheck'] = "Are you absolutely sure you want to delete '\$a'?";
$string['editcategories'] = "Edit categories";
+$string['editingmatch'] = "Editing a matching question";
+$string['editingmultichoice'] = "Editing a multiple choice question";
$string['editingquiz'] = "Editing quiz";
$string['editingquestion'] = "Editing a question";
+$string['editingrandomsamatch'] = "Editing a random short-answer matching question";
$string['editingshortanswer'] = "Editing a short answer question";
$string['editingtruefalse'] = "Editing a true/false question";
-$string['editingmultichoice'] = "Editing a multiple choice question";
-$string['editingrandommatch'] = "Editing a random matching question";
$string['false'] = "False";
$string['feedback'] = "Feedback";
$string['filloutoneanswer'] = "You must fill out at least one possible answer. Answers left blank will not be used.";
$string['fillouttwochoices'] = "You must fill out at least two choices. Choices left blank will not be used.";
+$string['filloutthreequestions'] = "You must fill out at least three questions. Questions left blank will not be used.";
$string['fileformat'] = "File format";
$string['fractionsaddwrong'] = "The positive grades you have chosen do not add up to 100%%
<BR>Instead, they add up to \$a%%
$string['importquestions'] = "Import questions from file";
$string['introduction'] = "Introduction";
$string['marks'] = "Marks";
+$string['match'] = "Matching";
+$string['matchanswer'] = "Matching answer";
$string['missingname'] = "Missing question name";
$string['missingquestiontext'] = "Missing question text";
$string['missingword'] = "Missing word format";
$string['noquestions'] = "No questions have been added yet";
$string['noreview'] = "You are not allowed to review this quiz";
$string['noreviewuntil'] = "You are not allowed to review this quiz until \$a";
+$string['notenoughsubquestions'] = "Not enough sub-questions have been defined!<br>
+Do you want to go back and fix this question?";
$string['publish'] = "Publish";
$string['qti'] = "IMS QTI format";
$string['question'] = "Question";
$string['quizopen'] = "Open the quiz";
$string['quiznotavailable'] = "The quiz will not be available until: \$a";
$string['random'] = "Random set";
-$string['randommatch'] = "Random Match";
-$string['randommatchcreate'] = "Create Random Match questions";
-$string['randommatchintro'] = "For each of the following questions, select the matching answer from the menu.";
-$string['randommatchnumber'] = "Number of questions to select";
+$string['randomsamatch'] = "Random Short-Answer Matching";
+$string['randomsamatchcreate'] = "Create Random Short-Answer Matching questions";
+$string['randomsamatchintro'] = "For each of the following questions, select the matching answer from the menu.";
+$string['randomsamatchnumber'] = "Number of questions to select";
$string['readytosend'] = "You are about to send your whole quiz to be graded. Are you sure you want to continue?";
$string['regrade'] = "Regrade all attempts";
$string['regradecomplete'] = "All attempts have been regraded";
execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_responses` ADD INDEX(question) ");
}
+ if ($oldversion < 2003033100) {
+ modify_database ("", "ALTER TABLE prefix_quiz_randommatch RENAME prefix_quiz_randomsamatch ");
+ modify_database ("", "CREATE TABLE `prefix_quiz_match` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `question` int(10) unsigned NOT NULL default '0',
+ `subquestions` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY `question` (`question`)
+ );");
+
+ modify_database ("", "CREATE TABLE `prefix_quiz_match_sub` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `question` int(10) unsigned NOT NULL default '0',
+ `questiontext` text NOT NULL,
+ `answertext` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY `question` (`question`)
+ );");
+ }
+
return true;
}
) TYPE=MyISAM COMMENT='Final quiz grade (may be best of several attempts)';
# --------------------------------------------------------
+#
+# Table structure for table `quiz_match`
+#
+
+CREATE TABLE `prefix_quiz_match` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `question` int(10) unsigned NOT NULL default '0',
+ `subquestions` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY `question` (`question`)
+) TYPE=MyISAM COMMENT='Defines fixed matching questions';
+# --------------------------------------------------------
+
+#
+# Table structure for table `quiz_match_sub`
+#
+
+CREATE TABLE `prefix_quiz_match_sub` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `question` int(10) unsigned NOT NULL default '0',
+ `questiontext` text NOT NULL,
+ `answertext` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY `question` (`question`)
+) TYPE=MyISAM COMMENT='Defines the subquestions that make up a matching question';
+# --------------------------------------------------------
+
#
# Table structure for table `quiz_multichoice`
#
) TYPE=MyISAM COMMENT='The grade for a question in a quiz';
# --------------------------------------------------------
-#
-# Table structure for table `quiz_randommatch`
-#
-
-CREATE TABLE `prefix_quiz_randommatch` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `question` int(10) unsigned NOT NULL default '0',
- `choose` INT UNSIGNED DEFAULT '4' NOT NULL,
- PRIMARY KEY ( `id` ),
- KEY `question` (`question`)
-) TYPE=MyISAM COMMENT='Info about a random matching question';
-
#
# Table structure for table `quiz_questions`
#
) TYPE=MyISAM COMMENT='The quiz questions themselves';
# --------------------------------------------------------
+#
+# Table structure for table `quiz_randomsamatch`
+#
+
+CREATE TABLE `prefix_quiz_randomsamatch` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `question` int(10) unsigned NOT NULL default '0',
+ `choose` INT UNSIGNED DEFAULT '4' NOT NULL,
+ PRIMARY KEY ( `id` ),
+ KEY `question` (`question`)
+) TYPE=MyISAM COMMENT='Info about a random short-answer matching question';
+# --------------------------------------------------------
+
#
# Table structure for table `quiz_responses`
#
table_column("quiz_questions", "", "defaultgrade", "INTEGER", "6", "UNSIGNED", "1", "NOT NULL", "image");
}
+ if ($oldversion < 2003033100) {
+ modify_database ("", "ALTER TABLE prefix_quiz_randommatch RENAME prefix_quiz_randomsamatch ");
+ modify_database ("", "CREATE TABLE `prefix_quiz_match_sub` (
+ id SERIAL PRIMARY KEY,
+ question integer NOT NULL default '0',
+ questiontext text NOT NULL default '',
+ answertext varchar(255) NOT NULL default ''
+ );");
+ modify_database ("", "CREATE INDEX question_prefix_quiz_match_sub_idx ON prefix_quiz_match_sub (question);");
+
+ modify_database ("", "CREATE TABLE prefix_quiz_multichoice (
+ id SERIAL PRIMARY KEY,
+ question integer NOT NULL default '0',
+ layout integer NOT NULL default '0',
+ answers varchar(255) NOT NULL default '',
+ single integer NOT NULL default '0'
+ );");
+ modify_database ("", "CREATE INDEX question_quiz_multichoice_idx ON prefix_quiz_multichoice (question);");
+ }
+
return true;
}
);
# --------------------------------------------------------
+#
+# Table structure for table quiz_match
+#
+
+CREATE TABLE prefix_quiz_match (
+ id SERIAL PRIMARY KEY,
+ question integer NOT NULL default '0',
+ subquestions varchar(255) NOT NULL default ''
+);
+# --------------------------------------------------------
+CREATE INDEX question_prefix_quiz_match_idx ON prefix_quiz_match (question);
+
+#
+# Table structure for table `quiz_match_sub`
+#
+
+CREATE TABLE `prefix_quiz_match_sub` (
+ id SERIAL PRIMARY KEY,
+ question integer NOT NULL default '0',
+ questiontext text NOT NULL default '',
+ answertext varchar(255) NOT NULL default ''
+);
+# --------------------------------------------------------
+CREATE INDEX question_prefix_quiz_match_sub_idx ON prefix_quiz_match_sub (question);
+
#
# Table structure for table quiz_multichoice
#
# --------------------------------------------------------
#
-# Table structure for table quiz_randommatch
+# Table structure for table quiz_randomsamatch
#
-CREATE TABLE prefix_quiz_randommatch (
+CREATE TABLE prefix_quiz_randomsamatch (
id SERIAL PRIMARY KEY,
question integer NOT NULL default '0',
choose integer NOT NULL default '4',
$rm->choose = 4; /// Always 4, for now.
$rm->category = $category->id;
- $rm->questiontext = get_string("randommatchintro", "quiz");
+ $rm->questiontext = get_string("randomsamatchintro", "quiz");
$rm->image = "";
- $rm->qtype = RANDOMMATCH;
+ $rm->qtype = RANDOMSAMATCH;
$rm->defaultgrade = $rm->choose;
echo "<hr>";
for ($i=1; $i<=$form->createrandom; $i++) {
- $rm->name = get_string("randommatch", "quiz") . " $i ($rm->choose $strquestions)";
+ $rm->name = get_string("randomsamatch", "quiz") . " $i ($rm->choose $strquestions)";
$db->debug = true;
if (!$rm->id = insert_record("quiz_questions", $rm)) {
choose_from_menu($QUIZ_FILE_FORMAT, "format", "missingword", "");
helpbutton("import", $strimportquestions, "quiz");
echo "</TR><TR><TD align=right>";
- print_string("randommatchcreate", "quiz");
+ print_string("randomsamatchcreate", "quiz");
echo ":</TD><TD>";
for ($i=0;$i<=100;$i++) {
$menu[$i] = $i;
ATTEMPTFIRST => get_string("attemptfirst", "quiz"),
ATTEMPTLAST => get_string("attemptlast", "quiz"));
-define("SHORTANSWER", "1");
-define("TRUEFALSE", "2");
-define("MULTICHOICE", "3");
-define("RANDOM", "4");
-define("MATCH", "5");
-define("RANDOMMATCH", "6");
-
-$QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"),
- TRUEFALSE => get_string("truefalse", "quiz"),
- SHORTANSWER => get_string("shortanswer", "quiz"),
- RANDOMMATCH => get_string("randommatch", "quiz") );
+define("SHORTANSWER", "1");
+define("TRUEFALSE", "2");
+define("MULTICHOICE", "3");
+define("RANDOM", "4");
+define("MATCH", "5");
+define("RANDOMSAMATCH", "6");
+
+$QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"),
+ TRUEFALSE => get_string("truefalse", "quiz"),
+ SHORTANSWER => get_string("shortanswer", "quiz"),
+ MATCH => get_string("match", "quiz"),
+ RANDOMSAMATCH => get_string("randomsamatch", "quiz") );
$QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"),
"webct" => get_string("webct", "quiz"),
define("QUIZ_PICTURE_DEFAULT_HEIGHT", "200");
+define("QUIZ_MAX_NUMBER_ANSWERS", "8");
+
/// FUNCTIONS ///////////////////////////////////////////////////////////////////
function quiz_add_instance($quiz) {
return false; // Not done yet
break;
- case RANDOMMATCH: // Could be any of many answers, return them all
+ case MATCH:
+ return get_records_sql("SELECT ms.*, g.grade
+ FROM {$CFG->prefix}quiz_match_sub ms,
+ {$CFG->prefix}quiz_question_grades g
+ WHERE ms.question = '$question->id'
+ AND ms.question = g.question");
+ break;
+
+ case RANDOMSAMATCH: // Could be any of many answers, return them all
return get_records_sql("SELECT a.*, g.grade
FROM {$CFG->prefix}quiz_questions q,
{$CFG->prefix}quiz_answers a,
case RANDOM:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rs.gif\">";
break;
- case RANDOMMATCH:
+ case MATCH:
+ echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/ma.gif\">";
+ break;
+ case RANDOMSAMATCH:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rm.gif\">";
break;
}
}
function quiz_print_question($number, $questionid, $grade, $courseid,
- $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL) {
+ $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL) {
/// Prints a quiz question, any format
if (!$question = get_record("quiz_questions", "id", $questionid)) {
echo "<P>Random questions not supported yet</P>";
break;
- case RANDOMMATCH:
- if (!$options = get_record("quiz_randommatch", "question", $question->id)) {
+ case MATCH:
+ if (!$options = get_record("quiz_match", "question", $question->id)) {
+ notify("Error: Missing question options!");
+ }
+ if (!$subquestions = get_records_list("quiz_match_sub", "id", $options->subquestions)) {
+ notify("Error: Missing subquestions for this question!");
+ }
+ echo text_to_html($question->questiontext);
+ if ($question->image) {
+ print_file_picture($question->image, $courseid, QUIZ_PICTURE_DEFAULT_HEIGHT);
+ }
+
+ foreach ($subquestions as $subquestion) {
+ $answers[$subquestion->id] = $subquestion->answertext;
+ }
+
+ $answers = draw_rand_array($answers, count($answers));
+
+ echo "<table border=0 cellpadding=10 align=right>";
+ foreach ($subquestions as $key => $subquestion) {
+ echo "<tr><td align=left valign=top>";
+ echo $subquestion->questiontext;
+ echo "</td>";
+ if (empty($response)) {
+ echo "<td align=right valign=top>";
+ choose_from_menu($answers, "q$question->id"."r$subquestion->id");
+ } else {
+ if (empty($response[$key])) {
+ echo "<td align=right valign=top>";
+ choose_from_menu($answers, "q$question->id"."r$subquestion->id");
+ } else {
+ if ($response[$key] == $correct[$key]) {
+ echo "<td align=right valign=top class=highlight>";
+ choose_from_menu($answers, "q$question->id"."r$subquestion->id", $response[$key]);
+ } else {
+ echo "<td align=right valign=top>";
+ choose_from_menu($answers, "q$question->id"."r$subquestion->id", $response[$key]);
+ }
+ }
+
+ if (!empty($feedback[$key])) {
+ quiz_print_comment($feedback[$key]);
+ }
+ }
+ echo "</td></tr>";
+ }
+ echo "</table>";
+
+ break;
+
+ case RANDOMSAMATCH:
+ if (!$options = get_record("quiz_randomsamatch", "question", $question->id)) {
notify("Error: Missing question options!");
}
echo text_to_html($question->questiontext);
}
break;
- case RANDOMMATCH:
+ case MATCH:
+ $matchcount = $totalcount = 0;
+
+ foreach ($question->answer as $questionanswer) { // Each answer is "questionid-answerid"
+ $totalcount++;
+ $qarr = explode('-', $questionanswer); // Extract question/answer.
+ if ($qarr[0] == $qarr[1]) {
+ $matchcount++;
+ $correct[$qarr[0]] = true;
+ $response[$qarr[0]] = $qarr[1];
+ $questiongrade = $answers[$qarr[0]]->grade;
+ } else {
+ $correct[$qarr[0]] = false;
+ $response[$qarr[0]] = $qarr[1];
+ }
+ }
+
+ $grade = $questiongrade * $matchcount / $totalcount;
+
+ break;
+
+ case RANDOMSAMATCH:
$bestanswer = array();
foreach ($answers as $answer) { // Loop through them all looking for correct answers
if (empty($bestanswer[$answer->question])) {
}
break;
- case RANDOMMATCH:
+ case MATCH:
+ delete_records("quiz_match", "question", $question->id);
+ delete_records("quiz_match_sub", "question", $question->id);
+
+ $subquestions = array();
+
+ // Insert all the new question+answer pairs
+ foreach ($question->subquestions as $key => $questiontext) {
+ $answertext = $question->subanswers[$key];
+ if (!empty($questiontext) and !empty($answertext)) {
+ unset($answer);
+ $subquestion->question = $question->id;
+ $subquestion->questiontext = $questiontext;
+ $subquestion->answertext = $answertext;
+ if (!$subquestion->id = insert_record("quiz_match_sub", $subquestion)) {
+ $result->error = "Could not insert quiz answer!";
+ return $result;
+ }
+ $subquestions[] = $subquestion->id;
+ }
+ }
+
+ if (count($subquestions) < 3) {
+ $result->notice = get_string("notenoughsubquestions", "quiz");
+ return $result;
+ }
+
+ unset($options);
+ $options->question = $question->id;
+ $options->subquestions = implode(",",$subquestions);
+ if (!insert_record("quiz_match", $options)) {
+ $result->error = "Could not insert quiz match options!";
+ return $result;
+ }
+
+ break;
+
+ case RANDOMSAMATCH:
$options->question = $question->id;
$options->choose = $question->choose;
- if ($existing = get_record("quiz_randommatch", "question", $options->question)) {
+ if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) {
$options->id = $existing->id;
- if (!update_record("quiz_randommatch", $options)) {
- $result->error = "Could not update quiz randommatch options!";
+ if (!update_record("quiz_randomsamatch", $options)) {
+ $result->error = "Could not update quiz randomsamatch options!";
return $result;
}
} else {
- if (!insert_record("quiz_randommatch", $options)) {
- $result->error = "Could not insert quiz randommatch options!";
+ if (!insert_record("quiz_randomsamatch", $options)) {
+ $result->error = "Could not insert quiz randomsamatch options!";
return $result;
}
}
if (!empty($options->answers)) {
$answersraw = get_records_list("quiz_answers", "id", $options->answers);
}
- for ($i=0; $i<6; $i++) {
+ for ($i=0; $i<QUIZ_MAX_NUMBER_ANSWERS; $i++) {
$answers[] = ""; // Make answer slots, default as blank
}
if (!empty($answersraw)) {
print_continue("edit.php");
break;
- case RANDOMMATCH:
+ case MATCH:
+ if (!empty($question->id)) {
+ $options = get_record("quiz_match", "question", $question->id);
+ if (!empty($options->subquestions)) {
+ $oldsubquestions = get_records_list("quiz_match_sub", "id", $options->subquestions);
+ }
+ }
+ if (empty($subquestions) and empty($subanswers)) {
+ for ($i=0; $i<QUIZ_MAX_NUMBER_ANSWERS; $i++) {
+ $subquestions[] = ""; // Make question slots, default as blank
+ $subanswers[] = ""; // Make answer slots, default as blank
+ }
+ if (!empty($oldsubquestions)) {
+ $i=0;
+ foreach ($oldsubquestions as $oldsubquestion) {
+ $subquestions[$i] = $oldsubquestion->questiontext; // insert questions into slots
+ $subanswers[$i] = $oldsubquestion->answertext; // insert answers into slots
+ $i++;
+ }
+ }
+ }
+ print_heading_with_help(get_string("editingmatch", "quiz"), "match", "quiz");
+ require("match.html");
+ break;
+
+ case RANDOMSAMATCH:
if (!empty($question->id)) {
- $options = get_record("quiz_randommatch", "question", $question->id);
+ $options = get_record("quiz_randomsamatch", "question", $question->id);
} else {
$options->choose = "";
}
$numberavailable = count_records("quiz_questions", "category", $category->id, "qtype", SHORTANSWER);
- print_heading_with_help(get_string("editingrandommatch", "quiz"), "randommatch", "quiz");
- require("randommatch.html");
+ print_heading_with_help(get_string("editingrandomsamatch", "quiz"), "randomsamatch", "quiz");
+ require("randomsamatch.html");
break;
default:
<TD>\r
<?PHP\r
if (empty($question->name)) {\r
- $question->name = get_string("randommatch", "quiz");\r
+ $question->name = get_string("randomsamatch", "quiz");\r
}\r
?>\r
<INPUT type="text" name="name" size=40 value="<? p($question->name) ?>">\r
echo "<BR \>";\r
}\r
if (empty($question->questiontext)) {\r
- $question->questiontext = get_string("randommatchintro", "quiz");\r
+ $question->questiontext = get_string("randomsamatchintro", "quiz");\r
}\r
print_textarea($usehtmleditor, 15, 60, 595, 300, "questiontext", $question->questiontext);\r
if ($usehtmleditor) {\r
</TD>\r
</TR>\r
<TR valign=top>\r
- <TD align=right><P><B><? print_string("randommatchnumber", "quiz") ?>:</B></P></TD>\r
+ <TD align=right><P><B><? print_string("randomsamatchnumber", "quiz") ?>:</B></P></TD>\r
<TD>\r
<?\r
if ($numberavailable < 2) {\r
} else if ($numberavailable < 6) {\r
$maxrandom = $numberavailable;\r
} else {\r
- $maxrandom = 6;\r
+ $maxrandom = QUIZ_MAX_NUMBER_ANSWERS;\r
}\r
\r
for ($i=2;$i<=$maxrandom;$i++) {\r
// This fragment is called by moodle_needs_upgrading() and /admin/index.php
////////////////////////////////////////////////////////////////////////////////
-$module->version = 2003032601; // The (date) version of this module
+$module->version = 2003033100; // The (date) version of this module
$module->cron = 0; // How often should cron check this module (seconds)?
?>