Difference between revisions of "MultiAnswerProblems"

From WeBWorK_wiki
Jump to navigation Jump to search
Line 113: Line 113:
 
</tr>
 
</tr>
 
</table>
 
</table>
  +
  +
<p>
  +
One further note is worth making about this: if the answer blanks in the problem have different types (e.g., if the formula 1-<i>x</i> and the string "anything" can be entered in either order), there will be trouble checking the answers, because answer checking will be stopped if the type of the student answer doesn't match that of the input answer. In this case we need to turn off type checking in the <code>MultiAnswer-&gt;with()</code> call, and add type checking in the answer checker. For example,
  +
</p>
  +
<pre>
  +
$multipart = MultiAnswer($ans1, $ans2)-&gt;with(
  +
singleResult =&gt; 0,
  +
checkTypes =&gt; 0,
  +
checker =&gt; sub {
  +
my ( $correct, $student, $self ) = @_;
  +
my ( $a1stu, $a2stu ) = @{$student};
  +
my ( $a1, $a2 ) = @{$correct};
  +
if ( ( ( ref($a1stu) eq ref($a1) && $a1stu == $a1 ) &&
  +
( ref($a2stu) eq ref($a2) && $a2stu == $a2 ) ) ||
  +
( ( ref($a1stu) eq ref($a2) && $a1stu == $a2 ) &&
  +
( ref($a2stu) eq ref($a1) && $a2stu == $a1 ) ) ) {
  +
return [1,1];
  +
} elsif ( ( ref($a1stu) eq ref($a1) && $a1stu == $a1 ) ||
  +
( ref($a1stu) eq ref($a2) && $a1stu == $a2 ) ) {
  +
return [1,0];
  +
} elsif ( ( ref($a2stu) eq ref($a1) && $a2stu == $a1 ) ||
  +
( ref($a2stu) eq ref($a2) && $a2stu == $a2 ) ) {
  +
return [0,1];
  +
} else {
  +
return [0,0];
  +
}
  +
} );
  +
</pre>
   
 
<p style="text-align:center;">
 
<p style="text-align:center;">

Revision as of 11:12, 18 February 2008

MultiAnswer Problems, Linked Answer Blanks: PG Code Snippet

This code snippet shows the essential PG code to create a problem with multiple answer blanks which use the answers to all of the answer blanks to decide if the problem is correct. Note that these are insertions, not a complete PG file. This code will have to be incorporated into the problem file on which you are working.

Problem Techniques Index

PG problem file Explanation
  loadMacros("parserMultiAnswer.pl");

In the initialization section of the file, load parserMultiAnswer.pl.

  $fac1 = Formula("(1 - x)");
  $fac2 = Formula("(1 + x)");

  $multipart = MultiAnswer($fac1, $fac2)->with(
    singleResult => 0,
    checker => sub {
        my ( $correct, $student, $self ) = @_;
        my ( $f1stu, $f2stu ) = @{$student};
        my ( $f1, $f2 ) = @{$correct};
        if ( ($f1 == $f1stu && $f2 == $f2stu) ||
             ($f1 == $f2stu && $f2 == $f1stu) ) {
            return [1,1];
        } else {
            if ($f1 == $f1stu || $f2 == $f1stu) {
                return [1,0];
            } elsif ($f1 == $f1stu || $f2 == $f2stu) {
                return [0,1];
            } else {
                return [0,0];
            }
        }
    }
  );

In the problem set-up section of the file we define a MultiAnswer object that knows how to deal with the problem. Here we define an object that will take two answers and check that they are correct (in either order).

First, the singleResult=>0 line indicates that the different answers in the problem will be evaluated as separate answers, rather than as a single unit.

Then, the checker=> section defines a subroutine to evaluate the problem. It will always have as input a reference to an array of correct answers, a reference to an array of student answers, and a reference to the object itself. (There is a fourth input, too, an answer hash, but we don't need that here.)

The checker routine then returns a reference to a list of results for the problem. In this case there are two answer blanks, so there are two return values. All return values should be 0 or 1, according to whether the answer for that answer blank is correct or not. Note that if we made this an "all or nothing" problem (that is, we set singleResult=>1), then there is only one return value needed, so that we could just return 0 or return 1.

It is possible to set an answer message that will be displayed when the problem is checked, too. For example, if we wanted to set a message when one of the parts was wrong, we could replace the section of the checker code that deals with incorrect answers with:

  if ($f1 == $f1stu || $f2 == $f1stu) {
    $self->setMessage(1,"This is correct.");
    $self->setMessage(2,"Check your answer by using FOIL.");
    return [1,0];
  } elsif ($f1 == $f1stu || $f2 == $f2stu) {
    $self->setMessage(1,"Check your answer by using FOIL.");
    $self->setMessage(2,"This is correct.");
    return [0,1];
  } else {
    return [0,0];
  }
  BEGIN_TEXT
  Factor: \(1-x^2 = \)
  \{$multipart->ans_rule(10)\} 
  \{$multipart->ans_rule(10)\}
  END_TEXT

In the text section of the problem we proceed as expected, but define the answer blanks using the MultiAnswer object that we defined in the initialization section of the problem.

  ANS( $multipart->cmp() ); 

And the answer and solution section of the file is straightforward.

One further note is worth making about this: if the answer blanks in the problem have different types (e.g., if the formula 1-x and the string "anything" can be entered in either order), there will be trouble checking the answers, because answer checking will be stopped if the type of the student answer doesn't match that of the input answer. In this case we need to turn off type checking in the MultiAnswer->with() call, and add type checking in the answer checker. For example,

  $multipart = MultiAnswer($ans1, $ans2)->with(
    singleResult => 0,
    checkTypes => 0,
    checker => sub {
        my ( $correct, $student, $self ) = @_;
        my ( $a1stu, $a2stu ) = @{$student};
        my ( $a1, $a2 ) = @{$correct};
        if ( ( ( ref($a1stu) eq ref($a1) && $a1stu == $a1 ) &&
               ( ref($a2stu) eq ref($a2) && $a2stu == $a2 ) ) ||
             ( ( ref($a1stu) eq ref($a2) && $a1stu == $a2 ) &&
               ( ref($a2stu) eq ref($a1) && $a2stu == $a1 ) ) ) {
            return [1,1];
        } elsif ( ( ref($a1stu) eq ref($a1) && $a1stu == $a1 ) ||
                  ( ref($a1stu) eq ref($a2) && $a1stu == $a2 ) ) {
            return [1,0];
        } elsif ( ( ref($a2stu) eq ref($a1) && $a2stu == $a1 ) ||
                  ( ref($a2stu) eq ref($a2) && $a2stu == $a2 ) ) {
            return [0,1];
        } else {
            return [0,0];
        }
    } );

Problem Techniques Index