OK,
here is another approach, based on using WeBWorK's tools for this. It's
not a completely happy solution, but my MultiPart object was supposed
to be that. Anyhow, here it is.
DOCUMENT(); # This should be the first executable line in the problem.
loadMacros( "PG.pl", "PGbasicmacros.pl", "PGanswermacros.pl", );
TEXT(&beginproblem);
# # This will only work once in a problem (you would need to # keep track of the rule separately if you wanted multiple # sets of answers in a single problem). # $ruleCount = 0; sub extra_ans_rule {NAMED_ANS_RULE_EXTENSION(RECORD_FORM_LABEL("Part".(++$ruleCount)),@_)}
sub myChecker { my @correct = @_;
my $ans = new AnswerEvaluator; $ans->ans_hash( correct_ans => join(", ",@correct), # show all answers in one line type => "multiple answer", # or whatever you want );
$ans->install_evaluator(sub { my $ans = shift; my @correct = @_;
# # Collect student answers from $inputs_ref # my @student = ($ans->{student_ans}); foreach my $i (1..$ruleCount) { my $x = $inputs_ref->{"Part$i"}; $x = "" unless defined($x); push(@student,$x); }
# # Check student's answers against professor's # $ans->score(1); my @latex = (); foreach my $i (0..$ruleCount) { $student[$i] =~ s/(^ +| +)//g; # trim leading and trailing spaces ### need to do error checking on student answers here ### $ans->score(0) if ($correct[$i] ne $student[$i]); if ($student[$i] eq "") {push(@latex,"\_\_"); $student[$i] = "__ "} else {push(@latex,"{\rm $student[$i]}")} } $ans->{preview_latex_string} = join(", ",@latex); $ans->{student_ans} = join(", ",@student);
return $ans; },@_);
# don't do blank check (so if the first blank is empty, we still get called) $ans->install_pre_filter('erase');
return $ans; }
BEGIN_TEXT Enter A and B: \{ans_rule(2)\}, \{extra_ans_rule(2)\} END_TEXT
ANS(myChecker('A','B'));
ENDDOCUMENT(); # This should be the last executable line in the problem.
The key parts to note are that NAMED_ANS_RULE_EXTENSION creates an answer rule that is not tied to an answer checker, and RECORD_FORM_LABEL makes its contents be retained by the WW database (so the student's answers for this blank will be recorded).
The first rule is a normal one that gets associated with an answer
checker, but the second (and potentially more) blanks are not. The
first answer checker has to look up the values that have been entered
by the student. This is done by accessing the $input_refs array reference.
This sample doesn't do any error checking, but you would probably want
to do that in the loop at the location indicated. Also, the check given
here is just a straight string compare between the student and
professor answers. Obviously, you would need to do whatever you need to
do to check your graph.
Note that the checker handles creation of the answer preview LaTeX
string and combines the student (and correct) answers into a single
string. Since the student answers are shown in a single row of the
answer response area at the top of the page, the answers are separated
by commas, and underscores are used to mark any blank entries to make
them more visible.
Finally, I have used an AnswerEvaluator object rather than pure code, to give you an example of how to do that.
Hope that is clear.
On the other hand, I still think the Parser's MultiPart object is a
better choice for this. Here is another example, this time based on the
MultiPart object. All the complexity of dealing with the answer rules,
combining answers, looking up student answers, error checking and
reporting, and so on, have been handled by the MultiPart. You just have
to be concerned with the check you want to perform. DOCUMENT(); # This should be the first executable line in the problem.
loadMacros( "PG.pl", "PGbasicmacros.pl", "PGanswermacros.pl", "Parser.pl", "contextString.pl", "parserMultiPart.pl", );
TEXT(&beginproblem);
Context("String")->strings->are( A => {caseSensitive=>1}, B => {caseSensitive=>1}, );
$mp = MultiPart("A","B")->with( singleResult => 1, checker => sub { my ($correct,$student,$self) = @_; # get the parameters for my $i (0..scalar(@correct)-1) { return 0 if $correct->[$i] != $student->[$i]; } return 1; }, );
BEGIN_TEXT Enter A and B: \{$mp->ans_rule(2)\}, \{$mp->ans_rule(2)\} END_TEXT
ANS($mp->cmp);
ENDDOCUMENT(); # This should be the last executable line in the problem.
Here, we set up a string context for the labels that we want the
student to enter. (You could use numbers as strings if you want.) The
rest is pretty simple: just do whatever check you want to do in the
checker routine.
Hope one of these suits your needs.
Davide
<| Post or View Comments |>
|