]> git.mjollnir.org Git - moodle.git/commitdiff
First implementation of completely random questions.
authormoodler <moodler>
Wed, 9 Apr 2003 06:32:51 +0000 (06:32 +0000)
committermoodler <moodler>
Wed, 9 Apr 2003 06:32:51 +0000 (06:32 +0000)
When you add a random question to a quiz, then a question
is chosen randomly from the same category.

Questions are not repeated in a particular quiz attempt.

This still needs more testing, but it's looking OK so far.

lang/en/help/quiz/random.html
lang/en/quiz.php
mod/quiz/attempt.php
mod/quiz/lib.php
mod/quiz/question.php
mod/quiz/random.html [new file with mode: 0644]
mod/quiz/report.php

index 6aaf9c38ca8ac646d4f454f4ecc2e5096ac277aa..189bfe2979fe2b5edbe361b6edc8183997e882cb 100644 (file)
@@ -1,3 +1,18 @@
-<P ALIGN=CENTER><B>Random question</B></P>
+<p align="center"><b>Random Question</b></p>
+
+<p>Random questions are a special question type.</p>
+
+<p>When you put a Random Question into a quiz, then a question 
+   will be chosen randomly from the whole category, on each attempt.</p>
+
+<p>The maximum grade for the question will always be when you have chosen
+   as the grade for the Random Question.</p>
+
+<p>If you make a quiz with, say, 10 random questions, then each student 
+   may get a completely different set of 10 questions each time they
+   attempt the quiz.</p>
+
+<p>Note that you can mix random and non-random questions if you want to 
+   ensure that particular questions are always included.</p>
 
 
index 14bb344e5e85397de45a801971119c8e10da6167..9947ea5d37f013d4a0b18d0b5f1b9e65c9a581e5 100644 (file)
@@ -42,13 +42,14 @@ $string['default'] = "Default";
 $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['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['editingrandom'] = "Editing a Random 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['false'] = "False";
 $string['feedback'] = "Feedback";
 $string['filloutoneanswer'] = "You must fill out at least one possible answer.  Answers left blank will not be used.";
@@ -94,7 +95,7 @@ $string['quizclose'] = "Close the quiz";
 $string['quizclosed'] = "This quiz closed on \$a";
 $string['quizopen'] = "Open the quiz";
 $string['quiznotavailable'] = "The quiz will not be available until: \$a";
-$string['random'] = "Random set";
+$string['random'] = "Random Question";
 $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.";
@@ -120,6 +121,7 @@ $string['showcorrectanswer'] = "In feedback, show correct answers?";
 $string['time'] = "Time";
 $string['timetaken'] = "Time taken";
 $string['timecompleted'] = "Completed";
+$string['toomanyrandom'] = "The number of random questions required is more than this category contains! (\$a)";
 $string['true'] = "True";
 $string['truefalse'] = "True/False";
 $string['type'] = "Type";
index 8e426222aa0613565f2268de1ef8fe837f4efe6b..921b4247e87ef733ae5cbab7401c56bffae3ca49 100644 (file)
                 if (isset($questions[$key])) {          // It's a real question number, not a coded one
                     $questions[$key]->answer[] = trim($value);
 
+                } else if (substr_count($key, "rq")) {  // Random Question information
+                    $check = explode("rq", $key);
+                    $key   = $check[0];                 // The random question id
+                    $real  = $check[1];                 // The real question id
+                    $questions[$key]->random = $real;  
+
                 } else if (substr_count($key, "a")) {   // Checkbox style multiple answers
                     $check = explode("a", $key);
                     $key   = $check[0];                 // The main question number
                     $value = $check[1];                 // The actual answer
                     $questions[$key]->answer[] = trim($value);  
 
-                } else if (substr_count($key, "r")) {   // Random-style questions
+                } else if (substr_count($key, "r")) {   // Random-style answers
                     $check = explode("r", $key);
                     $key   = $check[0];                 // The main question
                     $rand  = $check[1];                 // The random sub-question
         print_continue("view.php?id=$cm->id");
 
         if ($quiz->feedback) {
-            quiz_print_quiz_questions($quiz, $result);
+            quiz_print_quiz_questions($quiz, $result, $questions);
             print_continue("view.php?id=$cm->id");
         }
 
index 590a103206d2bc695c399f2c5ff327f417dbbeb6..d1e4554e222d29203166885edbf58a367c1ab78b 100644 (file)
@@ -24,6 +24,7 @@ $QUIZ_QUESTION_TYPE = array ( MULTICHOICE   => get_string("multichoice", "quiz")
                               TRUEFALSE     => get_string("truefalse", "quiz"),
                               SHORTANSWER   => get_string("shortanswer", "quiz"),
                               MATCH         => get_string("match", "quiz"),
+                              RANDOM        => get_string("random", "quiz"),
                               RANDOMSAMATCH => get_string("randomsamatch", "quiz") );
 
 $QUIZ_FILE_FORMAT = array ( "custom"   => get_string("custom", "quiz"),
@@ -237,6 +238,20 @@ function quiz_get_question_grades($quizid, $questionlist) {
                             AND question IN ($questionlist)");
 }
 
+function quiz_get_random_categories($questionlist) {
+/// Given an array of questions, this function looks for random
+/// questions among them and returns a list of categories with 
+/// an associated count of random questions for each.
+
+    global $CFG;
+
+    return get_records_sql_menu("SELECT category,count(*) 
+                            FROM {$CFG->prefix}quiz_questions 
+                            WHERE id IN ($questionlist) 
+                              AND qtype = '".RANDOM."' 
+                              GROUP BY category ");
+}
+
 function quiz_get_grade_records($quiz) {
 /// Gets all info required to display the table of quiz results
 /// for report.php
@@ -250,59 +265,41 @@ function quiz_get_grade_records($quiz) {
 }
 
 function quiz_get_answers($question) {
-// Given a question, returns the correct answers and grades
+// Given a question, returns the correct answers for a given question
     global $CFG;
 
     switch ($question->qtype) {
         case SHORTANSWER:       // Could be multiple answers
-            return get_records_sql("SELECT a.*, sa.usecase, g.grade
+            return get_records_sql("SELECT a.*, sa.usecase
                                       FROM {$CFG->prefix}quiz_shortanswer sa,  
-                                           {$CFG->prefix}quiz_answers a,  
-                                           {$CFG->prefix}quiz_question_grades g
+                                           {$CFG->prefix}quiz_answers a
                                      WHERE sa.question = '$question->id' 
-                                       AND sa.question = a.question
-                                       AND sa.question = g.question");
+                                       AND sa.question = a.question ");
             break;
 
         case TRUEFALSE:         // Should be always two answers
-            return get_records_sql("SELECT a.*, g.grade
-                                      FROM {$CFG->prefix}quiz_answers a, 
-                                           {$CFG->prefix}quiz_question_grades g
-                                     WHERE a.question = '$question->id' 
-                                       AND a.question = g.question");
+            return get_records("quiz_answers", "question", $question->id);
             break;
 
         case MULTICHOICE:       // Should be multiple answers
-            return get_records_sql("SELECT a.*, mc.single, g.grade
+            return get_records_sql("SELECT a.*, mc.single
                                       FROM {$CFG->prefix}quiz_multichoice mc, 
-                                           {$CFG->prefix}quiz_answers a, 
-                                           {$CFG->prefix}quiz_question_grades g
+                                           {$CFG->prefix}quiz_answers a
                                      WHERE mc.question = '$question->id' 
-                                       AND mc.question = a.question 
-                                       AND mc.question = g.question");
+                                       AND mc.question = a.question ");
             break;
 
-        case RANDOM:
-           return false;  // Not done yet
-           break;
-
         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");
+            return get_records("quiz_match_sub", "question", $question->id);
            break;
 
         case RANDOMSAMATCH:       // Could be any of many answers, return them all
-            return get_records_sql("SELECT a.*, g.grade
+            return get_records_sql("SELECT a.*
                                       FROM {$CFG->prefix}quiz_questions q,  
-                                           {$CFG->prefix}quiz_answers a,  
-                                           {$CFG->prefix}quiz_question_grades g
+                                           {$CFG->prefix}quiz_answers a
                                      WHERE q.category = '$question->category' 
                                        AND q.qtype = ".SHORTANSWER."
-                                       AND q.id = a.question
-                                       AND g.question = '$question->id'");
+                                       AND q.id = a.question ");
             break;
 
         default:
@@ -321,14 +318,25 @@ function quiz_get_attempt_responses($attempt, $quiz) {
                                         FROM {$CFG->prefix}quiz_responses r, 
                                              {$CFG->prefix}quiz_questions q
                                        WHERE r.attempt = '$attempt->id' 
-                                         AND q.id = r.question
-                                         AND q.id IN ($quiz->questions)")) {
+                                         AND q.id = r.question")) {
         notify("Could not find any responses for that attempt!");
         return false;
     }
 
+
+    foreach ($responses as $key => $response) {
+        if ($response->qtype == RANDOM) {
+            $responses[$key]->random = $response->answer;
+            $responses[$key]->answer = explode(",",$responses[$response->answer]->answer);
+            $responses[$response->answer]->delete = true;
+        } else {
+            $responses[$key]->answer = explode(",",$response->answer);
+        }
+    }
     foreach ($responses as $key => $response) {
-        $responses[$key]->answer = explode(",",$response->answer);
+        if (!empty($response->delete)) {
+            unset($responses[$key]);
+        }
     }
 
     return $responses;
@@ -352,12 +360,14 @@ function quiz_print_correctanswer($text) {
     echo "<P ALIGN=RIGHT><SPAN CLASS=highlight>$text</SPAN></P>";
 }
 
-function quiz_print_question_icon($question) {
+function quiz_print_question_icon($question, $editlink=true) {
 // Prints a question icon
 
     global $QUIZ_QUESTION_TYPE;
 
-    echo "<A HREF=\"question.php?id=$question->id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">";
+    if ($editlink) {
+        echo "<A HREF=\"question.php?id=$question->id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">";
+    }
     switch ($question->qtype) {
         case SHORTANSWER:
             echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/sa.gif\">";
@@ -378,16 +388,19 @@ function quiz_print_question_icon($question) {
             echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rm.gif\">";
             break;
     }
-    echo "</A>\n";
+    if ($editlink) {
+        echo "</A>\n";
+    }
 }
 
-function quiz_print_question($number, $questionid, $grade, $courseid, 
-                             $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL) {
-/// Prints a quiz question, any format
 
-    if (!$question = get_record("quiz_questions", "id", $questionid)) {
-        notify("Error: Question not found!");
-    }
+
+function quiz_print_question($number, $question, $grade, $courseid, 
+                             $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL,
+                             $realquestion=NULL) {
+
+/// Prints a quiz question, any format
+/// $question is provided as an object
 
     if (empty($actualgrade)) {
         $actualgrade = 0;
@@ -404,9 +417,18 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
         echo "<P ALIGN=CENTER><FONT SIZE=1>$grade $strmarks</FONT></P>";
     }
     print_spacer(1,100);
-    echo "</TD><TD VALIGN=TOP>";
+    echo "<p align=\"center\">";
+    quiz_print_question_icon($question, false);
+    echo "</p></TD><TD VALIGN=TOP>";
+
+    if (empty($realquestion)) { 
+        $realquestion->id = $question->id;
+    } else {    // Add a marker to connect this question to the actual random parent
+        echo "<input type=\"hidden\" name=\"q{$realquestion->id}rq$question->id\" value=\"x\">\n";
+    }
 
     switch ($question->qtype) {
+
        case SHORTANSWER: 
            if (!$options = get_record("quiz_shortanswer", "question", $question->id)) {
                notify("Error: Missing question options!");
@@ -420,7 +442,7 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
            } else {
                $value = "";
            }
-           echo "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$question->id SIZE=20 $value></P>";
+           echo "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$realquestion->id SIZE=20 $value></P>";
            if ($feedback) {
                quiz_print_comment("<P ALIGN=right>$feedback[0]</P>");
            }
@@ -474,9 +496,9 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
            }
            echo "<TABLE ALIGN=right cellpadding=5><TR><TD align=right>$stranswer:&nbsp;&nbsp;";
            echo "<TD $truecorrect>";
-           echo "<INPUT $truechecked TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$true->id\">$true->answer";
+           echo "<INPUT $truechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$true->id\">$true->answer";
            echo "</TD><TD $falsecorrect>";
-           echo "<INPUT $falsechecked TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$false->id\">$false->answer</P>";
+           echo "<INPUT $falsechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$false->id\">$false->answer</P>";
            echo "</TD></TR></TABLE><BR CLEAR=ALL>";
            if ($feedback) {
                quiz_print_comment("<P ALIGN=right>$feedback[$feedbackid]</P>");
@@ -511,9 +533,9 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
                }
                echo "<TR><TD valign=top>";
                if ($options->single) {
-                   echo "<INPUT $checked TYPE=RADIO NAME=q$question->id VALUE=\"$answer->id\">";
+                   echo "<INPUT $checked TYPE=RADIO NAME=q$realquestion->id VALUE=\"$answer->id\">";
                } else {
-                   echo "<INPUT $checked TYPE=CHECKBOX NAME=q$question->id"."a$answer->id VALUE=\"$answer->id\">";
+                   echo "<INPUT $checked TYPE=CHECKBOX NAME=q$realquestion->id"."a$answer->id VALUE=\"$answer->id\">";
                }
                echo "</TD>";
                if (empty($feedback) or empty($correct[$answer->id])) {
@@ -534,10 +556,6 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
            echo "</TABLE>";
            break;
 
-       case RANDOM:
-           echo "<P>Random questions not supported yet</P>";
-           break;
-
        case MATCH: 
            if (!$options = get_record("quiz_match", "question", $question->id)) {
                notify("Error: Missing question options!");
@@ -563,18 +581,18 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
                echo "</td>";
                if (empty($response)) {
                    echo "<td align=right valign=top>";
-                   choose_from_menu($answers, "q$question->id"."r$subquestion->id");
+                   choose_from_menu($answers, "q$realquestion->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");
+                       choose_from_menu($answers, "q$realquestion->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]);
+                           choose_from_menu($answers, "q$realquestion->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]);
+                           choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id", $response[$key]);
                        }
                    }
 
@@ -652,19 +670,19 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
                echo "</td>";
                echo "<td align=right valign=top>";
                if (empty($response)) {
-                   choose_from_menu($randomanswers, "q$question->id"."r$randomquestion->id");
+                   choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id");
                } else {
                    if (!empty($correct[$key])) {
                        if ($randomanswers[$responseanswer[$key]] == $correct[$key]) {
                            echo "<span=highlight>";
-                           choose_from_menu($randomanswers, "q$question->id"."r$randomquestion->id", $responseanswer[$key]);
+                           choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
                            echo "</span><br \>";
                        } else {
-                           choose_from_menu($randomanswers, "q$question->id"."r$randomquestion->id", $responseanswer[$key]);
+                           choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
                            quiz_print_correctanswer($correct[$key]);
                        }
                    } else {
-                       choose_from_menu($randomanswers, "q$question->id"."r$randomquestion->id", $responseanswer[$key]);
+                       choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
                    }
                    if (!empty($feedback[$key])) {
                        quiz_print_comment($feedback[$key]);
@@ -675,6 +693,9 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
            echo "</table>";
            break;
 
+       case RANDOM:
+           echo "<P>Random questions should not be printed this way!</P>";
+           break;
 
        default: 
            notify("Error: Unknown question type!");
@@ -683,15 +704,39 @@ function quiz_print_question($number, $questionid, $grade, $courseid,
     echo "</TD></TR></TABLE>";
 }
 
-function quiz_print_quiz_questions($quiz, $results=NULL) {
+
+
+function quiz_print_quiz_questions($quiz, $results=NULL, $questions=NULL) {
 // Prints a whole quiz on one page.
 
+    /// Get the questions
+
     if (empty($quiz->questions)) {
         notify("No questions have been defined!", "view.php?id=$cm->id");
         return false;
     }
 
-    $questions = explode(",", $quiz->questions);
+    if (!$questions) {
+        if (!$questions = get_records_list("quiz_questions", "id", $quiz->questions, "")) {
+            notify("Error when reading questions cound not be read from the database!");
+            return false;
+        }
+    }
+
+
+    /// Examine the set of questions for random questions, and retrieve them 
+
+    if (empty($results)) {
+        if ($randomcats = quiz_get_random_categories($quiz->questions)) {
+            foreach ($randomcats as $randomcat => $randomdraw) {
+                /// Get the appropriate amount of random questions from this category
+                if (!$catquestions[$randomcat] = quiz_choose_random_questions($randomcat, $randomdraw)) {
+                    notify(get_string("toomanyrandom", "quiz", $randomcat), "view.php?id=$cm->id");
+                    return false;
+                }
+            }
+        }
+    }
 
     if (!$grades = get_records_list("quiz_question_grades", "question", $quiz->questions, "", "question,grade")) {
         notify("No grades were found for these questions!");
@@ -703,31 +748,47 @@ function quiz_print_quiz_questions($quiz, $results=NULL) {
     echo "<FORM METHOD=POST ACTION=attempt.php onsubmit=\"return confirm('$strconfirmattempt');\">";
     echo "<INPUT TYPE=hidden NAME=q VALUE=\"$quiz->id\">";
 
-    foreach ($questions as $key => $questionid) {
+    $count = 0;
+    foreach ($questions as $question) {
+        $count++;
+
         $feedback       = NULL;
         $response       = NULL;
         $actualgrades   = NULL;
         $correct        = NULL;
-        if (!empty($results)) {
-            if (!empty($results->feedback[$questionid])) {
-                $feedback      = $results->feedback[$questionid];
+        $randomquestion = NULL;
+
+        if (empty($results)) {
+            if ($question->qtype == RANDOM ) {   // Set up random questions
+                $randomquestion = $question;
+                $question = array_pop($catquestions[$randomquestion->category]);
+                $grades[$question->id]->grade = $grades[$randomquestion->id]->grade;
             }
-            if (!empty($results->response[$questionid])) {
-                $response      = $results->response[$questionid];
+        } else {
+            if (!empty($results->feedback[$question->id])) {
+                $feedback      = $results->feedback[$question->id];
             }
-            if (!empty($results->grades[$questionid])) {
-                $actualgrades  = $results->grades[$questionid];
+            if (!empty($results->response[$question->id])) {
+                $response      = $results->response[$question->id];
+            }
+            if (!empty($results->grades[$question->id])) {
+                $actualgrades  = $results->grades[$question->id];
             }
             if ($quiz->correctanswers) {
-                if (!empty($results->correct[$questionid])) {
-                    $correct   = $results->correct[$questionid];
+                if (!empty($results->correct[$question->id])) {
+                    $correct   = $results->correct[$question->id];
                 }
             }
+            if (!empty($question->random)) {
+                $randomquestion = $question;
+                $question = get_record("quiz_questions", "id", $question->random);
+                $grades[$question->id]->grade = $grades[$randomquestion->id]->grade;
+            }
         }
 
         print_simple_box_start("CENTER", "90%");
-        quiz_print_question($key+1, $questionid, $grades[$questionid]->grade, $quiz->course, 
-                            $feedback, $response, $actualgrades, $correct);
+        quiz_print_question($count, $question, $grades[$question->id]->grade, $quiz->course, 
+                            $feedback, $response, $actualgrades, $correct, $randomquestion);
         print_simple_box_end();
         echo "<BR>";
     }
@@ -739,8 +800,12 @@ function quiz_print_quiz_questions($quiz, $results=NULL) {
 
     return true;
 }
+
+
  
 function quiz_get_default_category($courseid) {
+/// Returns the current category
+
     if ($categories = get_records("quiz_categories", "course", $courseid, "id")) {
         foreach ($categories as $category) {
             return $category;   // Return the first one (lowest id)
@@ -804,6 +869,31 @@ function quiz_print_category_form($course, $current) {
 }
 
 
+
+function quiz_choose_random_questions($category, $draws) {
+/// Given a question category and a number of draws, this function
+/// creates a random subset of that size - returned as an array of questions
+
+    if (!$pool = get_records_select_menu("quiz_questions", 
+                "category = '$category' AND qtype <> ".RANDOM, "", "id,qtype")) {
+        return false;
+    }
+
+    $countpool = count($pool);
+
+    if ($countpool == $draws) {
+        $chosen = $pool;
+    } else if ($countpool < $draws) {
+        return false;
+    } else {
+        $chosen = draw_rand_array($pool, $draws);
+    }
+
+    $chosenlist = implode(",", array_keys($chosen));
+    return get_records_list("quiz_questions", "id", $chosenlist);
+}
+
+
 function quiz_get_all_question_grades($questionlist, $quizid) {
 // Given a list of question IDs, finds grades or invents them to 
 // create an array of matching grades
@@ -1127,6 +1217,7 @@ function quiz_calculate_best_grade($quiz, $attempts) {
     }
 }
 
+
 function quiz_save_attempt($quiz, $questions, $result, $attemptnum) {
 /// Given a quiz, a list of attempted questions and a total grade 
 /// this function saves EVERYTHING so it can be reconstructed later
@@ -1163,6 +1254,18 @@ function quiz_save_attempt($quiz, $questions, $result, $attemptnum) {
         $response->attempt = $attempt->id;
         $response->question = $question->id;
         $response->grade = $result->grades[$question->id];
+
+        if ($question->random) {
+            // First save the response of the random question
+            // the answer is the id of the REAL response
+            $response->answer = $question->random;
+            if (!insert_record("quiz_responses", $response)) {
+                notify("Error while saving response");
+                return false;
+            }
+            $response->question = $question->random;
+        }
+
         if (!empty($question->answer)) {
             $response->answer = implode(",",$question->answer);
         } else {
@@ -1194,16 +1297,32 @@ function quiz_grade_attempt_results($quiz, $questions) {
     if (!$questions) {
         error("No questions!");
     }
-    
+
+    if (!$grades = get_records_menu("quiz_question_grades", "quiz", $quiz->id, "", "question,grade")) {
+        error("No grades defined for these quiz questions!");
+    }
+
     $result->sumgrades = 0;
 
     foreach ($questions as $question) {
+
+        if (!empty($question->random)) {      // This question has been randomly chosen
+            $randomquestion = $question;      // Save it for later
+            if (!$question = get_record("quiz_questions", "id", $question->random)) {
+                error("Could not find the real question behind this random question!");
+            }
+            $question->answer = $randomquestion->answer;
+            $question->grade = $grades[$randomquestion->id];
+        } else {
+            $question->grade = $grades[$question->id];
+        }
+        
         if (!$answers = quiz_get_answers($question)) {
             error("No answers defined for question id $question->id!");
         }
 
         $grade    = 0;   // default
-        $correct = array();
+        $correct  = array();
         $feedback = array();
         $response = array();
 
@@ -1227,7 +1346,7 @@ function quiz_grade_attempt_results($quiz, $questions) {
                     }
                     if ($question->answer == $answer->answer) {
                         $feedback[0] = $answer->feedback;
-                        $grade = (float)$answer->fraction * $answer->grade;
+                        $grade = (float)$answer->fraction * $question->grade;
                     }
                 }
                 break;
@@ -1245,7 +1364,7 @@ function quiz_grade_attempt_results($quiz, $questions) {
                         $correct[$answer->id]  = true;
                     }
                     if ($question->answer == $answer->id) {
-                        $grade = (float)$answer->fraction * $answer->grade;
+                        $grade = (float)$answer->fraction * $question->grade;
                         $response[$answer->id] = true;
                     }
                 }
@@ -1263,10 +1382,10 @@ function quiz_grade_attempt_results($quiz, $questions) {
                             if ($questionanswer == $answer->id) {
                                 $response[$answer->id] = true;
                                 if ($answer->single) {
-                                    $grade = (float)$answer->fraction * $answer->grade;
+                                    $grade = (float)$answer->fraction * $question->grade;
                                     continue;
                                 } else {
-                                    $grade += (float)$answer->fraction * $answer->grade;
+                                    $grade += (float)$answer->fraction * $question->grade;
                                 }
                             }
                         }
@@ -1277,21 +1396,24 @@ function quiz_grade_attempt_results($quiz, $questions) {
             case MATCH:
                 $matchcount = $totalcount = 0;
 
-                foreach ($question->answer as $questionanswer) {  // Each answer is "questionid-answerid"
+                foreach ($question->answer as $questionanswer) {  // Each answer is "subquestionid-answerid"
                     $totalcount++;
-                    $qarr = explode('-', $questionanswer);        // Extract question/answer.
-                    if ($qarr[0] == $qarr[1]) {
+                    $qarr = explode('-', $questionanswer);        // Extract subquestion/answer.
+                    $subquestionid = $qarr[0];
+                    $subanswerid = $qarr[1];
+                    if (($subquestionid == $subanswerid) or 
+                        ($answers[$subquestionid]->answertext == $answers[$subanswerid]->answertext)) {   
+                        // Either the ids match exactly, or the answertexts match exactly 
+                        // (in case two subquestions had the same answer)
                         $matchcount++;
-                        $correct[$qarr[0]] = true;
-                        $response[$qarr[0]] = $qarr[1];
-                        $questiongrade = $answers[$qarr[0]]->grade;
+                        $correct[$subquestionid] = true;
                     } else {
-                        $correct[$qarr[0]] = false;
-                        $response[$qarr[0]] = $qarr[1];
+                        $correct[$subquestionid] = false;
                     }
+                    $response[$subquestionid] = $subanswerid;
                 }
 
-                $grade = $questiongrade * $matchcount / $totalcount;
+                $grade = $question->grade * $matchcount / $totalcount;
 
                 break;
 
@@ -1317,13 +1439,19 @@ function quiz_grade_attempt_results($quiz, $questions) {
                         $answer = $answers[$ranswer];         
                         $feedback[$rquestion] = $answer->feedback;
                         if ($answer->question == $rquestion) {    // Check that this answer matches the question
-                            $grade += (float)$answer->fraction * $answer->grade * $answerfraction;
+                            $grade += (float)$answer->fraction * $question->grade * $answerfraction;
                         }
                     }
                 }
                 break;
 
         }
+
+        if (!empty($randomquestion)) {      // This question has been randomly chosen
+            $question = $randomquestion;    // Restore the question->id
+            unset($randomquestion);
+        }
+
         if ($grade < 0.0) {   // No negative grades
             $grade = 0.0;
         }
@@ -1545,6 +1673,9 @@ function quiz_save_question_options($question) {
             }
         break;
 
+        case RANDOM:
+        break;
+
         default:
             $result->error = "Unsupported question type ($question->qtype)!";
             return $result;
index f27dd9218de4bb405aedcdf0c848135ad3319ee5..6ab1261384ea069800ef6702b2a2b6e5a4bc5220 100644 (file)
             require("multichoice.html");
         break;
 
-        case RANDOM:
-            print_heading_with_help(get_string("editingrandom", "quiz"), "random", "quiz");
-            print_continue("edit.php");
-        break;
-
         case MATCH:
             if (!empty($question->id)) {
                 $options = get_record("quiz_match", "question", $question->id);
             require("randomsamatch.html");
         break;
 
+        case RANDOM:
+            print_heading_with_help(get_string("editingrandom", "quiz"), "random", "quiz");
+            require("random.html");
+        break;
+
         default:
             error("Invalid question type");
         break;
diff --git a/mod/quiz/random.html b/mod/quiz/random.html
new file mode 100644 (file)
index 0000000..f576701
--- /dev/null
@@ -0,0 +1,30 @@
+<center>\r
+<form name="theform" method="post" action="question.php">\r
+\r
+<table cellpadding=5>\r
+<tr valign=top>\r
+    <td align=right><P><B><? print_string("category", "quiz") ?>:</B></P></TD>\r
+    <td>\r
+       <? choose_from_menu($categories, "category", "$question->category", ""); ?>\r
+    </td>\r
+</tr>\r
+<tr valign=top>\r
+    <td align=right><P><B><? print_string("questionname", "quiz") ?>:</B></P></TD>\r
+    <td>\r
+        <? if (empty($question->name)) {\r
+               $question->name = get_string("random", "quiz");\r
+           } ?>\r
+        <input type="text" name="name" size=40 value="<? p($question->name) ?>">\r
+        <? if (isset($err["name"])) formerr($err["name"]); ?>\r
+    </td>\r
+</tr>\r
+</table>\r
+\r
+<input type="hidden" name=questiontext value="---">\r
+\r
+<input type="hidden" name=id value="<? p($question->id) ?>">\r
+<input type="hidden" name=qtype value="<? p($question->qtype) ?>">\r
+<input type="submit" value="<? print_string("savechanges") ?>">\r
+</form>\r
+</center>\r
+\r
index 24e38f1cc250157dc98f9ddaf1ebc76841e1f8a4..10a0ec8e263e38a9221051c87338d301cebffbfd 100644 (file)
 
         $quiz->feedback = true;
         $quiz->correctanswers = true;
-        quiz_print_quiz_questions($quiz, $result);
+        quiz_print_quiz_questions($quiz, $result, $questions);
 
         if (empty($review)) {
             print_continue("report.php?q=$quiz->id");