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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5554 - (view) (download) (as text)

1 : dpvc 5328 sub _answerHints_init {}
2 :    
3 : dpvc 5373 =head1 AnswerHints()
4 : dpvc 5328
5 : sh002i 5554 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 : dpvc 5328
10 : sh002i 5554 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 : dpvc 5328 =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 : dpvc 5365 if (sprintf("%p",$self) ne sprintf("%p",$ans->{correct_value})) {
148 : dpvc 5328 $ans->{correct_ans} = $self->string;
149 :     $ans->{correct_value} = $self;
150 :     $ans->{correct_formula} = Value->Package("Formula")->new($self);
151 :     }
152 : dpvc 5365 if (sprintf("%p",$other) ne sprintf("%p",$ans->{student_value})) {
153 : dpvc 5328 $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