## WeBWorK Problems

by Bruce Yoshiwara -
Number of replies: 4

Is it possible to create a WeBWorK problem for which the student needs to enter only one of many correct answers?

For example, “Give an ordered pair that is a solution to the equation x+y=10.”

Or more challenging, “List three ordered pair solutions to...” with the student being allowed any ordering.

How would the answer be defined?

by Davide Cervone -
Yes, it is possible to do what you ask. The easiest way is probably to use a MathObject Point with a custom answer checker. Here is one way to do it:
    Context("Point");

BEGIN_TEXT
A solution to $$x+y=10$$ is $$(x,y)$$ = \{ans_rule(20)\}
END_TEXT

ANS(Point(3,7)->cmp(
showCoordinateHints => 0,
checker => sub {
my ($correct,$student,$ans) = @_; my ($x,$y) =$student->value;
return $x +$y == 10;
}
));


The key is the checker => sub {...}, which lets you provide a subroutine that checks the student's answer. It only gets called when the student's answer actually is a point with two coordinates, so it is safe not to do any type checking within the checker itself. The first line extracts the parameters (the correct answer as a MathObject, the student's answer as a MathObject, and the answer hash). The second line breaks the point into its coordinates, and the third determines if the coordinates have the needed property. Note that the coordinates are themselves MathObject Reals, so the equality is a fuzzy check, so you don't have to do anything special in order to allow the student answers to be off by a small amount.

For your second question, you can use a MultiAnswer object with three answer blanks. Here's one solution:

    loadMacros("parserMultiAnswer.pl");

Context("Point");

$ma = MultiAnswer("(3,7)","(0,10)","(-1,11)")->with( allowBlankAnswers => 1, checker => sub { my ($correct,$student,$ans) = @_;
my @score = (0) x scalar(@$correct); ANSWER: foreach my$i (0..scalar(@$correct)-1) { if ($student->[$i] ne "") { foreach my$j (0..$i-1) { if ($student->[$j] ne "" &&$student->[$i] ==$student->[$j]) {$ma->setMessage($i+1,"This is the same as your ".$ma->NameForNumber($j+1)." solution."); next ANSWER; } } my ($x,$y) =$student->[$i]->value;$score[$i] =$x + $y == 10; } } return @score; } ); BEGIN_TEXT Three distinct solutions to $$x+y=10$$ are$BR
$$(x,y)$$ = \{$ma->ans_rule(10)\}, \{$ma->ans_rule(10)\}, and \{$ma->ans_rule(10)\} END_TEXT$showPartialCorrectAnswers =1;
ANS($ma->cmp);  Here, the MultiAnswer provides three answer blanks (note the use of$ma->ans_rule rather than just ans_rule), and its checker looks through the individual answers to see that they are distinct (and gives an error message otherwise), and that they satisfy the equation.

Hope these help.

Davide

by Dick Lane -
It was easy to modify both of Davide's examples to handle solutions for  a x + b y = c.  However, I have not found a way to supply an answer which displays using fractional notation.  Here is my current version for generalizing the first example.

DOCUMENT();
loadMacros( "PGstandard.pl" , "MathObjects.pl" , "contextFraction.pl" );

TEXT(beginproblem());
Context( "Fraction" ) ;

$a = random( 1 , 9 , 1 ) ; do {$b = random( 1 , 9 , 1 );}  until  ($b !=$a) ;
$gcd = gcd($a , $b ) ;$a *= list_random( -1 , 1 ) / $gcd ; if ($a > 0)  {$b *= list_random(-1,1)/$gcd;} else {$b /=$gcd;}

$c = random( -20 , 20 , 1 ) ;$d = Compute( "$c/$b" ) ;

Context( "Point" ) ; #### y is valid variable in Point context
$LHS = Formula( "$a x + $b y" ) -> reduce ; Context() -> texStrings ; BEGIN_TEXT One solution to $$LHS = c$$ is $$(x,y)$$ = \{ans_rule(20)\}. END_TEXT Context() -> normalStrings ; #### Point(0,$d)  gets error msg: Coordinate of Point can't be a Fraction
ANS( Point( 0 , $c/$b ) -> cmp(
showCoordinateHints => 0 ,
checker => sub {
my ($correct,$student,$ans) = @_; my ($x,$y) =$student->value;
return $a*$x + $b*$y == $c ; } )); ENDDOCUMENT(); ==================== Notes: a) Point(0,$c/$b) in ANS results in decimal display of "correct answer"; preceding comment quotes error message if$d (a  Fraction) is used.

b)  I do not see a need for "Show Answer" to produce prose explaining there are many correct answers other than the displayed example.  Students who produce a correct response should not need it and those who fail are apt to react OOPS upon seeing coordinates for intersection with y-axis --- provided (!) the display shows an explicit fraction.

c)  $LHS can display as 2 x + 3 y, 4 x - 5 y, 6 y - 7 x. If both$a and $b were allowed to be negative, then$LHS = $c could display as - (8 x + 9 y) = -13; my computation of$b avoids that.

d)  if PGauxiliaryFunctions.pl included an Extended GCD function, then it would be easy to supply a lattice point as "correct answer".  On the other hand, I prefer to cite points on the axes.

by Davide Cervone -
1. Point(0,$c/$b) produces a decimal because Perl computes $c/$b before Point() is called, so the coordinates are decimals and not fractions. You are correct to try to use $d instead, but because the context has changed, it doesn't really know that Fraction objects are special cases of Real numbers, and so complains about the coordinates not being reals. You can fix that by using: $d = Compute( "$c/$b" )->with(isReal => 1) ;

or perhaps
    ANS( Point( 0, $d->with(isReal=>1) ) -> cmp ( ... ));  instead. I will modify the Fraction object to include this automatically, but right now I'm temporarily not able to make updates to the WeBWorK archive (because I haven't converted over from CVS to SVN, which is now being used to manage the archive). I'll do that soon. If you make that change, your correct answers will show up properly (though student answers will show as decimals, since they aren't in Fraction context). Alternatively, you could use  ANS(Compute("(0,$c/$d)")->cmp( ... ));  since Compute() always shows the string that was used for the computation as the correct answer. I'm not sure where such a statement is being produced. I don't see it in the samples I'm using, but that may be because I'm not going through a normal problem assignment to view the results. You can disable the reduction rules that cause this transformation to occur by using $LHS = Formula( "$a x +$b y" ) -> reduce("(-x)-y"=>0) ;

which will prevent the rule that converts -x-y to -(x+y). You can also use
    $LHS = Formula( "$a x + \$b y" ) -> reduce("(-x)-y"=>0,"(-x)+y"=>0) ;

to force the order to be preserved (so that -3x+2y does not become 2y-3x).

Hope those help.

Davide

by Dick Lane -