From 361f649d7ad7ddf2d0af1932505a6dd316559fb6 Mon Sep 17 00:00:00 2001 From: moodler Date: Thu, 10 Jul 2003 13:25:07 +0000 Subject: [PATCH] New question type: Numerical questions. Mostly coded by Henrik Kaipe - I changed a few things on the way in. --- lang/en/help/index.html | 2 + lang/en/help/quiz/numerical.html | 10 +++ lang/en/quiz.php | 5 ++ mod/quiz/db/mysql.php | 12 +++ mod/quiz/db/mysql.sql | 14 +++ mod/quiz/lib.php | 141 ++++++++++++++++++++++++++----- mod/quiz/numerical.html | 114 +++++++++++++++++++++++++ mod/quiz/pix/de.gif | Bin 128 -> 117 bytes mod/quiz/pix/nu.gif | Bin 0 -> 84 bytes mod/quiz/question.php | 27 +++++- mod/quiz/version.php | 2 +- 11 files changed, 303 insertions(+), 24 deletions(-) create mode 100644 lang/en/help/quiz/numerical.html create mode 100644 mod/quiz/numerical.html create mode 100755 mod/quiz/pix/nu.gif diff --git a/lang/en/help/index.html b/lang/en/help/index.html index cba75434a2..7774c909bb 100755 --- a/lang/en/help/index.html +++ b/lang/en/help/index.html @@ -65,11 +65,13 @@
  • Categories
  • Correct answers
  • Creating multiple quizzes +
  • Descriptions
  • Grading method
  • Importing questions
  • Matching questions
  • Maximum grade
  • Multiple choice questions +
  • Numerical questions
  • Opening and closing the quiz
  • Question Feedback
  • Question types- creating a new question diff --git a/lang/en/help/quiz/numerical.html b/lang/en/help/quiz/numerical.html new file mode 100644 index 0000000000..92d261996d --- /dev/null +++ b/lang/en/help/quiz/numerical.html @@ -0,0 +1,10 @@ +

    Numerical questions

    + +

    In response to a question (that may include a image) the respondent + must type a number.

    + +

    The required answer may have an accepted error. This allows a range of + answers to be set.

    + +

    For example, if the answer is 30 with an error of 5, then any number + between 25 and 35 will be accepted as correct.

    diff --git a/lang/en/quiz.php b/lang/en/quiz.php index 5b017f882e..d51d7f45d1 100644 --- a/lang/en/quiz.php +++ b/lang/en/quiz.php @@ -5,6 +5,7 @@ $string['modulename'] = "Quiz"; $string['modulenameplural'] = "Quizzes"; #------------------------------------------------------------ +$string['acceptederror'] = "Accepted error"; $string['addquestions'] = "Add questions"; $string['addingquestions'] = "This side of the page is where you manage your database of questions. Questions are stored in categories to help you keep them organised, and can be used by any quiz in your course or even other courses if you choose to 'publish' them.

    After you select or create a question category you will be able to create or edit questions. You can select any of these questions to add to your quiz over on the other side of this page."; $string['addquestionstoquiz'] = "Add questions to current quiz"; @@ -16,6 +17,7 @@ $string['answer'] = "Answer"; $string['answerhowmany'] = "One or multiple answers?"; $string['answersingleyes'] = "One answer only"; $string['answersingleno'] = "Multiple answers allowed"; +$string['answerswithacceptederrormarginmustbenumeric'] = "Answers with accepted error must be numeric"; $string['attempt'] = "Attempt \$a"; $string['attemptfirst'] = "First attempt"; $string['attemptlast'] = "Last attempt"; @@ -51,6 +53,7 @@ $string['editcategories'] = "Edit categories"; $string['editingdescription'] = "Editing a Description"; $string['editingmatch'] = "Editing a Matching Question"; $string['editingmultichoice'] = "Editing a Multiple Choice question"; +$string['editingnumerical'] = "Editing a numerical question"; $string['editingquiz'] = "Editing quiz"; $string['editingquestion'] = "Editing a question"; $string['editingrandom'] = "Editing a Random Question"; @@ -80,6 +83,7 @@ $string['introduction'] = "Introduction"; $string['marks'] = "Marks"; $string['match'] = "Matching"; $string['matchanswer'] = "Matching answer"; +$string['missingcorrectanswer'] = "Correct answer must be specified"; $string['missingname'] = "Missing question name"; $string['missingquestiontext'] = "Missing question text"; $string['missingword'] = "Missing word format"; @@ -92,6 +96,7 @@ $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!
    Do you want to go back and fix this question?"; +$string['numerical'] = "Numerical"; $string['publish'] = "Publish"; $string['qti'] = "IMS QTI format"; $string['question'] = "Question"; diff --git a/mod/quiz/db/mysql.php b/mod/quiz/db/mysql.php index 37eeaa6d19..76ca101861 100644 --- a/mod/quiz/db/mysql.php +++ b/mod/quiz/db/mysql.php @@ -92,6 +92,18 @@ function quiz_upgrade($oldversion) { table_column("quiz", "", "shuffleanswers", "INTEGER", "4", "UNSIGNED", "0", "NOT NULL", "shufflequestions"); } + if ($oldversion < 2003071000) { + + modify_database ("", " CREATE TABLE `prefix_quiz_numerical` ( + `id` int(10) unsigned NOT NULL auto_increment, + `answer` int(10) unsigned NOT NULL default '0', + `min` varchar(255) NOT NULL default '', + `max` varchar(255) NOT NULL default '', + PRIMARY KEY (`id`), + KEY `answer` (`answer`) + ) TYPE=MyISAM COMMENT='Options for numerical questions'; "); + } + return true; } diff --git a/mod/quiz/db/mysql.sql b/mod/quiz/db/mysql.sql index 1ccd6ef9b6..37d068795c 100644 --- a/mod/quiz/db/mysql.sql +++ b/mod/quiz/db/mysql.sql @@ -216,6 +216,20 @@ CREATE TABLE `prefix_quiz_shortanswer` ( ) TYPE=MyISAM COMMENT='Options for short answer questions'; # -------------------------------------------------------- +# +# Table structure for table `quiz_numerical` +# + +CREATE TABLE `prefix_quiz_numerical` ( + `id` int(10) unsigned NOT NULL auto_increment, + `answer` int(10) unsigned NOT NULL default '0', + `min` varchar(255) NOT NULL default '', + `max` varchar(255) NOT NULL default '', + PRIMARY KEY (`id`), + KEY `answer` (`answer`) +) TYPE=MyISAM COMMENT='Options for numerical questions'; +# -------------------------------------------------------- + # # Table structure for table `quiz_truefalse` # diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index e46466582a..1a0682a846 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -20,14 +20,17 @@ define("RANDOM", "4"); define("MATCH", "5"); define("RANDOMSAMATCH", "6"); define("DESCRIPTION", "7"); +define("NUMERICAL", "8"); $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"), TRUEFALSE => get_string("truefalse", "quiz"), SHORTANSWER => get_string("shortanswer", "quiz"), + NUMERICAL => get_string("numerical", "quiz"), MATCH => get_string("match", "quiz"), + DESCRIPTION => get_string("description", "quiz"), RANDOM => get_string("random", "quiz"), - RANDOMSAMATCH => get_string("randomsamatch", "quiz"), - DESCRIPTION => get_string("description", "quiz") ); + RANDOMSAMATCH => get_string("randomsamatch", "quiz") + ); $QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"), "missingword" => get_string("missingword", "quiz"), @@ -293,6 +296,15 @@ function quiz_get_answers($question) { AND q.id = a.question "); break; + case NUMERICAL: // Logical support for multiple answers + return get_records_sql("SELECT a.*, n.min, n.max + FROM {$CFG->prefix}quiz_numerical n, + {$CFG->prefix}quiz_answers a + WHERE a.question = '$question->id' + AND n.answer = a.id "); + break; + + default: return false; } @@ -342,13 +354,13 @@ function quiz_get_attempt_responses($attempt, $quiz) { function quiz_print_comment($text) { global $THEME; - echo "".text_to_html($text, true, false).""; + echo "".text_to_html($text, true, false).""; } function quiz_print_correctanswer($text) { global $THEME; - echo "

    $text

    "; + echo "

    $text

    "; } function quiz_print_question_icon($question, $editlink=true) { @@ -357,33 +369,36 @@ function quiz_print_question_icon($question, $editlink=true) { global $QUIZ_QUESTION_TYPE; if ($editlink) { - echo "id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">"; + echo "id\" title=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">"; } switch ($question->qtype) { case SHORTANSWER: - echo ""; + echo ''; break; case TRUEFALSE: - echo ""; + echo ''; break; case MULTICHOICE: - echo ""; + echo ''; break; case RANDOM: - echo ""; + echo ''; break; case MATCH: - echo ""; + echo ''; break; case RANDOMSAMATCH: - echo ""; + echo ''; break; case DESCRIPTION: - echo ""; + echo ''; + break; + case NUMERICAL: + echo ''; break; } if ($editlink) { - echo "\n"; + echo "\n"; } } @@ -413,15 +428,15 @@ function quiz_print_question($number, $question, $grade, $courseid, $stranswer = get_string("answer", "quiz"); $strmarks = get_string("marks", "quiz"); - echo "
    "; - echo "

    $number

    "; + echo "
    "; + echo "

    $number

    "; if ($feedback or $response) { - echo "

    $strmarks: $actualgrade/$grade

    "; + echo "

    $strmarks: $actualgrade/$grade

    "; } else { - echo "

    $grade $strmarks

    "; + echo "

    $grade $strmarks

    "; } print_spacer(1,100); - echo "
    "; + echo ""; if (empty($realquestion)) { $realquestion->id = $question->id; @@ -432,9 +447,7 @@ function quiz_print_question($number, $question, $grade, $courseid, switch ($question->qtype) { case SHORTANSWER: - if (!$options = get_record("quiz_shortanswer", "question", $question->id)) { - notify("Error: Missing question options!"); - } + case NUMERICAL: echo text_to_html($question->questiontext); if ($question->image) { print_file_picture($question->image, $courseid); @@ -1423,7 +1436,7 @@ function quiz_grade_attempt_results($quiz, $questions) { } $response[0] = $question->answer; $bestshortanswer = 0; - foreach($answers as $answer) { // There might be multiple right answers + foreach ($answers as $answer) { // There might be multiple right answers if ($answer->fraction > $bestshortanswer) { $correct[$answer->id] = $answer->answer; $bestshortanswer = $answer->fraction; @@ -1439,6 +1452,26 @@ function quiz_grade_attempt_results($quiz, $questions) { } break; + case NUMERICAL: + if ($question->answer) { + $question->answer = trim(stripslashes($question->answer[0])); + } else { + $question->answer = ""; + } + $response[0] = $question->answer; + $bestshortanswer = 0; + foreach ($answers as $answer) { // There might be multiple right answers + if ($answer->fraction > $bestshortanswer) { + $correct[$answer->id] = $answer->answer; + $bestshortanswer = $answer->fraction; + } + if ( ((float)$question->answer >= (float)$answer->min) and + ((float)$question->answer <= (float)$answer->max) ) { + $feedback[0] = $answer->feedback; + $grade = (float)$answer->fraction * $question->grade; + } + } + break; case TRUEFALSE: if ($question->answer) { @@ -1641,6 +1674,70 @@ function quiz_save_question_options($question) { } break; + case NUMERICAL: // Note similarities to SHORTANSWER + + if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { + $oldanswers = array(); + } + + $answers = array(); + $maxfraction = -1; + + // Insert all the new answers + foreach ($question->answer as $key => $dataanswer) { + if ($dataanswer != "") { + if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it + $answer = $oldanswer; + $answer->answer = $dataanswer; + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $question->feedback[$key]; + if (!update_record("quiz_answers", $answer)) { + $result->error = "Could not update quiz answer! (id=$answer->id)"; + return $result; + } + } else { // This is a completely new answer + unset($answer); + $answer->answer = $dataanswer; + $answer->question = $question->id; + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $question->feedback[$key]; + if (!$answer->id = insert_record("quiz_answers", $answer)) { + $result->error = "Could not insert quiz answer!"; + return $result; + } + } + $answers[] = $answer->id; + if ($question->fraction[$key] > $maxfraction) { + $maxfraction = $question->fraction[$key]; + } + + if ($options = get_record("quiz_numerical", "answer", $answer->id)) { + $options->min= $question->min[$key]; + $options->max= $question->max[$key]; + if (!update_record("quiz_numerical", $options)) { + $result->error = "Could not update quiz numerical options! (id=$options->id)"; + return $result; + } + } else { // completely new answer + unset($options); + $options->min= $question->min[$key]; + $options->max= $question->max[$key]; + $options->answer= $answer->id; + if (!insert_record("quiz_numerical", $options)) { + $result->error = "Could not insert quiz numerical options!"; + return $result; + } + } + } + } + + /// Perform sanity checks on fractional grades + if ($maxfraction != 1) { + $maxfraction = $maxfraction * 100; + $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); + return $result; + } + break; case TRUEFALSE: diff --git a/mod/quiz/numerical.html b/mod/quiz/numerical.html new file mode 100644 index 0000000000..5499a2ab0d --- /dev/null +++ b/mod/quiz/numerical.html @@ -0,0 +1,114 @@ +
    action="question.php"> +
    + + + + + + + + + + + + + + + + + + + + + min) && is_numeric($answers[0]->answer)) { + $acceptederror = (float)($answers[0]->answer) + - (float)($answers[0]->min); + } else { + $acceptederror = ""; + } + ?> + + + + + + +

    :

    + category", ""); ?> +

    :

    + + +

    :

    + "; + } + print_textarea($usehtmleditor, 15, 60, 630, 300, "questiontext", $question->questiontext); + if ($usehtmleditor) { + helpbutton("richtext", get_string("helprichtext"), "moodle"); + } else { + helpbutton("text", get_string("helptext"), "moodle"); + } + ?> +

    :

    + image", get_string("none"),"",""); + } + ?> +

    :

    +    + :  + + + + + +
    +

    :

    + +
    + + + +"> +
    +
    + + + diff --git a/mod/quiz/pix/de.gif b/mod/quiz/pix/de.gif index 550df5db8c43d778c40a1290f1d3a724d0e88133..9c6ec299d1c42431d90e6c1e75934f7c0d0b7d47 100755 GIT binary patch literal 117 zcmZ?wbhEHb6krfwSj524A&*yLWcPa|NsBruwerO1BjvclZBCift^7I$OWnt zU|?Xjs@QespMjC{>aC|Hoc*on<|cB~V_tMcM(pgajF?qxZeLWBdc&x(tC_*!LG;YN TCKbW--Kly3T`69^3=Gx)nf@z& literal 128 zcmZ?wbhEHb6krfwSoEKPf#I&Pahh>jn(@rE0|yTL|Np+Z^fq{iV2gnAh z6kuRrcJF+-+G^iGBQ{L07kMNUjP6A literal 0 HcmV?d00001 diff --git a/mod/quiz/question.php b/mod/quiz/question.php index 88e94837b4..dfb40e5d7f 100644 --- a/mod/quiz/question.php +++ b/mod/quiz/question.php @@ -316,10 +316,35 @@ break; case DESCRIPTION: - print_heading(get_string("editingdescription", "quiz")); + print_heading_with_help(get_string("editingdescription", "quiz"), "description", "quiz"); require("description.html"); break; + case NUMERICAL: + // This will only support one answer of the type NUMERICAL + // However, lib.php has support for multiple answers + if (!empty($question->id)) { + $answersraw= quiz_get_answers($question); + } + $answers= array(); + for ($i=0; $i<6; $i++) { + $answers[$i]->answer = ""; // Make answer slots, default as blank... + $answers[$i]->min = ""; + $answers[$i]->max = ""; + $answers[$i]->feedback = ""; + } + if (!empty($answersraw)) { + $i=0; + foreach ($answersraw as $answer) { + $answers[$i] = $answer; + $i++; + } + } + print_heading_with_help(get_string("editingnumerical", "quiz"), "numerical", "quiz"); + require("numerical.html"); + break; + + default: error("Invalid question type"); break; diff --git a/mod/quiz/version.php b/mod/quiz/version.php index 50d0821f0e..ff93d62157 100644 --- a/mod/quiz/version.php +++ b/mod/quiz/version.php @@ -5,7 +5,7 @@ // This fragment is called by moodle_needs_upgrading() and /admin/index.php //////////////////////////////////////////////////////////////////////////////// -$module->version = 2003042702; // The (date) version of this module +$module->version = 2003071000; // The (date) version of this module $module->cron = 0; // How often should cron check this module (seconds)? ?> -- 2.39.5