WeBWorK Problems

Custom error messages for a 'list' answer (Quadratic equations)

Custom error messages for a 'list' answer (Quadratic equations)

by Chris Hughes -
Number of replies: 2
I'm writing some problems on solving quadratic equations- starting with something like:

Solve the following quadratic equation

x^2=a^2

I'd like the students to answer with

x=a,x=-a

I'd like to customize the error messages so that when students enter answers like the following they are given the corresponding error messages (and combinations thereof)

a
Your first solution is correct, but you need to write x=____
Are you sure you have all the solutions?
a,-a
Your first solution is correct, but you need to write x=____
Your second solution is correct, but you need to write x=____
x=a
Are you sure you have all of the solutions?

I have made some progress following http://webwork.maa.org/wiki/Custom_Answer_Checkers_for_Lists but I have some issues outstanding:
  • most importantly, my code doesn't check the correctness (!)
  • more subtly, when a student enters x=a the error message persists as if there are two solutions. I would quite like to have the error message 'Are you sure you have all the solutions?' as above

I hope these aren't too elementary, I'm quite new to WeBWorK- if there's an existing or better way to do this, I'm very open to it! Thanks in advance.

Here's a complete MWE comprising what I have so far:

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"parserAssignment.pl",
"PGML.pl",
"answerHints.pl",
);

##############################################

Context("Numeric");

# the variable of the equation
$var = 'x';
Context()->variables->are($var=>'Real');

# custom error messages
parser::Assignment->Allow;
Context()->flags->set(reduceConstantFunctions=>0,formatStudentAnswer=>parsed);
Context()->{error}{msg}{"The left side of an assignment must be a variable or function"}
= "Your answer should be in the form $var = ___";
Context()->{error}{msg}{"The right side of an assignment must not include the variable being defined"}
= "The right side must not include the variable being defined";

# add solution strings to context- this means that if
# students enter these (and they are not correct), then
# WW will not give a Context warning
Context()->strings->add("no solution"=>{},
"no solutions"=>{alias=>'no solution'},
"none"=>{alias=>'no solution'},
);

# the right hand side
$a = random(2,10,1);

# answer
$ans = $a;
$ans = Compute($ans);
$ans1 = -$a;
$ans1 = Compute($ans1);
#$ansEq = List($a,$b);
#$ansEq=Formula("$var=$ans");
#$ansEq=List(Formula("$var=$ans"),Formula("$var=$ans1"));
$ansEq=Formula("$var=$ans","$var=$ans1");


##############################################
TEXT(beginproblem());

BEGIN_PGML
Solve the following quadratic equation

[`
[$var]^2 = [$a**2]
`]

[____________]

* Enter multiple answers separated by commas, such as [`x=1,x=-1`]
* If you need to use the square root symbol,
as in [`x=\sqrt{17}`], type it using: *sqrt(17)*
* If there are no solutions, enter *no solutions*
END_PGML

#ANS(Formula("$var=$ans,$var=$ans1")->cmp);
## answer checker for lists tutorial:
##
## http://webwork.maa.org/wiki/Custom_Answer_Checkers_for_Lists
##
##
#ANS(Formula("$var=$ans,$var=$ans1")->cmp);
ANS(Formula("$var=$ans,$var=$ans1")->cmp(list_checker => sub {
my ($correct,$student,$ansHash,$value) = @_;
my $n = scalar(@$student); # number of student answers
my $score = 0; # number of correct student answers
my @errors = (); # stores error messages
my $i, $j; # loop counters

#
# Loop though the student answers
##
for ($i = 0; $i < $n; $i++) {
my $ith = Value::List->NameForNumber($i+1);
my $p = $student->[$i]; # i-th student answer
#
# Check that the student's answer is a point
#
if ($p->type ne "Assignment") {
push(@errors,"Your $ith entry needs to be in the form x=____");
next;
}
#
# Check that the point hasn't been given before
#
for ($j = 0, $used = 0; $j < $i; $j++) {
if ($student->[$j]->type eq "Assignment" && $student->[$j] == $p) {
push(@errors,"Your $ith solution is the same as a previous one") unless $ansHash->{isPreview};
$used = 1; last;
}
}
#
# If not already used, check that it satisfies the equation
# and increase the score if so.
#
if (!$used) {
$score++;
#my ($a,$b) = $p->value;
#if ($a + $b == 5) {$score++} else {
# push(@errors,"Your $ith point is not correct") unless $ansHash->{isPreview}
#}
}
}
#
# Check that there are the right number of answers
#
if (!$ansHash->{isPreview}) {
push(@errors,"Are you sure you have all the solutions?") if $n < 2;
push(@errors,"You have given too many solutions- every quadratic equation has at most two solutions") if $n > 2;
}
return ($score,@errors);
}));

BEGIN_PGML_SOLUTION
The answer is [`[$ansEq]`].
END_PGML_SOLUTION
##############################################


ENDDOCUMENT();


In reply to Chris Hughes

Re: Custom error messages for a 'list' answer (Quadratic equations)

by Davide Cervone -
You are pretty far along with your checker, and I applaud you for your efforts; but there are some easier ways to handle this. In particular, the AnswerHints macro (in answerHints.pl) is designed specifically for this kind of situation. So you could use
    loadMacros("answerHints.pl");
    ...
    $showPartialCorrectAnswers = 1;
    ANS($ans->cmp->withPostFilter(AnswerHints(
      ["$var=$a","$var=-$a"] => "Are you sure you have all the solutions?",
      [$a,-$a] => ["Your solution is a correct one, but you should write $var = ___<br>Are you sure you have all the solutions?",replaceMessage=>1],
      ["$a,-$a","-$a,$a"] => ["Your solutions are correct, but you should write $var = ___",replaceMessage=>1],
    )));
to get the messages that you request. Note that this will not give any messages about writing x = ___ except for the special cases when the solutions are correct. If you want to handle any situation that doesn't use an assignment, then you can use the extra option to provide a subroutine that checks the syntax for any extra (i.e., incorrect) answers. This can be used to provide additional error messages for those items. Here is one approach:
    loadMacros(
      "parserAssignment.pl",
      "answerHints.pl",
      "PGML.pl",
    );
    
    Context("Numeric");
    parser::Assignment->Allow;
    
    $var = "x";
    $a = random(2,10,1);
    $ans = Compute("$var = -$a, $var = $a");
    
    BEGIN_PGML
    Solve the quadratic equation
    
    >> [` [$var]^2 = [$a**2] `]. <<

    The solutions are: [____________]
    END_PGML
    
    $showPartialCorrectAnswers = 1;
    ANS($ans->cmp(entry_type => "solution", extra => sub {
      my ($student,$ansHash,$nth,$value) = @_;
      if ($student->type ne "Assignment" && $ansHash->{student_formula}->type ne "Assignment") {
        $student->context->setError("Your$nth $value should be written $var = ___","",undef,undef,$Value::CMP_WARNING);
        return;
      }
      return Value::Real->typeMatch($student);
    })->withPostFilter(AnswerHints(
      ["$var=$a","$var=-$a"] => "Are you sure you have all the solutions?",
      [$a,-$a] => ["Your solution is a correct one, but you should write $var = ___<br>Are you sure you have all the solutions?",replaceMessage=>1],
      ["$a,-$a","-$a,$a"] => ["Your solutions are correct, but you should write $var = ___",replaceMessage=>1],
    )));
Here the extra checker get the student answer, the answer has, and values for "n-th" and the type of answer (we have set this to "solution" using entry_type). if the student answer isn't an assignment, we provide a warning message, otherwise we do the type-check for real numbers (that is, we get any warning messages from that).

Hope that helps.

Davide

In reply to Davide Cervone

Re: Custom error messages for a 'list' answer (Quadratic equations)

by Chris Hughes -
Thank you so much Davide, this is perfect! You've taught me a great deal from your explanation and answer, I really appreciate it smile

Thanks again.
Chris