--- loncom/homework/caparesponse/caparesponse.pm 2005/06/26 22:21:06 1.170 +++ loncom/homework/caparesponse/caparesponse.pm 2005/11/16 22:52:31 1.181 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # caparesponse definition # -# $Id: caparesponse.pm,v 1.170 2005/06/26 22:21:06 albertel Exp $ +# $Id: caparesponse.pm,v 1.181 2005/11/16 22:52:31 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,11 +36,104 @@ BEGIN { &Apache::lonxml::register('Apache::caparesponse',('caparesponse','numericalresponse','stringresponse','formularesponse')); } +my %answer; +my $cur_name; +sub start_answer { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + $cur_name = &Apache::lonxml::get_param('name',$parstack,$safeeval); + if ($cur_name =~ /^\s*$/) { $cur_name = $Apache::lonxml::curdepth; } + my $type = &Apache::lonxml::get_param('type',$parstack,$safeeval); + if (!defined($type) && $tagstack->[-2] eq 'answergroup') { + $type = &Apache::lonxml::get_param('type',$parstack,$safeeval,-2); + } + if (!defined($type)) { $type = 'ordered' }; + $answer{$cur_name}= { 'type' => $type, + 'answers' => [] }; + return $result; +} + +sub end_answer { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + undef($cur_name); + return $result; +} + +sub start_answergroup { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + my $id = $Apache::inputtags::response[-1]; + my $dis = &Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval); + if (defined($dis)) { $Apache::inputtags::answertxt{$id}=$dis; } + return $result; +} + +sub end_answergroup { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub start_value { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + if ( $target eq 'web' || $target eq 'tex' || + $target eq 'grade' || $target eq 'webgrade' || + $target eq 'answer' || $target eq 'analyze' ) { + my $bodytext = &Apache::lonxml::get_all_text("/value",$parser); + $bodytext = &Apache::run::evaluate($bodytext,$safeeval, + $$parstack[-1]); + push(@{ $answer{$cur_name}{'answers'} },$bodytext); + } + return $result; +} + +sub end_value { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub start_array { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + if ( $target eq 'web' || $target eq 'tex' || + $target eq 'grade' || $target eq 'webgrade' || + $target eq 'answer' || $target eq 'analyze' ) { + my $bodytext = &Apache::lonxml::get_all_text("/value",$parser); + my @values = &Apache::run::evaluate($bodytext,$safeeval, + $$parstack[-1]); + push(@{ $answer{$cur_name}{'answers'} },@values); + } + return $result; +} + +sub end_array { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub start_unit { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub end_unit { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + sub start_numericalresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + &Apache::lonxml::register('Apache::caparesponse',('answer','answergroup','value','array','unit')); my $id = &Apache::response::start_response($parstack,$safeeval); my $result; - undef %{$safeeval->varglob('LONCAPA::CAPAresponse_args')}; + undef(%answer); + undef(%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}); if ($target eq 'edit') { $result.=&Apache::edit::tag_start($target,$token); $result.=&Apache::edit::text_arg('Answer:','answer',$token); @@ -121,7 +214,7 @@ sub start_numericalresponse { } sub check_submission { - my ($response,$partid,$id,$tag,$parstack,$safeeval)=@_; + my ($response,$partid,$id,$tag,$parstack,$safeeval,$ignore_sig)=@_; my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}; $$args_ref{'response'}=$response; my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit'); @@ -142,7 +235,8 @@ sub check_submission { } #sig fig don't make much sense either if (($Apache::lonhomework::type eq 'exam' || - &Apache::response::submitted('scantron')) && + &Apache::response::submitted('scantron') || + $ignore_sig) && $tag eq 'numericalresponse') { delete($$args_ref{'sig'}); } @@ -154,14 +248,31 @@ sub check_submission { } my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); &Apache::lonxml::debug('answer is'.join(':',@answer)); - @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=@answer; - - my ($result,@msgs) = - &Apache::run::run("&caparesponse_check_list()",$safeeval); - &Apache::lonxml::debug('msgs are'.join(':',@msgs)); - my ($awards)=split(/:/,$result); - my @awards= split(/,/,$awards); - return(\@awards,\@msgs); + if (@answer && defined($answer[0])) { + $answer{'INTERNAL'}= {'type' => 'ordered', + 'answers' => \@answer }; + } + #FIXME would be nice if we could save name so we know who graded him + #correct + my (%results,@final_awards,@final_msgs,@names); + foreach my $name (keys(%answer)) { + &Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} })); + @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=@{ $answer{$name}{'answers'} }; + my ($result,@msgs) = + &Apache::run::run("&caparesponse_check_list()",$safeeval); + &Apache::lonxml::debug('msgs are '.join(':',@msgs)); + my ($awards)=split(/:/,$result); + my @awards= split(/,/,$awards); + my ($ad, $msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs); + $results{$name}= [$ad,$msg]; + push(@final_awards,$ad); + push(@final_msgs,$msg); + push(@names,$name); + } + my ($ad, $msg, $name) = &Apache::inputtags::finalizeawards(\@final_awards, + \@final_msgs, + \@names,1); + return($ad,$msg); } sub end_numericalresponse { @@ -184,7 +295,6 @@ sub end_numericalresponse { } else { my $response = &Apache::response::getresponse(); if ( $response =~ /[^\s]/) { - my $ad; my %previous = &Apache::response::check_for_previous($response,$partid,$id); &Apache::lonxml::debug("submitted a $response
\n"); &Apache::lonxml::debug($$parstack[-1] . "\n
"); @@ -200,10 +310,9 @@ sub end_numericalresponse { $response=$values->[$response]; } $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; - my ($awards,$msgs)=&check_submission($response,$partid,$id, - $tag,$parstack,$safeeval); + my ($ad,$msg)=&check_submission($response,$partid,$id, + $tag,$parstack,$safeeval); - ($ad,my $msg) = &Apache::inputtags::finalizeawards($awards,$msgs); &Apache::lonxml::debug('ad is'.$ad); if ($ad eq 'SIG_FAIL') { my ($sig_u,$sig_l)= @@ -329,6 +438,7 @@ sub end_numericalresponse { if ($target eq 'answer') { $result.=&Apache::response::answer_header($tag); } + my ($sigline,$tolline); for(my $i=0;$i<=$#answers;$i++) { my $ans=$answers[$i]; my $fmt=$formats[0]; @@ -351,19 +461,17 @@ sub end_numericalresponse { # $low =&format_number($low,$fmt,$target,$safeeval); #} } - my $response=$ans; - if ($unit) { - my $cleanunit=$unit; - $cleanunit=~s/\$\,//g; - $response.=" $cleanunit"; - } if ($target eq 'answer') { - if ($high && $tag eq 'numericalresponse') { $ans.=' ['.$low.','.$high.']'; } + if ($high && $tag eq 'numericalresponse') { + $ans.=' ['.$low.','.$high.']'; + $tolline .= "[$low, $high]"; + } if (defined($sighigh) && $tag eq 'numericalresponse') { if ($env{'form.answer_output_mode'} eq 'tex') { $ans.= " Sig $siglow - $sighigh"; } else { $ans.= " Sig $siglow - $sighigh"; + $sigline .= "[$siglow, $sighigh]"; } } $result.=&Apache::response::answer_part($tag,$ans); @@ -377,13 +485,57 @@ sub end_numericalresponse { push (@{ $Apache::lonhomework::analyze{"$part_id.format"} }, $fmt); } } - my ($awards,$msgs)=&check_submission($response,$partid,$id,$tag, - $parstack,$safeeval); - my ($ad,$msg) =&Apache::inputtags::finalizeawards($awards,$msgs); + } + + my @fmt_ans; + for(my $i=0;$i<=$#answers;$i++) { + my $ans=$answers[$i]; + my $fmt=$formats[0]; + if (@formats && $#formats) {$fmt=$formats[$i];} + if ($fmt && $tag eq 'numericalresponse') { + $fmt=~s/e/E/g; + if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; } + if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; } + $ans = &format_number($ans,$fmt,$target,$safeeval); + if ($fmt=~/\$/ && $unit!~/\$/) { $ans=~s/\$//; } + } + push(@fmt_ans,$ans); + } + my $response=join(', ',@fmt_ans); + my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'. + $id.'.turnoffunit'); + if ($unit ne '' && + ! ($Apache::lonhomework::type eq 'exam' || + lc($hideunit) eq "yes") ) { + my $cleanunit=$unit; + $cleanunit=~s/\$\,//g; + $response.=" $cleanunit"; + } + + my ($ad,$msg)=&check_submission($response,$partid,$id,$tag, + $parstack,$safeeval); + if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') { + my $error; + if ($tag eq 'formularesponse') { + $error=&mt('Computer\'s answer is incorrect ("[_1]").'); + } else { + # answer failed check if it is sig figs that is failing + my ($ad,$msg)=&check_submission($response,$partid,$id, + $tag,$parstack, + $safeeval,1); + if ($sigline ne '') { + $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] or significant figures [_3] need to be adjusted.',$response,$tolline,$sigline); + } else { + $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] needs to be adjusted.',$response,$tolline); + } + } if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') { - &Apache::lonxml::warning(&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range ("[_2]" to "[_3]") or significant figures ("[_4]" to "[_5]") needs to be adjusted',$response,$low,$high,$siglow,$sighigh)); + &Apache::lonxml::error($error); + } else { + &Apache::lonxml::warning($error); } } + if (defined($unit) and ($unit ne '') and $tag eq 'numericalresponse') { if ($target eq 'answer') { @@ -652,7 +804,7 @@ sub end_stringresponse { # $answer=$token->[2]->{'answer'}; # } ${$safeeval->varglob('LONCAPA::response')}=$response; - $result = &Apache::run::run('return $LONCAPA::response=~m'.$answer,$safeeval); + $result = &Apache::run::run('if ($LONCAPA::response=~m'.$answer.') { return 1; } else { return 0; }',$safeeval); &Apache::lonxml::debug("current $response"); &Apache::lonxml::debug("current $answer"); $ad = ($result) ? 'APPROX_ANS' : 'INCORRECT'; @@ -713,6 +865,10 @@ sub end_stringresponse { # foreach my $ans (@answers) { if ($target eq 'answer') { $result.=&Apache::response::answer_part('stringresponse',$answer); + if ($type eq 're') { + $result.=&Apache::response::answer_part('stringresponse', + $answerdisplay); + } } elsif ($target eq 'analyze') { push (@{ $Apache::lonhomework::analyze{"$part.$id.answer"} }, $answer);