Parent Directory
|
Revision Log
Use alternative method of testing if whether two objects are the same (without causing them to stringify first). [Technically, this should call Value::address, the renamed version of Value::Ref, but I didn't want the AIM participants to have to update to the latests version of MathObjects to be able to use this.]
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 # 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 if (sprintf("%p",$self) ne sprintf("%p",$ans->{correct_value})) { 135 $ans->{correct_ans} = $self->string; 136 $ans->{correct_value} = $self; 137 $ans->{correct_formula} = Value->Package("Formula")->new($self); 138 } 139 if (sprintf("%p",$other) ne sprintf("%p",$ans->{student_value})) { 140 $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 |