[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 6058 - (download) (as text) (annotate)
Thu Jun 25 23:28:44 2009 UTC (10 years, 7 months ago) by gage
File size: 6182 byte(s)
syncing pg HEAD with pg2.4.7 on 6/25/2009

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9