Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Question Engine 2:Developing the Multianswer (Cloze) Question Type: Difference between revisions

From MoodleDocs
No edit summary
No edit summary
Line 1: Line 1:
== Introduction ==
This page will describe details about implementing the multianswer ( Cloze) question type in the new question engine code.
This page will describe details about implementing the multianswer ( Cloze) question type in the new question engine code.



Revision as of 16:35, 7 April 2010

Introduction

This page will describe details about implementing the multianswer ( Cloze) question type in the new question engine code.

The detailed day-to-day interactions between Tim Hunt and me (Pierre Pichet) can be found in MDL-20636 .

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


The multianswer question type is more an enclosure for subquestions than a real question type as shortanwer or multichoice. The subquestions are enclosed in the multianswer question text using a specific coding i.e

{1:MULTICHOICE: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}

In the pre engine multianswer the following subquestuons are allowed

  • short answers (SHORTANSWER or SA or MW), case is unimportant,
  • short answers (SHORTANSWER_C or SAC or MWC), case must match,
  • numerical answers (NUMERICAL or NM),
  • multiple choice (MULTICHOICE or MC), represented as a dropdown menu in-line in the text
  • multiple choice (MULTICHOICE_V or MCV), represented a vertical column of radio buttons, or
  • multiple choice (MULTICHOICE_H or MCH), represented as a horizontal row of radio-buttons.

As the new engine allow to store easily more subquestions parameters we decide to implement MULTICHOICE Multi answer and shuffling for multichoice subquestions. So we add the following types

  • multiple choice multi answer (M_MULTICHOICE_V or MMCV), represented a vertical column of radio buttons, or
  • multiple choice multi answer (M_MULTICHOICE_H or MMCH), represented as a horizontal row of radio-buttons

and the shuffled anwers types

  • multiple choice (MULTICHOICE_S or MCS), represented as a dropdown menu in-line in the text
  • multiple choice (MULTICHOICE_V_S or MCVS), represented a vertical column of radio buttons, or
  • multiple choice (MULTICHOICE_H_S or MCHS), represented as a horizontal row of radio-buttons.
  • multiple choice multi answer (M_MULTICHOICE_V_S or MCVS), represented a vertical column of radio buttons, or
  • multiple choice multi answer (M_MULTICHOICE_H_S or MMCHS), represented as a horizontal row of radio-buttons.

This give thirteen variants.

The new engine is built with only one question that is handle by the correponding renderer and the various interacton model.

The attempt object has no initial provision for subquestions although match question type could be considered as having subquestions.

We need first a way to idenitfiy the or other answers coming from the different subquestions which are identified in the cloze questions by there appearance order in the question text ( i.e 1,2, 3, etc.). The identifier chosen was _sub_subquestion_index giving _sub3_answer parameter for the answer step value of the 3rd subquestion.

question classes

The question engine initialise_question_instance in question/type/multianswer/questiontype.php is

   protected function initialise_question_instance(question_definition $question, $questiondata) {
....
    parent::initialise_question_instance($question, $questiondata);
    foreach($questiondata->options->questions as $key =>$wrapped) {
    $class = "";
    switch ($wrapped->qtype){
       case "shortanswer":$class = "qtype_multianswer_shortanswer_question";
                          ....
                          break;
       case "numerical": $class = "qtype_multianswer_numerical_question";
                          ....
                          break;                                           
       case "multichoice":
            if ($wrapped->options->single) {                                    
               switch ($wrapped->options->layout){
                    case VERTICAL   : 
                    case HORIZONTAL : $class = "qtype_multianswer_multichoice_single_question";
                                      break;
                    default : $class = "qtype_multianswer_multichoice_single_inline_question";
               }
                       
             } else {
                   $class = "qtype_multianswer_multichoice_multi_question";
             }

$question->subquestions[$key]->shuffleanswers handle the shuffling options. 

The 5 classes qtype_multianswer_..._question in addition to the qtype_multianswer_question are defined in question/type/multianswer/question.php.

renderer classes

With careful design we could limit the renderer to 4 types. The main class qtype_multianswer_renderer extends qtype_renderer { whose public function formulation_and_controls() follows the same coding as the function print_question_formulation_and_controls of the question/type/multianswer/questiontype.php

       $qtextremaining = $question->format_questiontext();

       // The regex will recognize text snippets of type {#X}
       // where the X can be any text not containg } or white-space characters.

       while (ereg('\{#([^[:space:]}]*)}', $qtextremaining, $regs)) {
           $qtextsplits = explode($regs[0], $qtextremaining, 2);
           $result .= $qtextsplits[0];
           $qtextremaining = $qtextsplits[1];
           $positionkey = $regs[1];
      // transfer to the specific subquestion renderer                 
           if (isset($question->subquestions[$positionkey]) &&
               $question->subquestions[$positionkey] != ){
                  $wrapped = &$question->subquestions[$positionkey];
                  $qout = $wrapped->get_renderer();
                  $qa->subquestionindex = $positionkey ;
                  $result .= $qout->formulation_and_controls($qa,$options);

Shortanswer and numerical use the same renderer

The regular in-line select element multichoice has its own renderer.

The multianswer or single answer multiple choice (vertical or horizontal display) use the same renderer.

Question functions

The main difficulties where how to code the various functions ( i.e. get_correct_response(), is_complete_response() etc.) to the specifics of each subquestion types.

The QA Question attempt expects to interact with a multianswer question object but has no initial provision to handle subquestions.

So the multianswer question functions should redirect the call to the subquestions.

In one case we could desing an universal function without refering to the subquestions.

function is_same_response()

   public function is_same_response(array $prevresponse, array $newresponse) {
       if ( $newresponse ==  || count($prevresponse) != count($newresponse)){
           return false ;
       }
       foreach($newresponse as $arraykey => $value){
           if($value ==  ||  ! array_key_exists($arraykey, $prevresponse) 
               || $value !== $prevresponse[$arraykey]){
              return false ;
         }
       }
       return true ;       
   }

For the functions that involve directly the $step, Tim design the