[system] / trunk / pg / lib / Value / AnswerChecker.pm Repository:
ViewVC logotype

Diff of /trunk/pg/lib/Value/AnswerChecker.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 2647 Revision 2648
23 ignoreStrings => 1, 23 ignoreStrings => 1,
24)} 24)}
25 25
26sub cmp { 26sub cmp {
27 my $self = shift; 27 my $self = shift;
28 $$Value::context->flags->set(StringifyAsTeX => 0); # reset this, just in case.
29 my $ans = new AnswerEvaluator; 28 my $ans = new AnswerEvaluator;
30 $ans->ans_hash( 29 $ans->ans_hash(
31 type => "Value (".$self->class.")", 30 type => "Value (".$self->class.")",
32 correct_ans => $self->string, 31 correct_ans => $self->string,
33 correct_value => $self, 32 correct_value => $self,
34 $self->cmp_defaults, 33 $self->cmp_defaults,
35 @_ 34 @_
36 ); 35 );
37 $ans->install_evaluator( 36 $ans->install_evaluator(sub {$ans = shift; $ans->{correct_value}->cmp_parse($ans)});
38 sub { 37 $self->{context} = $$Value::context unless defined($self->{context});
39 my $ans = shift;
40 # can't seem to get $inputs_ref any other way
41 $ans->{isPreview} = $self->getPG('$inputs_ref->{previewAnswers}');
42 my $self = $ans->{correct_value};
43 my $method = $ans->{cmp_check} || 'cmp_check';
44 $ans->{cmp_class} = $self->cmp_class($ans) unless $ans->{cmp_class};
45 $self->$method($ans);
46 }
47 );
48 return $ans; 38 return $ans;
49} 39}
50 40
51# 41#
52# Parse the student answer and compute its value, 42# Parse the student answer and compute its value,
53# produce the preview strings, and then compare the 43# produce the preview strings, and then compare the
54# student and professor's answers for equality. 44# student and professor's answers for equality.
55# 45#
56sub cmp_check { 46sub cmp_parse {
57 my $self = shift; my $ans = shift; 47 my $self = shift; my $ans = shift;
58 # 48 #
59 # Methods to call 49 # Do some setup
60 # 50 #
61 my $cmp_equal = $ans->{cmp_equal} || 'cmp_equal'; 51 my $context = $$Value::context; # save it for later
62 my $cmp_error = $ans->{cmp_error} || 'cmp_error'; 52 Parser::Context->current(undef,$self->{context}); # change to object's context
63 my $cmp_postprocess = $ans->{cmp_postprocess} || 'cmp_postprocess'; 53 $context->flags->set(StringifyAsTeX => 0); # reset this, just in case.
54 $ans->{isPreview} = $self->getPG('$inputs_ref->{previewAnswers}');
55 $ans->{cmp_class} = $self->cmp_class($ans) unless $ans->{cmp_class};
56
64 # 57 #
65 # Parse and evaluate the student answer 58 # Parse and evaluate the student answer
66 # 59 #
67 $ans->score(0); # assume failure 60 $ans->score(0); # assume failure
68 $ans->{student_value} = $ans->{student_formula} = Parser::Formula($ans->{student_ans}); 61 $ans->{student_value} = $ans->{student_formula} = Parser::Formula($ans->{student_ans});
69 $ans->{student_value} = Parser::Evaluate($ans->{student_formula}) 62 $ans->{student_value} = Parser::Evaluate($ans->{student_formula})
70 if defined($ans->{student_formula}) && $ans->{student_formula}->isConstant; 63 if defined($ans->{student_formula}) && $ans->{student_formula}->isConstant;
64
71 # 65 #
72 # If it parsed OK, save the output forms and check if it is correct 66 # If it parsed OK, save the output forms and check if it is correct
73 # otherwise report an error 67 # otherwise report an error
74 # 68 #
75 if (defined $ans->{student_value}) { 69 if (defined $ans->{student_value}) {
76 $ans->{student_value} = Value::Formula->new($ans->{student_value}) 70 $ans->{student_value} = Value::Formula->new($ans->{student_value})
77 unless Value::isValue($ans->{student_value}); 71 unless Value::isValue($ans->{student_value});
78 $ans->{preview_latex_string} = $ans->{student_formula}->TeX; 72 $ans->{preview_latex_string} = $ans->{student_formula}->TeX;
79 $ans->{preview_text_string} = $ans->{student_formula}->string; 73 $ans->{preview_text_string} = protectHTML($ans->{student_formula}->string);
80 $ans->{student_ans} = $ans->{preview_text_string}; 74 $ans->{student_ans} = $ans->{preview_text_string};
81 $self->$cmp_equal($ans); 75 $self->cmp_equal($ans);
82 $self->$cmp_postprocess($ans) if !$ans->{error_message}; 76 $self->cmp_postprocess($ans) if !$ans->{error_message};
83 } else { 77 } else {
84 $self->$cmp_error($ans); 78 $self->cmp_error($ans);
85 } 79 }
80 Parser::Context->current(undef,$context); # put back the old context
86 return $ans; 81 return $ans;
87} 82}
88 83
89# 84#
90# Check if the parsed student answer equals the professor's answer 85# Check if the parsed student answer equals the professor's answer
94 my $correct = $ans->{correct_value}; 89 my $correct = $ans->{correct_value};
95 my $student = $ans->{student_value}; 90 my $student = $ans->{student_value};
96 if ($correct->typeMatch($student,$ans)) { 91 if ($correct->typeMatch($student,$ans)) {
97 my $equal = eval {$correct == $student}; 92 my $equal = eval {$correct == $student};
98 if (defined($equal) || !$ans->{showEqualErrors}) {$ans->score(1) if $equal; return} 93 if (defined($equal) || !$ans->{showEqualErrors}) {$ans->score(1) if $equal; return}
99 my $cmp_error = $ans->{cmp_error} || 'cmp_error';
100 $self->$cmp_error($ans); 94 $self->cmp_error($ans);
101 } else { 95 } else {
102 return if $ans->{ignoreStrings} && (!Value::isValue($student) || $student->type eq 'String'); 96 return if $ans->{ignoreStrings} && (!Value::isValue($student) || $student->type eq 'String');
103 $ans->{ans_message} = $ans->{error_message} = 97 $ans->{ans_message} = $ans->{error_message} =
104 "Your answer isn't ".lc($ans->{cmp_class}). 98 "Your answer isn't ".lc($ans->{cmp_class}).
105 " (it looks like ".lc($student->showClass).")" 99 " (it looks like ".lc($student->showClass).")"
205)} 199)}
206 200
207sub typeMatch { 201sub typeMatch {
208 my $self = shift; my $other = shift; my $ans = shift; 202 my $self = shift; my $other = shift; my $ans = shift;
209 return 1 unless ref($other); 203 return 1 unless ref($other);
210 return 0 if $other->class eq 'Formula'; 204 return 0 if Value::isFormula($other);
211 return 1 if $other->type eq 'Infinity' && $ans->{ignoreInfinity}; 205 return 1 if $other->type eq 'Infinity' && $ans->{ignoreInfinity};
212 $self->type eq $other->type; 206 $self->type eq $other->type;
213} 207}
214 208
215############################################################# 209#############################################################
219sub cmp_class {'a Number'}; 213sub cmp_class {'a Number'};
220 214
221sub typeMatch { 215sub typeMatch {
222 my $self = shift; my $other = shift; my $ans = shift; 216 my $self = shift; my $other = shift; my $ans = shift;
223 return 1 unless ref($other); 217 return 1 unless ref($other);
224 return 0 if $other->class eq 'Formula'; 218 return 0 if Value::isFormula($other);
225 return 1 if $other->type eq 'Number'; 219 return 1 if $other->type eq 'Number';
226 $self->type eq $other->type; 220 $self->type eq $other->type;
227} 221}
228 222
229############################################################# 223#############################################################
241 return $typeMatch->cmp_class; 235 return $typeMatch->cmp_class;
242}; 236};
243 237
244sub typeMatch { 238sub typeMatch {
245 my $self = shift; my $other = shift; my $ans = shift; 239 my $self = shift; my $other = shift; my $ans = shift;
246 return 0 if ref($other) && $other->class eq 'Formula'; 240 return 0 if ref($other) && Value::isFormula($other);
247 my $typeMatch = $ans->{typeMatch}; 241 my $typeMatch = $ans->{typeMatch};
248 return 1 if !Value::isValue($typeMatch) || $typeMatch->class eq 'String' || 242 return 1 if !Value::isValue($typeMatch) || $typeMatch->class eq 'String' ||
249 $self->type eq $other->type; 243 $self->type eq $other->type;
250 return $typeMatch->typeMatch($other,$ans); 244 return $typeMatch->typeMatch($other,$ans);
251} 245}
508 my @correct = (); 502 my @correct = ();
509 if ($self->class ne 'Formula') {@correct = $self->value} 503 if ($self->class ne 'Formula') {@correct = $self->value}
510 else {@correct = Value::List->splitFormula($self,$ans)} 504 else {@correct = Value::List->splitFormula($self,$ans)}
511 my $student = $ans->{student_value}; 505 my $student = $ans->{student_value};
512 my @student = ($student); 506 my @student = ($student);
513 if ($student->class eq 'Formula' && $student->type eq $self->type) { 507 if (Value::isFormula($student) && $student->type eq $self->type) {
514 @student = Value::List->splitFormula($student,$ans); 508 @student = Value::List->splitFormula($student,$ans);
515 } elsif ($student->class ne 'Formula' && $student->class eq $self->type && 509 } elsif ($student->class ne 'Formula' && $student->class eq $self->type &&
516 ($allowParens || (!$student->{open} && !$student->{close}))) { 510 ($allowParens || (!$student->{open} && !$student->{close}))) {
517 @student = @{$student->{data}}; 511 @student = @{$student->{data}};
518 } 512 }
598 push(@formula,$v); 592 push(@formula,$v);
599 # 593 #
600 # There shouldn't be an error evaluating the formula, 594 # There shouldn't be an error evaluating the formula,
601 # but you never know... 595 # but you never know...
602 # 596 #
603 if (!defined($v)) { 597 if (!defined($v)) {$ans->{split_error} = 1; $self->cmp_error; return}
604 $ans->{split_error} = 1;
605 my $cmp_error = $ans->{cmp_error} || 'cmp_error';
606 $self->$cmp_error; return;
607 }
608 } 598 }
609 return @formula; 599 return @formula;
610} 600}
611 601
612# 602#
645# 635#
646sub typeMatch { 636sub typeMatch {
647 my $self = shift; my $other = shift; my $ans = shift; 637 my $self = shift; my $other = shift; my $ans = shift;
648 return 1 if $self->type eq $other->type; 638 return 1 if $self->type eq $other->type;
649 my $typeMatch = ($self->createRandomPoints(1))[1]->[0]; 639 my $typeMatch = ($self->createRandomPoints(1))[1]->[0];
650 $other = eval {($other->createRandomPoints(1))[1]->[0]} if ($other->class eq 'Formula'); 640 $other = eval {($other->createRandomPoints(1))[1]->[0]} if Value::isFormula($other);
651 return 1 unless defined($other); # can't really tell, so don't report type mismatch 641 return 1 unless defined($other); # can't really tell, so don't report type mismatch
652 $typeMatch->typeMatch($other,$ans); 642 $typeMatch->typeMatch($other,$ans);
653} 643}
654 644
655# 645#

Legend:
Removed from v.2647  
changed lines
  Added in v.2648

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9