| … | |
… | |
| 106 | |
106 | |
| 107 | # |
107 | # |
| 108 | # Check if types are compatible for equality check |
108 | # Check if types are compatible for equality check |
| 109 | # |
109 | # |
| 110 | sub typeMatch { |
110 | sub typeMatch { |
| 111 | my $self = shift; |
111 | my $self = shift; my $other = shift; |
| 112 | my $other = shift; |
112 | return 1 unless ref($other); |
| 113 | $self->type eq $other->type; |
113 | $self->type eq $other->type; |
| 114 | } |
114 | } |
| 115 | |
115 | |
| 116 | # |
116 | # |
| 117 | # Student answer evaluation failed. |
117 | # Student answer evaluation failed. |
| … | |
… | |
| 165 | ignoreStrings => 1, |
165 | ignoreStrings => 1, |
| 166 | }; |
166 | }; |
| 167 | |
167 | |
| 168 | sub typeMatch { |
168 | sub typeMatch { |
| 169 | my $self = shift; my $other = shift; my $ans = shift; |
169 | my $self = shift; my $other = shift; my $ans = shift; |
| 170 | return 1 if !ref($other); |
170 | return 1 unless ref($other); |
| 171 | if ($other->type eq 'String' && $ans->{ignoreStrings}) { |
171 | if ($other->type eq 'String' && $ans->{ignoreStrings}) { |
| 172 | $ans->{showEqualErrors} = 0; |
172 | $ans->{showEqualErrors} = 0; |
| 173 | return 1; |
173 | return 1; |
| 174 | } |
174 | } |
| 175 | $self->type eq $other->type; |
175 | $self->type eq $other->type; |
| … | |
… | |
| 184 | showDimensionWarnings => 1, |
184 | showDimensionWarnings => 1, |
| 185 | }; |
185 | }; |
| 186 | |
186 | |
| 187 | sub typeMatch { |
187 | sub typeMatch { |
| 188 | my $self = shift; my $other = shift; my $ans = shift; |
188 | my $self = shift; my $other = shift; my $ans = shift; |
|
|
189 | return 0 unless ref($other); |
| 189 | return 0 unless $other->type eq 'Point'; |
190 | return 0 unless $other->type eq 'Point'; |
| 190 | if (!$ans->{isPreview} && $ans->{showDimensionWarnings} && |
191 | if (!$ans->{isPreview} && $ans->{showDimensionWarnings} && |
| 191 | $self->length != $other->length) { |
192 | $self->length != $other->length) { |
| 192 | $ans->{ans_message} = $ans->{error_message} = "The dimension is incorrect"; |
193 | $ans->{ans_message} = $ans->{error_message} = "The dimension is incorrect"; |
| 193 | return 0; |
194 | return 0; |
| … | |
… | |
| 208 | cmp_postprocess => 'cmp_postprocess', |
209 | cmp_postprocess => 'cmp_postprocess', |
| 209 | }; |
210 | }; |
| 210 | |
211 | |
| 211 | sub typeMatch { |
212 | sub typeMatch { |
| 212 | my $self = shift; my $other = shift; my $ans = shift; |
213 | my $self = shift; my $other = shift; my $ans = shift; |
|
|
214 | return 0 unless ref($other); |
| 213 | return 0 unless $other->type eq 'Vector' || |
215 | return 0 unless $other->type eq 'Vector' || |
| 214 | ($ans->{promotePoints} && $other->type eq 'Point'); |
216 | ($ans->{promotePoints} && $other->type eq 'Point'); |
| 215 | if (!$ans->{isPreview} && $ans->{showDimensionWarnings} && |
217 | if (!$ans->{isPreview} && $ans->{showDimensionWarnings} && |
| 216 | $self->length != $other->length) { |
218 | $self->length != $other->length) { |
| 217 | $ans->{ans_message} = $ans->{error_message} = "The dimension is incorrect"; |
219 | $ans->{ans_message} = $ans->{error_message} = "The dimension is incorrect"; |
| … | |
… | |
| 240 | showDimensionWarnings => 1, |
242 | showDimensionWarnings => 1, |
| 241 | }; |
243 | }; |
| 242 | |
244 | |
| 243 | sub typeMatch { |
245 | sub typeMatch { |
| 244 | my $self = shift; my $other = shift; my $ans = shift; |
246 | my $self = shift; my $other = shift; my $ans = shift; |
|
|
247 | return 0 unless ref($other); |
| 245 | $other = $self->make($other->{data}) if $other->class eq 'Point'; |
248 | $other = $self->make($other->{data}) if $other->class eq 'Point'; |
| 246 | return 0 unless $other->type eq 'Matrix'; |
249 | return 0 unless $other->type eq 'Matrix'; |
| 247 | return 1 unless $ans->{showDimensionWarnings}; |
250 | return 1 unless $ans->{showDimensionWarnings}; |
| 248 | my @d1 = $self->dimensions; my @d2 = $other->dimensions; |
251 | my @d1 = $self->dimensions; my @d2 = $other->dimensions; |
| 249 | if (scalar(@d1) != scalar(@d2)) { |
252 | if (scalar(@d1) != scalar(@d2)) { |
| … | |
… | |
| 268 | |
271 | |
| 269 | ## @@@ report interval-type mismatch? @@@ |
272 | ## @@@ report interval-type mismatch? @@@ |
| 270 | |
273 | |
| 271 | sub typeMatch { |
274 | sub typeMatch { |
| 272 | my $self = shift; my $other = shift; |
275 | my $self = shift; my $other = shift; |
|
|
276 | return 0 unless ref($other); |
| 273 | return $other->length == 2 && |
277 | return $other->length == 2 && |
| 274 | ($other->{open} eq '(' || $other->{open} eq '[') && |
278 | ($other->{open} eq '(' || $other->{open} eq '[') && |
| 275 | ($other->{close} eq ')' || $other->{close} eq ']') |
279 | ($other->{close} eq ')' || $other->{close} eq ']') |
| 276 | if $other->type =~ m/^(Point|List)$/; |
280 | if $other->type =~ m/^(Point|List)$/; |
| 277 | $other->type =~ m/^(Interval|Union)$/; |
281 | $other->type =~ m/^(Interval|Union)$/; |
| … | |
… | |
| 281 | |
285 | |
| 282 | package Value::Union; |
286 | package Value::Union; |
| 283 | |
287 | |
| 284 | sub typeMatch { |
288 | sub typeMatch { |
| 285 | my $self = shift; my $other = shift; |
289 | my $self = shift; my $other = shift; |
|
|
290 | return 0 unless ref($other); |
| 286 | return $other->length == 2 && |
291 | return $other->length == 2 && |
| 287 | ($other->{open} eq '(' || $other->{open} eq '[') && |
292 | ($other->{open} eq '(' || $other->{open} eq '[') && |
| 288 | ($other->{close} eq ')' || $other->{close} eq ']') |
293 | ($other->{close} eq ')' || $other->{close} eq ']') |
| 289 | if $other->type =~ m/^(Point|List)$/; |
294 | if $other->type =~ m/^(Point|List)$/; |
| 290 | $other->type =~ m/^(Interval|Union)/; |
295 | $other->type =~ m/^(Interval|Union)/; |
| … | |
… | |
| 338 | $maxscore = $m if ($m > $maxscore); |
343 | $maxscore = $m if ($m > $maxscore); |
| 339 | my $score = 0; my @errors; my $i = 0; |
344 | my $score = 0; my @errors; my $i = 0; |
| 340 | |
345 | |
| 341 | ENTRY: foreach my $entry (@student) { |
346 | ENTRY: foreach my $entry (@student) { |
| 342 | $i++; |
347 | $i++; |
|
|
348 | $entry = Value::Real->make($entry) if !ref($entry) && Value::matchNumber($entry); |
|
|
349 | $entry = Value::Formula->new($entry) if !Value::isValue($entry); |
| 343 | if ($ordered) { |
350 | if ($ordered) { |
| 344 | if (eval {shift(@correct) == $entry}) {$score++; next ENTRY} |
351 | if (eval {shift(@correct) == $entry}) {$score++; next ENTRY} |
| 345 | } else { |
352 | } else { |
| 346 | foreach my $k (0..$#correct) { |
353 | foreach my $k (0..$#correct) { |
| 347 | if (eval {$correct[$k] == $entry}) { |
354 | if (eval {$correct[$k] == $entry}) { |
| … | |
… | |
| 352 | } |
359 | } |
| 353 | if ($showTypeWarnings && defined($typeMatch) && |
360 | if ($showTypeWarnings && defined($typeMatch) && |
| 354 | !$typeMatch->typeMatch($entry,$ans)) { |
361 | !$typeMatch->typeMatch($entry,$ans)) { |
| 355 | push(@errors, |
362 | push(@errors, |
| 356 | "Your ".NameForNumber($i)." value isn't ".lc($typeMatch->showClass). |
363 | "Your ".NameForNumber($i)." value isn't ".lc($typeMatch->showClass). |
| 357 | " (it looks like ".lc(Value::showClass($entry)).")"); |
364 | " (it looks like ".lc($entry->showClass).")"); |
| 358 | next ENTRY; |
365 | next ENTRY; |
| 359 | } |
366 | } |
| 360 | push(@errors,"Your ".NameForNumber($i)." $value is incorrect") |
367 | push(@errors,"Your ".NameForNumber($i)." $value is incorrect") |
| 361 | if $showHints && $m > 1; |
368 | if $showHints && $m > 1; |
| 362 | } |
369 | } |