Difference between revisions of "CustomAnswerCheckers"

From WeBWorK_wiki
Jump to navigation Jump to search
m
(added historical tag and gave updated problem link)
 
(19 intermediate revisions by 4 users not shown)
Line 1: Line 1:
  +
{{historical}}
  +
  +
<p style="font-size: 120%;font-weight:bold">This problem has been replaced with [https://openwebwork.github.io/pg-docs/sample-problems/problem-techniques/CustomAnswerCheckers.html a newer version of this problem]</p>
 
<h2>Custom Answer Checkers: PG Code Snippet</h2>
 
<h2>Custom Answer Checkers: PG Code Snippet</h2>
   
 
<p style="background-color:#eeeeee;border:black solid 1px;padding:3px;">
 
<p style="background-color:#eeeeee;border:black solid 1px;padding:3px;">
<em>This code snippet shows the essential PG code to write problems that check "arbitrary" conditions on the student's answer. Note that these are <b>insertions</b>, not a complete PG file. This code will have to be incorporated into the problem file on which you are working.</em>
+
<em>This is the essential PG code to write problems that check "arbitrary" conditions on the student's answer.
  +
<br />
  +
<br />
  +
You may also be interested in [http://webwork.maa.org/wiki/PeriodicAnswers PeriodicAnswers]
  +
</em>
 
</p>
 
</p>
   
 
<p style="text-align:center;">
 
<p style="text-align:center;">
[[IndexOfProblemTechniques|Problem Techniques Index]]
+
[[Problem_Techniques|Problem Techniques Index]]
</p>
 
 
<p>
 
Note that it is possible to do this with old-style answer checkers as well. However, it's more straightforward to do it with MathObjects based answer checkers, so that's the method that we use here.
 
 
</p>
 
</p>
   
Line 13: Line 16:
 
<th> PG problem file </th>
 
<th> PG problem file </th>
 
<th> Explanation </th>
 
<th> Explanation </th>
  +
</tr>
  +
<tr valign="top">
  +
<td style="background-color:#ddffdd;border:black 1px dashed;">
  +
<pre>
  +
DOCUMENT();
  +
loadMacros(
  +
"PGstandard.pl",
  +
"MathObjects.pl",
  +
);
  +
TEXT(beginproblem());
  +
</pre>
  +
</td>
  +
<td style="background-color:#ccffcc;padding:7px;">
  +
<p>
  +
<b>Initialization:</b> Standard. You might want to use [http://webwork.maa.org/pod/pg/macros/answerCustom.html answerCustom.pl], although it is not necessary.
  +
</p>
  +
</td>
 
</tr>
 
</tr>
 
<tr valign="top">
 
<tr valign="top">
 
<td style="background-color:#ffffdd;border:black 1px dashed;">
 
<td style="background-color:#ffffdd;border:black 1px dashed;">
 
<pre>
 
<pre>
$ans = pi/3;
 
  +
Context("Numeric");
$val = cos($ans);
 
  +
  +
$ans = pi/3;
  +
$val = cos($ans);
 
</pre>
 
</pre>
 
</td>
 
</td>
 
<td style="background-color:#ffffcc;padding:7px;">
 
<td style="background-color:#ffffcc;padding:7px;">
 
<p>
 
<p>
  +
<b>Setup:</b>
 
To set up the custom answer checker we will override the answer checker routine for the MathObject that we're using to check the answer. Thus our answer object should be of the same type (e.g., Real, Formula, etc.) as what we want the student to be entering. For example, here we're going to ask for a value of <i>x</i> such that cos(<i>x</i>)=cos($ans). Thus we set up the answer to be a real number.
 
To set up the custom answer checker we will override the answer checker routine for the MathObject that we're using to check the answer. Thus our answer object should be of the same type (e.g., Real, Formula, etc.) as what we want the student to be entering. For example, here we're going to ask for a value of <i>x</i> such that cos(<i>x</i>)=cos($ans). Thus we set up the answer to be a real number.
 
</p>
 
</p>
Line 36: Line 59:
 
<td style="background-color:#ffdddd;border:black 1px dashed;">
 
<td style="background-color:#ffdddd;border:black 1px dashed;">
 
<pre>
 
<pre>
BEGIN_TEXT
 
  +
Context()->texStrings;
Enter a value of \(x\) for which \(\cos(x) = $val\):
 
  +
BEGIN_TEXT
\(x = \) \{ ans_rule(25) \}
 
  +
Enter a value of \(x\) for which \(\cos(x) = $val\):
END_TEXT
 
  +
\(x = \) \{ ans_rule(25) \}
  +
END_TEXT
  +
Context()->normalStrings;
 
</pre>
 
</pre>
 
<td style="background-color:#ffcccc;padding:7px;">
 
<td style="background-color:#ffcccc;padding:7px;">
 
<p>
 
<p>
  +
<b>Main Text:</b>
 
We don't have to make any changes or additions to the text section of the file.
 
We don't have to make any changes or additions to the text section of the file.
 
</p>
 
</p>
Line 50: Line 76:
 
<td style="background-color:#eeddff;border:black 1px dashed;">
 
<td style="background-color:#eeddff;border:black 1px dashed;">
 
<pre>
 
<pre>
ANS( $ans-&gt;cmp( checker=&gt;sub {
 
  +
$showPartialCorrectAnswers = 1;
my ( $correct, $student, $ansHash ) = @_;
 
  +
return cos($correct) == cos($student);
 
  +
ANS( $ans-&gt;cmp( checker=&gt;sub {
} ) );
 
  +
my ( $correct, $student, $ansHash ) = @_;
  +
return cos($correct) == cos($student);
  +
} ) );
  +
  +
ENDDOCUMENT();
 
</pre>
 
</pre>
 
<td style="background-color:#eeccff;padding:7px;">
 
<td style="background-color:#eeccff;padding:7px;">
 
<p>
 
<p>
Then when setting up the answer and solution section, we overwride the default answer checker in the answer. The replacement is a Perl subroutine that takes as its arguments the correct answer, student answer, and answer hash that is being processed in the answer comparison. Its return value should be 1 if the student's answer is correct, and 0 (false) otherwise.
 
  +
<b>Answer Evaluation:</b>
  +
Then when setting up the answer and solution section, we override the default answer checker in the answer. The replacement is a Perl subroutine that takes as its arguments the correct answer, student answer, and answer hash that is being processed in the answer comparison. Its return value should be 1 if the student's answer is correct, and 0 (false) otherwise. When doing the relational check, you should always put the correct answer on the left and the student answer on the right, e.g., <code>cos($correct) == cos($student)</code> should be used, but <code>cos($student) == cos($correct)</code> should not since the relational operator works from left to right which would mean that the student's answer would be determining the settings (such as domain of function evaluation) instead of the correct answer.
 
</p>
 
</p>
 
<p>
 
<p>
We could also specify the answer checker as a separate subroutine by writing <code>ANS( $ans-&gt;cmp( checker=&gt;~~&mycheck ) )</code> and then including <code>mycheck</code> as a separate subroutine, viz.,
+
We could also specify the answer checker as a separate subroutine by writing
</p>
 
 
<pre>
 
<pre>
 
sub mycheck {
 
sub mycheck {
 
my ($correct, $student, $ansHash) = @_;
 
my ($correct, $student, $ansHash) = @_;
return cos($student) == cos($correct);
+
return cos($correct) == cos($student);
 
}
 
}
</pre>
 
  +
<p>
 
  +
ANS( $ans-&gt;cmp( checker=&gt;~~&mycheck ) );
  +
</pre>
 
(The <code>~~</code> in the above is remapped to a backslash in the course of the PG translation of the problem.)
 
(The <code>~~</code> in the above is remapped to a backslash in the course of the PG translation of the problem.)
 
</p>
 
</p>
 
<p>
 
<p>
One final point: we can set an error message in the answer checker by including the line <code>Value-&gt;Error("message")</code> after the error. This will set the message that is displayed to the student and exit the checker with an incorrect return value.
+
We can set an error message in the answer checker by using <code>Value-&gt;Error("message")</code>. This will set the message that is displayed to the student and exit the checker with an incorrect return value. For example:
  +
<pre>
  +
sub mycheck {
  +
my ($correct, $student, $ansHash) = @_;
  +
Value->Error("Try again") if cos($student)==sqrt(3)/2;
  +
return cos($correct) == cos($student);
  +
}
  +
  +
ANS( $ans-&gt;cmp( checker=&gt;~~&mycheck ) );
  +
</pre>
  +
To see all of the keys and values in the <code>$ansHash</code> when the submit answers button is pressed, include this in your custom answer checker:
  +
<pre>
  +
foreach my $key ( keys %{$ansHash} ) {
  +
warn "key: $key, value: $ansHash->{$key}";
  +
}
  +
</pre>
 
</p>
 
</p>
 
</td>
 
</td>
Line 78: Line 110:
   
 
<p style="text-align:center;">
 
<p style="text-align:center;">
[[IndexOfProblemTechniques|Problem Techniques Index]]
+
[[Problem_Techniques|Problem Techniques Index]]
 
</p>
 
</p>
   
 
[[Category:Problem Techniques]]
 
[[Category:Problem Techniques]]
  +
  +
  +
  +
<ul>
  +
<li>POD documentation: [http://webwork.maa.org/pod/pg/macros/answerCustom.html answerCustom.pl]</li>
  +
<li>PG macro: [http://webwork.maa.org/viewvc/system/trunk/pg/macros/answerCustom.pl?view=log answerCustom.pl]</li>
  +
</ul>

Latest revision as of 08:17, 28 June 2023

This article has been retained as a historical document. It is not up-to-date and the formatting may be lacking. Use the information herein with caution.

This problem has been replaced with a newer version of this problem

Custom Answer Checkers: PG Code Snippet

This is the essential PG code to write problems that check "arbitrary" conditions on the student's answer.

You may also be interested in PeriodicAnswers

Problem Techniques Index

PG problem file Explanation
DOCUMENT();
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
);
TEXT(beginproblem());

Initialization: Standard. You might want to use answerCustom.pl, although it is not necessary.

Context("Numeric");

$ans = pi/3;
$val = cos($ans);

Setup: To set up the custom answer checker we will override the answer checker routine for the MathObject that we're using to check the answer. Thus our answer object should be of the same type (e.g., Real, Formula, etc.) as what we want the student to be entering. For example, here we're going to ask for a value of x such that cos(x)=cos($ans). Thus we set up the answer to be a real number.

In this sample, we've taken advantage of a bunch of overloading that MathObjects do: the line $ans = pi/3 is doing the same thing as $ans = Real("pi/3") or $ans = Compute("pi/3"), because pi is already defined as a Real, and the division / is overloaded for MathObjects.

Similarly, $val = cos($ans) takes advantage of the cos() function being overloaded to produce a MathObject when the argument is a MathObject. Thus this is the same as $val = Compute("cos(x)")->eval(x=>$ans) (which would be necessary if $ans wasn't already a MathObject).

Context()->texStrings;
BEGIN_TEXT
Enter a value of \(x\) for which \(\cos(x) = $val\):
\(x = \) \{ ans_rule(25) \}
END_TEXT
Context()->normalStrings;

Main Text: We don't have to make any changes or additions to the text section of the file.

$showPartialCorrectAnswers = 1;

ANS( $ans->cmp( checker=>sub {
my ( $correct, $student, $ansHash ) = @_;
return cos($correct) == cos($student);
} ) );

ENDDOCUMENT();

Answer Evaluation: Then when setting up the answer and solution section, we override the default answer checker in the answer. The replacement is a Perl subroutine that takes as its arguments the correct answer, student answer, and answer hash that is being processed in the answer comparison. Its return value should be 1 if the student's answer is correct, and 0 (false) otherwise. When doing the relational check, you should always put the correct answer on the left and the student answer on the right, e.g., cos($correct) == cos($student) should be used, but cos($student) == cos($correct) should not since the relational operator works from left to right which would mean that the student's answer would be determining the settings (such as domain of function evaluation) instead of the correct answer.

We could also specify the answer checker as a separate subroutine by writing

sub mycheck {
  my ($correct, $student, $ansHash) = @_;
  return cos($correct) == cos($student);
}

ANS( $ans->cmp( checker=>~~&mycheck ) );

(The ~~ in the above is remapped to a backslash in the course of the PG translation of the problem.)

We can set an error message in the answer checker by using Value->Error("message"). This will set the message that is displayed to the student and exit the checker with an incorrect return value. For example:

sub mycheck {
  my ($correct, $student, $ansHash) = @_;
  Value->Error("Try again") if cos($student)==sqrt(3)/2;
  return cos($correct) == cos($student);
}

ANS( $ans->cmp( checker=>~~&mycheck ) );

To see all of the keys and values in the $ansHash when the submit answers button is pressed, include this in your custom answer checker:

foreach my $key ( keys %{$ansHash} ) {
  warn "key: $key, value: $ansHash->{$key}";
}

Problem Techniques Index