[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 5365 - (view) (download) (as text)

1 : dpvc 5328 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 : dpvc 5365 if (sprintf("%p",$self) ne sprintf("%p",$ans->{correct_value})) {
135 : dpvc 5328 $ans->{correct_ans} = $self->string;
136 :     $ans->{correct_value} = $self;
137 :     $ans->{correct_formula} = Value->Package("Formula")->new($self);
138 :     }
139 : dpvc 5365 if (sprintf("%p",$other) ne sprintf("%p",$ans->{student_value})) {
140 : dpvc 5328 $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