[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 5328 - (download) (as text) (annotate)
Wed Aug 15 03:58:26 2007 UTC (12 years, 5 months ago) by dpvc
File size: 6023 byte(s)
This file implements a postfilter for AnswerEvaluators that allows you
to specify answer hint messages to use when specific answers or sets
of answers are given by the student.  You can use specific constants
or a perl subroutine to determine which answers to respond to.  You
can also specify a score to use when the answers are triggered, and
whether to replace existing messages or not.  See the comments in the
file for more details.

    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 my $noValueRef = ! defined &{\&{Value::Ref}};
  127 #
  128 #  Calls the answer checker on two values with a copy of the answer hash
  129 #  and returns true if the two values match and false otherwise.
  130 #
  131 sub Compare {
  132   my $self = shift; my $other = shift; my $ans = shift;
  133   $ans = bless {%{$ans},@_}, ref($ans);  # make a copy
  134   $ans->{typeError} = 0; $ans->{ans_message} = $ans->{error_message} = ""; $ans->{score} = 0;
  135   if ($noValueRef || Value::Ref($self) != Value::Ref($ans->{correct_value})) {
  136     $ans->{correct_ans} = $self->string;
  137     $ans->{correct_value} = $self;
  138     $ans->{correct_formula} = Value->Package("Formula")->new($self);
  139   }
  140   if ($noValueRef || Value::Ref($other) != Value::Ref($ans->{student_value})) {
  141     $ans->{student_ans} = $other->string;
  142     $ans->{student_value} = $other;
  143     $ans->{student_formula} = Value->Package("Formula")->new($other);
  144   }
  145   $self->cmp_preprocess($ans);
  146   $self->cmp_equal($ans);
  147   $self->cmp_postprocess($ans) if !$ans->{error_message} && !$ans->{typeError};
  148   return $ans->{score} >= 1;
  149 }
  150 
  151 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9