ref
is not really he right way to do the type checking.
Here is my example of the problem that you requested (where three points are required):
DOCUMENT();
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"parserMultiAnswer.pl",
);
Context("Point");
Parser::BOP::equality->Allow; # Allow equalities in formulas
$f = Compute("x^2 + y^2 = 1"); # The equation the students must match
#
# The is the MultiAnswer object, with three correct points
# (only used for showing the correct answer). It allows
# blank answers, so students can add one point at a
# time, and it checks that no two points are equal.
#
$ma = MultiAnswer("(1,0)","(0,1)","(-1,0)")->with(
function => $f,
allowBlankAnswers => 1,
checker => sub {
my ($correct,$student,$self) = @_;
my @student = @$student; # The array of student answers
my $n = scalar(@student); # How many are in the array
my @correct = (0) x $n; # An array of that many zeros (assume none correct)
foreach my $i (0..$n-1) { # Loop through the student answers
next unless $student[$i]->classMatch("Point"); # Go on if the answer is blank
my ($x,$y) = $student[$i]->value; # Get the x and y coordinates
if ($self->{function}->eval(x=>$x,y=>$y)) { # If the equation is satisfied (1 if equal, 0 if not)
$correct[$i] = 1; # Indicate answer is correct
foreach my $j (0..$i-1) { # Look through previous points
if ($student[$j] == $student[$i]) { # If this point equals a previous one
$self->setMessage($i+1,"This point is the same as the ".Value->NameForNumber($j+1)." one");
$correct[$i] = 0; # Give a warning and mark incorrect
break; # Stop looking through previous points
}
}
}
}
return @correct; # Return the array indicating which are correct
}
);
Context()->texStrings;
BEGIN_TEXT
Three distinct points that lie on \($f\) are:$BR
\{$ma->ans_rule(15)\}, \{$ma->ans_rule(15)\}, and \{$ma->ans_rule(15)\}
END_TEXT
Context()->normalStrings;
ANS($ma->cmp);
ENDDOCUMENT();
Note that this checker works for any number of points. The checker itself could be packaged into a separate macro file for re-use, if so desired. For example, the macro file could contain
$points_on_function = sub { my ($correct,$student,$self) = @_; ... return @correct; };then you could use it as
MultiAnswer("(1,0)","(0,1"),"(-1,0)")->with( function => $f, allowBlankAnswers => 1, checker => $points_on_function, );In fact, in that case, you could do something like
sub PointsOnFunction { my $f = shift; return MultiAnswer(@_)->with( function => Compute($f), allowBlankAnswers => 1, checker => $points_on_function, ); }in the macro file, and then just do
PointsOnFunction("x^2+y^2=1","(1,0)","(0,1)","(-1,0)");in the main program. Note that none of the approaches above checks that the correct answers are actually on the function given, so we assume you have them right. :-)
Hope that does the trick.
Davide