[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 5373 - (download) (as text) (annotate)
Sun Aug 19 02:01:57 2007 UTC (12 years, 3 months ago) by dpvc
File size: 6027 byte(s)
Normalized comments and headers to that they will format their POD
documentation properly.  (I know that the POD processing was supposed
to strip off the initial #, but that doesn't seem to happen, so I've
added a space throughout.)

    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  #      checkCorrect => 0 or 1      1 means check for messages even
   27  #                                  if the answer is correct.
   28  #                                      Default: 0
   29  #
   30  #      replaceMessage => 0 or 1    1 means it's OK to repalce any
   31  #                                  message that is already in place
   32  #                                  in the answer hash.
   33  #                                      Default: 0
   34  #
   35  #      checkTypes => 0 or 1        1 means only perform the test
   36  #                                  if the student answer is the
   37  #                                  same type as the correct one.
   38  #                                      Default: 1
   39  #
   40  #      score => number             Specifies the score to use if
   41  #                                  the message is triggered (so that
   42  #                                  partial credit can be given).
   43  #                                      Default: keep original score
   44  #
   45  #      cmp_options => [...]        provides options for the cmp routine
   46  #                                  used to check if the student answer
   47  #                                  matches these answers.
   48  #                                     Default: []
   49  #
   50  #  If more than one message matches the student's answer, the first
   51  #  one in the list is used.
   52  #
   53  #  Example:
   54  #
   55  #    ANS(Vector(1,2,3)->cmp(showCoordinateHints=>0)->withPostFilter(AnswerHints(
   56  #      Vector(0,0,0) => "The zero vector is not a valid solution",
   57  #      "-<1,2,3>" => "Try the opposite direction",
   58  #      "<1,2,3>" => "Well done!",
   59  #      ["<1,1,1>","<2,2,2>","<3,3,3>"] => "Don't just guess!",
   60  #      sub {
   61  #        my ($correct,$student,$ans) = @_;
   62  #        return $correct . $student == 0;
   63  #      } => "Your answer is perpendicular to the correct one",
   64  #      Vector(1,2,3) => [
   65  #        "You have the right direction, but not length",
   66  #        cmp_options => [parallel=>1],
   67  #      ],
   68  #      0 => ["Careful, your answer should be a vector!", checkTypes => 0, replaceMessage => 1],
   69  #      sub {
   70  #        my ($correct,$student,$ans) = @_;
   71  #        return norm($correct-$student) < .1;
   72  #      } => ["Close!  Keep trying.", score => .25],
   73  #    )));
   74  #
   75 
   76 =cut
   77 
   78 sub AnswerHints {
   79   return (sub {
   80     my $ans = shift; $ans->{_filter_name} = "Answer Hints Post Filter";
   81     my $correct = $ans->{correct_value};
   82     my $student = $ans->{student_value};
   83     Value::Error("AnswerHints can only be used with MathObjects answer checkers") unless ref($correct);
   84     return $ans unless ref($student);
   85 
   86     while (@_) {
   87       my $wrongList = shift; my $message = shift; my @options;
   88       ($message,@options) = @{$message} if ref($message) eq 'ARRAY';
   89       my %options = (
   90         checkCorrect => 0,
   91         replaceMessage => 0,
   92   checkTypes => 1,
   93         score => undef,
   94         cmp_options => [],
   95         @options,
   96       );
   97       next if $options{checkType} && $correct->type ne $student->type;
   98       $wrongList = [$wrongList] unless ref($wrongList) eq 'ARRAY';
   99       foreach my $wrong (@{$wrongList}) {
  100   if (ref($wrong) eq 'CODE') {
  101     if (($ans->{score} < 1 || $options{checkCorrect}) &&
  102         ($ans->{ans_message} eq "" || $options{replaceMessage}) &&
  103         &$wrong($correct,$student,$ans)) {
  104       $ans->{ans_message} = $ans->{error_message} = $message;
  105       $ans->{score} = $options{score} if defined $options{score};
  106       last;
  107     }
  108   } else {
  109     $wrong = Value::makeValue($wrong);
  110     if (($ans->{score} < 1 || $options{checkCorrect} || AnswerHints::Compare($correct,$wrong,$ans)) &&
  111         ($ans->{ans_message} eq "" || $options{replaceMessage}) &&
  112         AnswerHints::Compare($wrong,$student,$ans,@{$options{cmp_options}})) {
  113       $ans->{ans_message} = $ans->{error_message} = $message;
  114       $ans->{score} = $options{score} if defined $options{score};
  115       last;
  116     }
  117   }
  118       }
  119     }
  120     return $ans;
  121   },@_);
  122 }
  123 
  124 package AnswerHints;
  125 
  126 #
  127 #  Calls the answer checker on two values with a copy of the answer hash
  128 #  and returns true if the two values match and false otherwise.
  129 #
  130 sub Compare {
  131   my $self = shift; my $other = shift; my $ans = shift;
  132   $ans = bless {%{$ans},@_}, ref($ans);  # make a copy
  133   $ans->{typeError} = 0; $ans->{ans_message} = $ans->{error_message} = ""; $ans->{score} = 0;
  134   if (sprintf("%p",$self) ne sprintf("%p",$ans->{correct_value})) {
  135     $ans->{correct_ans} = $self->string;
  136     $ans->{correct_value} = $self;
  137     $ans->{correct_formula} = Value->Package("Formula")->new($self);
  138   }
  139   if (sprintf("%p",$other) ne sprintf("%p",$ans->{student_value})) {
  140     $ans->{student_ans} = $other->string;
  141     $ans->{student_value} = $other;
  142     $ans->{student_formula} = Value->Package("Formula")->new($other);
  143   }
  144   $self->cmp_preprocess($ans);
  145   $self->cmp_equal($ans);
  146   $self->cmp_postprocess($ans) if !$ans->{error_message} && !$ans->{typeError};
  147   return $ans->{score} >= 1;
  148 }
  149 
  150 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9