[system] / trunk / pg / macros / answerHints.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/answerHints.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5554 - (download) (as text) (annotate)
Wed Oct 3 19:30:31 2007 UTC (12 years, 4 months ago) by sh002i
File size: 5348 byte(s)
fixed some POD errors, indentation

    1 sub _answerHints_init {}
    2 
    3 =head1 AnswerHints()
    4 
    5 This is an answer-checker post-filter that allows you to produce
    6 additional error messages for incorrect answers.  You can trigger
    7 a message for a single answer, a collection of answers, or via a
    8 subroutine that determines the condition for the message.
    9 
   10 Note that this filter only works for MathObjects answer checkers.
   11 
   12 The answer hints are given as a pair using => with the right-hand
   13 side being the answer message and the left-hand side being one of
   14 three possibilities:  1) the value that triggers the message,
   15 2) a reference to an array of values that trigger the message, or
   16 3) a code reference to a subtroutine that accepts tthe correct
   17 answer, the student's answer, and the answer hash, and returns
   18 1 or 0 depending on whether the message should or should not be
   19 displayed.  (See the examples below.)
   20 
   21 The right-hand side can be either the message string itself, or
   22 a referrence to an array where the first element is the message
   23 string, and the remaining elements are name-value pairs that
   24 set options for the message.  These can include:
   25 
   26 =over
   27 
   28 =item C<S<< checkCorrect => 0 or 1 >>>
   29 
   30 1 means check for messages even
   31 if the answer is correct.
   32 Default: 0
   33 
   34 =item C<S<< replaceMessage => 0 or 1 >>>
   35 
   36 1 means it's OK to repalce any
   37 message that is already in place
   38 in the answer hash.
   39 Default: 0
   40 
   41 =item C<S<< checkTypes => 0 or 1 >>>
   42 
   43 1 means only perform the test
   44 if the student answer is the
   45 same type as the correct one.
   46 Default: 1
   47 
   48 =item C<S<< score => number >>>
   49 
   50 Specifies the score to use if
   51 the message is triggered (so that
   52 partial credit can be given).
   53 Default: keep original score
   54 
   55 =item C<S<< cmp_options => [...] >>>
   56 
   57 provides options for the cmp routine
   58 used to check if the student answer
   59 matches these answers.
   60 Default: []
   61 
   62 =back
   63 
   64 If more than one message matches the student's answer, the first
   65 one in the list is used.
   66 
   67 Example:
   68 
   69   ANS(Vector(1,2,3)->cmp(showCoordinateHints=>0)->withPostFilter(AnswerHints(
   70     Vector(0,0,0) => "The zero vector is not a valid solution",
   71     "-<1,2,3>" => "Try the opposite direction",
   72     "<1,2,3>" => "Well done!",
   73     ["<1,1,1>","<2,2,2>","<3,3,3>"] => "Don't just guess!",
   74     sub {
   75       my ($correct,$student,$ans) = @_;
   76       return $correct . $student == 0;
   77     } => "Your answer is perpendicular to the correct one",
   78     Vector(1,2,3) => [
   79       "You have the right direction, but not length",
   80       cmp_options => [parallel=>1],
   81     ],
   82     0 => ["Careful, your answer should be a vector!", checkTypes => 0, replaceMessage => 1],
   83     sub {
   84       my ($correct,$student,$ans) = @_;
   85       return norm($correct-$student) < .1;
   86     } => ["Close!  Keep trying.", score => .25],
   87   )));
   88 
   89 =cut
   90 
   91 sub AnswerHints {
   92   return (sub {
   93     my $ans = shift; $ans->{_filter_name} = "Answer Hints Post Filter";
   94     my $correct = $ans->{correct_value};
   95     my $student = $ans->{student_value};
   96     Value::Error("AnswerHints can only be used with MathObjects answer checkers") unless ref($correct);
   97     return $ans unless ref($student);
   98 
   99     while (@_) {
  100       my $wrongList = shift; my $message = shift; my @options;
  101       ($message,@options) = @{$message} if ref($message) eq 'ARRAY';
  102       my %options = (
  103         checkCorrect => 0,
  104         replaceMessage => 0,
  105   checkTypes => 1,
  106         score => undef,
  107         cmp_options => [],
  108         @options,
  109       );
  110       next if $options{checkType} && $correct->type ne $student->type;
  111       $wrongList = [$wrongList] unless ref($wrongList) eq 'ARRAY';
  112       foreach my $wrong (@{$wrongList}) {
  113   if (ref($wrong) eq 'CODE') {
  114     if (($ans->{score} < 1 || $options{checkCorrect}) &&
  115         ($ans->{ans_message} eq "" || $options{replaceMessage}) &&
  116         &$wrong($correct,$student,$ans)) {
  117       $ans->{ans_message} = $ans->{error_message} = $message;
  118       $ans->{score} = $options{score} if defined $options{score};
  119       last;
  120     }
  121   } else {
  122     $wrong = Value::makeValue($wrong);
  123     if (($ans->{score} < 1 || $options{checkCorrect} || AnswerHints::Compare($correct,$wrong,$ans)) &&
  124         ($ans->{ans_message} eq "" || $options{replaceMessage}) &&
  125         AnswerHints::Compare($wrong,$student,$ans,@{$options{cmp_options}})) {
  126       $ans->{ans_message} = $ans->{error_message} = $message;
  127       $ans->{score} = $options{score} if defined $options{score};
  128       last;
  129     }
  130   }
  131       }
  132     }
  133     return $ans;
  134   },@_);
  135 }
  136 
  137 package AnswerHints;
  138 
  139 #
  140 #  Calls the answer checker on two values with a copy of the answer hash
  141 #  and returns true if the two values match and false otherwise.
  142 #
  143 sub Compare {
  144   my $self = shift; my $other = shift; my $ans = shift;
  145   $ans = bless {%{$ans},@_}, ref($ans);  # make a copy
  146   $ans->{typeError} = 0; $ans->{ans_message} = $ans->{error_message} = ""; $ans->{score} = 0;
  147   if (sprintf("%p",$self) ne sprintf("%p",$ans->{correct_value})) {
  148     $ans->{correct_ans} = $self->string;
  149     $ans->{correct_value} = $self;
  150     $ans->{correct_formula} = Value->Package("Formula")->new($self);
  151   }
  152   if (sprintf("%p",$other) ne sprintf("%p",$ans->{student_value})) {
  153     $ans->{student_ans} = $other->string;
  154     $ans->{student_value} = $other;
  155     $ans->{student_formula} = Value->Package("Formula")->new($other);
  156   }
  157   $self->cmp_preprocess($ans);
  158   $self->cmp_equal($ans);
  159   $self->cmp_postprocess($ans) if !$ans->{error_message} && !$ans->{typeError};
  160   return $ans->{score} >= 1;
  161 }
  162 
  163 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9