Parent Directory
|
Revision Log
Revision 5328 - (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 : | 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 |