File:  [LON-CAPA] / loncom / homework / caparesponse / caparesponse.pm
Revision 1.117: download - view: text, annotated - select for diffs
Thu Oct 23 07:31:52 2003 UTC (20 years, 7 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- implements the ability to specify incorrect answers fr bubble mode,
  supports overspecifying and exactly specifying the correct number of answers
  (in the underspecified mode it currently punts and ignores the incorrect, ideas on what to do are apprec
iated)
-  supports a number of bubbles option

    1: # The LearningOnline Network with CAPA
    2: # caparesponse definition
    3: #
    4: # $Id: caparesponse.pm,v 1.117 2003/10/23 07:31:52 albertel Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: 
   29: package Apache::caparesponse;
   30: use strict;
   31: use capa;
   32: 
   33: BEGIN {
   34:     &Apache::lonxml::register('Apache::caparesponse',('caparesponse','numericalresponse','stringresponse','formularesponse'));
   35: }
   36: 
   37: sub start_numericalresponse {
   38:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
   39:     my $id = &Apache::response::start_response($parstack,$safeeval);
   40:     my $result;
   41:     if ($target eq 'edit') {
   42: 	$result.=&Apache::edit::tag_start($target,$token);
   43: 	$result.=&Apache::edit::text_arg('Answer:','answer',$token);
   44: 	$result.=&Apache::edit::text_arg('Incorrect Answers:','incorrect',
   45: 					 $token);
   46: 	if ($token->[1] eq 'numericalresponse') {
   47: 	    $result.=&Apache::edit::text_arg('Unit:','unit',$token,5).
   48: 		&Apache::loncommon::help_open_topic('Physical_Units');
   49: 	    $result.=&Apache::edit::text_arg('Format:','format',$token,4).
   50: 		&Apache::loncommon::help_open_topic('Numerical_Response_Format');
   51: 	} elsif ($token->[1] eq 'stringresponse') {
   52: 	    $result.=&Apache::edit::select_arg('Type:','type',
   53: 			 [['cs','Case Sensitive'],['ci','Case Insensitive'],
   54: 			  ['mc','Case Insensitive, Any Order']],$token);
   55: 	} elsif ($token->[1] eq 'formularesponse') {
   56: 	    $result.=&Apache::edit::text_arg('Sample Points:','samples',
   57: 					     $token,40).
   58: 	      &Apache::loncommon::help_open_topic('Formula_Response_Sampling');
   59: 	}
   60: 	$result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
   61:     } elsif ($target eq 'modified') {
   62: 	my $constructtag;
   63: 	if ($token->[1] eq 'numericalresponse') {
   64: 	    $constructtag=&Apache::edit::get_new_args($token,$parstack,
   65: 						      $safeeval,'answer',
   66: 						      'incorrect','unit',
   67: 						      'format');
   68: 	} elsif ($token->[1] eq 'stringresponse') {
   69: 	    $constructtag=&Apache::edit::get_new_args($token,$parstack,
   70: 						      $safeeval,'answer',
   71: 						      'type');
   72: 	} elsif ($token->[1] eq 'formularesponse') {
   73: 	    $constructtag=&Apache::edit::get_new_args($token,$parstack,
   74: 						      $safeeval,'answer',
   75: 						      'samples');
   76: 	}
   77: 	if ($constructtag) {
   78: 	    $result = &Apache::edit::rebuild_tag($token);
   79: 	    $result.=&Apache::edit::handle_insert();
   80: 	}
   81:     } elsif ($target eq 'meta') {
   82: 	$result=&Apache::response::meta_package_write('numericalresponse');
   83:     } elsif ($target eq 'answer' || $target eq 'grade') {
   84: 	&Apache::response::reset_params();
   85:     } elsif ($target eq 'web') {
   86: 	my $partid = $Apache::inputtags::part;
   87: 	my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit');
   88: 	&Apache::lonxml::debug("Got unit $hideunit for $partid $id");
   89: 	#no way to enter units, with radio buttons
   90: 	if (lc($hideunit) eq "yes") {
   91: 	    my $unit=&Apache::lonxml::get_param_var('unit',$parstack,
   92: 						    $safeeval);
   93: 	    if ($unit =~ /\S/) { $result.=" (in $unit) "; }
   94: 	}
   95:     }
   96:     return $result;
   97: }
   98: 
   99: sub end_numericalresponse {
  100:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
  101:     my $increment=1;
  102:     my $result = '';
  103:     if (!$Apache::lonxml::default_homework_loaded) {
  104: 	&Apache::lonxml::default_homework_load($safeeval);
  105:     }
  106:     if ( $target eq 'grade' && defined($ENV{'form.submitted'})) {
  107: 	&Apache::response::setup_params($$tagstack[-1]);
  108: 	$safeeval->share_from('capa',['&caparesponse_capa_check_answer']);
  109: 	my $partid = $Apache::inputtags::part;
  110: 	my $id = $Apache::inputtags::response['-1'];
  111: 	if ($Apache::lonhomework::type eq 'exam' && 
  112: 	    ($$tagstack[-1] eq 'formularesponse' ||
  113: 	     $$tagstack[-1] eq 'stringresponse')) {
  114: 	    $increment=&Apache::response::scored_response($partid,$id);
  115: 	} else {
  116: 	    my $response = &Apache::response::getresponse();
  117: 	    if ( $response =~ /[^\s]/) {
  118: 		my $ad;
  119: 		my %previous = &Apache::response::check_for_previous($response,$partid,$id);
  120: 		&Apache::lonxml::debug("submitted a $response<br>\n");
  121: 		&Apache::lonxml::debug($$parstack[-1] . "\n<br>");
  122: 		
  123: 		if ($ENV{'form.submitted'} eq 'scantron') {
  124: 		    my $number_of_bubbles = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.numbubbles');
  125: 		    if (!$number_of_bubbles) { $number_of_bubbles=8; }
  126: 		    my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval);
  127: 		    my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
  128: 		    my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval);
  129: 		    my @values=&make_numerical_bubbles($number_of_bubbles,$target,$answers[0],$formats[0],\@incorrect);
  130: 		    $response=$values[$response];
  131: 		} else {
  132: 		    $response =~ s/\\/\\\\/g;
  133: 		    $response =~ s/\'/\\\'/g;
  134: 		}
  135: 		$Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;
  136: 		&Apache::lonxml::debug("current $response");
  137: 		my $expression="&caparesponse_check_list('".$response."','".
  138: 		    $$parstack[-1];
  139: 		my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit');
  140: 		#no way to enter units, with radio buttons
  141: 		if ($Apache::lonhomework::type eq 'exam' ||
  142: 		    lc($hideunit) eq "yes") {
  143: 		    $expression.=';my $unit=undef;';
  144: 		}
  145: 		foreach my $key (keys(%Apache::inputtags::params)) {
  146: 		    $expression.= ';my $'. #'
  147: 			$key.'="'.$Apache::inputtags::params{$key}.'"';
  148: 		}
  149: 		if ($$tagstack[-1] eq 'formularesponse') {
  150: 		    $expression.=';my $type="fml";';
  151: 		} elsif ($$tagstack[-1] eq 'numericalresponse') {
  152: 		    $expression.=';my $type="float";';
  153: 		}
  154: 		$expression.="');";
  155: 		my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
  156: 		&Apache::lonxml::debug('answer is'.join(':',@answer));
  157: 		@{$safeeval->varglob('CAPARESPONSE_CHECK_LIST_answer')}=@answer;
  158: 		
  159: 		$result = &Apache::run::run($expression,$safeeval);
  160: 		my ($awards) = split /:/ , $result;
  161: 		($ad) = &Apache::inputtags::finalizeawards(split /,/ , $awards);
  162: 		&Apache::lonxml::debug("$expression");
  163: 		&Apache::lonxml::debug("\n<br>result:$result:$Apache::lonxml::curdepth<br>\n");
  164: 		&Apache::response::handle_previous(\%previous,$ad);
  165: 		$Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;
  166: 		$result='';
  167: 	    }
  168: 	}
  169:     } elsif ($target eq 'web' || $target eq 'tex') {
  170: 	my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,
  171: 						     $safeeval);
  172: 	my $award = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.solved"};
  173: 	my $status = $Apache::inputtags::status['-1'];
  174: 	if (  &Apache::response::show_answer() ) {
  175: 	    my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,
  176: 							 $safeeval);
  177: 	    my $unit=&Apache::lonxml::get_param_var('unit',$parstack,
  178: 						    $safeeval);
  179: 	    if ($target eq 'web') {
  180: 		$result="<br />The correct answer is ";
  181: 	    }
  182: 	    for (my $i=0; $i <= $#answers; $i++) {
  183: 		my $answer=$answers[$i];
  184: 		my $format;
  185: 		if ($#formats > 0) {
  186: 		    $format=$formats[$i];
  187: 		} else {
  188: 		    $format=$formats[0];
  189: 		}
  190: 		my $formatted;
  191: 		if ((defined($format)) && ($format ne '')) {
  192: 		    $format=~s/e/E/g;
  193: 		    &Apache::lonxml::debug("formatting with :$format: answer :$answer:");
  194: 		    $formatted=sprintf('%.'.$format,$answer).',';
  195: 		} else {
  196: 		    &Apache::lonxml::debug("no format answer :$answer:");
  197: 		    $formatted="$answer,";
  198: 		}
  199: 		if ($target eq 'tex') {
  200: 		    $formatted='';
  201: 		    #$formatted=&Apache::lonxml::latex_special_symbols($formatted);
  202: 		}
  203: 		$result.=$formatted;
  204: 	    }
  205: 	    chop $result;
  206: 	    if ($target eq 'web') {
  207: 		$result.=" $unit.<br />";
  208: 	    }
  209: 	}
  210: 	if ($Apache::lonhomework::type eq 'exam') {
  211: 	    my $number_of_bubbles = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.numbubbles');
  212: 	    if (!$number_of_bubbles) { $number_of_bubbles=8; }
  213: 	    my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,
  214: 							 $safeeval);
  215: 	    my $unit=&Apache::lonxml::get_param_var('unit',$parstack,
  216: 						    $safeeval);
  217: 	    my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval);
  218: 	    my @bubble_values=&make_numerical_bubbles($number_of_bubbles,
  219: 						      $target,$answers[0],
  220: 						      $formats[0],\@incorrect);
  221: 	    my @alphabet=('A'..'Z');
  222: 	    my $id=$Apache::inputtags::response[-1];
  223: 	    if ($target eq 'web') {
  224: 		if ($$tagstack[-1] eq 'numericalresponse') {
  225: 		    if ($unit=~/\S/) {$result.=' (in '.$unit.')<br /><br />';}
  226: 		    $result.= '<table border="1"><tr>';
  227: 		    my $previous=$Apache::lonhomework::history{"resource.$Apache::inputtags::part.$id.submission"};
  228: 		    for (my $ind=0;$ind<$number_of_bubbles;$ind++) {
  229: 			my $checked='';
  230: 			if ($previous eq $bubble_values[$ind]) {
  231: 			    $checked=" checked='on' ";
  232: 			}
  233: 			$result.='<td><input type="radio" name="HWVAL_'.$id.
  234: 			    '" value="'.$bubble_values[$ind].'" '.$checked
  235: 			    .' /><b>'.$alphabet[$ind].'</b>: '.
  236: 			    $bubble_values[$ind].'</td>';
  237: 		    }
  238: 		    $result.='</tr></table>';
  239: 		} elsif ($$tagstack[-1] eq 'formularesponse') {
  240: 		    $result.= '<br /><br /><font color="red">
  241:                            <textarea name="HWVAL_'.$id.'" rows="4" cols="50">
  242:                            </textarea></font> <br /><br />';
  243: 		}
  244: 	    } elsif ($target eq 'tex') {
  245: 		if ((defined $unit) and ($unit=~/\S/) and ($Apache::lonhomework::type eq 'exam')) {
  246: 		    $result.=' \textit{(in} \verb|'.$unit.'|\textit{)} ';
  247: 		}
  248: 		if ($$tagstack[-1] eq 'numericalresponse') {
  249: 		    my ($celllength,$number_of_tables,@table_range)=
  250: 			&get_table_sizes($formats[0],$number_of_bubbles);
  251: 		    my $j=0;
  252: 		    my $cou=0;
  253: 		    $result.='\vskip -1 mm \noindent \begin{enumerate}\item[\textbf{'.$Apache::lonxml::counter.'}.]';
  254: 		    for (my $i=0;$i<$number_of_tables;$i++) {
  255: 			$result.='\vskip -1 mm \noindent \begin{tabular}{';
  256: 			for (my $ind=0;$ind<$table_range[$j];$ind++) {
  257: 			    $result.='lp{'.$celllength.' mm}';
  258: 			}
  259: 			$result.='}';
  260: 			for (my $ind=$cou;$ind<$cou+$table_range[$j];$ind++) {
  261: 			    $result.='\hskip -3 mm {\small \textbf{'.$alphabet[$ind].'}}$\bigcirc$\hskip -2 mm & {\small '.$bubble_values[$ind].'} ';
  262: 			    if ($ind != $cou+$table_range[$j]-1) {$result.=' & ';}
  263: 			}
  264: 			$cou += $table_range[$j];
  265: 			$j++;
  266: 			$result.='\\\\\end{tabular}\vskip 0 mm ';
  267: 		    }
  268: 		    $result.='\end{enumerate}';
  269: 		} else {
  270: 		    $result.='\fbox{\fbox{\parbox{\textwidth-5mm}{\strut\\\\\strut\\\\\strut\\\\\strut\\\\}}}';
  271: 		    my $repetition = &Apache::response::repetition();
  272: 		    $result.='\begin{enumerate}';
  273: 		    for (my $i=0;$i<$repetition;$i++) {
  274: 			$result.='\item[\textbf{'.($Apache::lonxml::counter+$i).'}.]\textit{Leave blank on scoring form}\vskip 0 mm';
  275: 		    }
  276: 		    $increment=$repetition;
  277: 		    $result.= '\end{enumerate}';
  278: 		}
  279: 	    }
  280: 	}
  281:     } elsif ($target eq 'edit') {
  282: 	$result.='</td></tr>'.&Apache::edit::end_table;
  283:     } elsif ($target eq 'answer' || $target eq 'analyze') {
  284: 	
  285: 	my $part_id="$Apache::inputtags::part.$Apache::inputtags::response[-1]";
  286: 	if ($target eq 'analyze') {
  287: 	    push (@{ $Apache::lonhomework::analyze{"parts"} },$part_id);
  288: 	    $Apache::lonhomework::analyze{"$part_id.type"} = $$tagstack[-1];
  289: 	    my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval);
  290: 	    push (@{ $Apache::lonhomework::analyze{"$part_id.incorrect"} }, @incorrect);
  291: 	}
  292: 	&Apache::response::setup_params($$tagstack[-1]);
  293: 	my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
  294: 	my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval);
  295: 	my $unit=&Apache::lonxml::get_param_var('unit',$parstack,$safeeval);
  296: 	my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval);
  297: 	
  298: 	if ($target eq 'answer') {
  299: 	    $result.=&Apache::response::answer_header($$tagstack[-1]);
  300: 	}
  301: 	for(my $i=0;$i<=$#answers;$i++) {
  302: 	    my $ans=$answers[$i];
  303: 	    my $fmt=$formats[0];
  304: 	    if (@formats && $#formats) {$fmt=$formats[$i];}
  305: 	    my ($high,$low);
  306: 	    if ($Apache::inputtags::params{'tol'}) {
  307: 		($high,$low)=&get_tolrange($ans,$Apache::inputtags::params{'tol'});
  308: 	    }
  309: 	    my ($sighigh,$siglow);
  310: 	    if ($Apache::inputtags::params{'sig'}) {
  311: 		($sighigh,$siglow)=&get_sigrange($Apache::inputtags::params{'sig'});
  312: 	    }
  313: 	    if ($fmt && $$tagstack[-1] eq 'numericalresponse') {
  314: 		$fmt=~s/e/E/g;
  315: 		$ans = sprintf('%.'.$fmt,$ans);
  316: 		if ($high) {
  317: 		    $high=sprintf('%.'.$fmt,$high);
  318: 		    $low =sprintf('%.'.$fmt,$low);
  319: 		}
  320: 	    }
  321: 	    if ($target eq 'answer') {
  322: 		if ($high && $$tagstack[-1] eq 'numericalresponse') { $ans.=' ['.$low.','.$high.']'; }
  323: 		if ($sighigh && $$tagstack[-1] eq 'numericalresponse') {
  324: 		    if ($ENV{'form.answer_output_mode'} eq 'tex') {
  325: 			$ans.= " Sig $siglow - $sighigh";
  326: 		    } else {
  327: 			$ans.= " Sig <i>$siglow - $sighigh</i>";
  328: 		    }
  329: 		}
  330: 		$result.=&Apache::response::answer_part($$tagstack[-1],$ans);
  331: 	    } elsif ($target eq 'analyze') {
  332: 		push (@{ $Apache::lonhomework::analyze{"$part_id.answer"} }, $ans);
  333: 		if ($high) {
  334: 		    push (@{ $Apache::lonhomework::analyze{"$part_id.ans_high"} }, $high);
  335: 		    push (@{ $Apache::lonhomework::analyze{"$part_id.ans_low"} }, $low);
  336: 		}
  337: 	    }
  338: 	}
  339: 	if (defined($unit) and ($unit ne '') and
  340: 	    $$tagstack[-1] eq 'numericalresponse') {
  341: 	    if ($target eq 'answer') {
  342: 		if ($ENV{'form.answer_output_mode'} eq 'tex') {
  343: 		    $result.=&Apache::response::answer_part($$tagstack[-1],
  344: 							    " Unit: $unit ");
  345: 		} else {
  346: 		    $result.=&Apache::response::answer_part($$tagstack[-1],
  347: 							    "Unit: <b>$unit</b>");
  348: 		}
  349: 	    } elsif ($target eq 'analyze') {
  350: 		push (@{ $Apache::lonhomework::analyze{"$part_id.unit"} }, $unit);
  351: 	    }
  352: 	}
  353: 	if ($type || $$tagstack[-1] eq 'stringresponse') {
  354: 	    my $string='Case Insensitive';
  355: 	    if ($type eq 'mc') {
  356: 		$string='Multiple Choice';
  357: 	    } elsif ($type eq 'cs') {
  358: 		$string='Case Sensitive';
  359: 	    } elsif ($type eq 'ci') {
  360: 		$string='Case Insensitive';
  361: 	    } elsif ($type eq 'fml') {
  362: 		$string='Formula';
  363: 	    }
  364: 	    if ($target eq 'answer') {
  365: 		if ($ENV{'form.answer_output_mode'} eq 'tex') {
  366: 		    $result.=&Apache::response::answer_part($$tagstack[-1],
  367: 							  "$string");
  368: 		} else {
  369: 		    $result.=&Apache::response::answer_part($$tagstack[-1],
  370: 							    "<b>$string</b>");
  371: 		}
  372: 	    } elsif ($target eq 'analyze') {
  373: 		push (@{ $Apache::lonhomework::analyze{"$part_id.str_type"} },
  374: 		      $type);
  375: 	    }
  376: 	}
  377: 	if ($$tagstack[-1] eq 'formularesponse' && $target eq 'answer') {
  378: 	    my $samples=&Apache::lonxml::get_param('samples',$parstack,$safeeval);
  379: 	    $result.=&Apache::response::answer_part($$tagstack[-1],$samples);
  380: 	}
  381: 	if ($target eq 'answer') {
  382: 	    $result.=&Apache::response::answer_footer($$tagstack[-1]);
  383: 	}
  384:     }
  385:     if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
  386: 	$target eq 'tex' || $target eq 'analyze') {
  387: 	&Apache::lonxml::increment_counter($increment);
  388:     }
  389:     &Apache::response::end_response;
  390:     return $result;
  391: }
  392: 
  393: sub get_table_sizes {
  394:     my ($format,$number_of_bubbles)=@_;
  395:     my $max_val = 0;
  396:     if ($format=~m/^(\d+)E([^\d]*)(\d*)$/) {
  397: 	$max_val=$1+$2+4;
  398:     } else {
  399: 	$max_val=4;
  400:     }
  401:     $max_val = int(0.9*$ENV{'form.textwidth'}/(($max_val+6)*2));
  402:     my $celllength = 0.9*$ENV{'form.textwidth'}/$max_val-10;
  403:     my @table_range = ();
  404:     my $number_of_tables = int($number_of_bubbles/$max_val);
  405:     for (my $i=0;$i<$number_of_tables;$i++) {push @table_range,$max_val;}
  406:     if ($number_of_bubbles % $max_val != 0) {
  407: 	$number_of_tables++;
  408: 	push @table_range,($number_of_bubbles % $max_val);
  409:     }
  410:     return ($celllength,$number_of_tables,@table_range);
  411: }
  412: 
  413: sub format_number {
  414:     my ($number,$format,$target)=@_;
  415:     my $ans;
  416:     if ($format ne '') {
  417: 	$format=~s/e/E/g;
  418: 	$ans = sprintf('%.'.$format,$number);
  419:     } else {
  420: 	my $format = '';
  421: 	#What is the number? (integer,decimal,floating point)
  422: 	if ($number=~/^(\d*\.?\d*)(E|e)(\d*)$/) {
  423: 	    $format = '3e';
  424: 	} elsif ($number=~/^(\d*)\.(\d*)$/) {
  425: 	    $format = '4f';
  426: 	} elsif ($number=~/^(\d*)$/) {
  427: 	    $format = 'd';
  428: 	}
  429: 	$ans = sprintf('%.'.$format,$number);
  430:     }
  431:     if ($target eq 'tex') {
  432: 	if ($ans =~ m/([0-9\.\-\+]+)E([0-9\-\+]+)/ ) {
  433: 	    my $number = $1;
  434: 	    my $power = $2;
  435: 	    $power=~s/^\+//;
  436: 	    $power=~s/^(-?)0+(\d+)//;
  437: 	    $ans=$number.'$\times 10^{'.$1.$2.'}$'; #'stupidemacs
  438: 	}
  439:     }
  440:     return $ans;
  441: }
  442: 
  443: sub make_numerical_bubbles {
  444:     my ($number_of_bubbles,$target,$answer,$format,$incorrect) =@_;
  445:     my @bubble_values = ();
  446:     &Apache::lonxml::debug("incorrect is $incorrect");
  447:     if (defined($incorrect) && ref($incorrect)) {
  448: 	&Apache::lonxml::debug("inside ".(scalar(@$incorrect)+1 gt $number_of_bubbles));
  449: 	if (scalar(@$incorrect)+1 >= $number_of_bubbles) {
  450: 	    &Apache::lonxml::debug("inside ".(scalar(@$incorrect)+1).":$number_of_bubbles");
  451: 	    &Apache::response::setrandomnumber();
  452: 	    my @rand_inc=&Math::Random::random_permutation(@$incorrect);
  453: 	    @bubble_values=@rand_inc[0..($number_of_bubbles-2)];
  454: 	    @bubble_values=sort {$a <=> $b} (@bubble_values,$answer);
  455: 	    &Apache::lonxml::debug("Answer was :$answer: returning :".$#bubble_values.": whih are :".join(':',@bubble_values));
  456: 	    return @bubble_values;
  457: 	}
  458: 	#FIXME what to do when not enough incorrects specified?
  459:     }
  460:     my @factors = (1.13,1.17,1.25,1.33,1.45); #default values of factors
  461:     my @powers = (1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0); #default values for powers
  462:     &Apache::response::setrandomnumber();
  463:     my $ind=&Math::Random::random_uniform_integer(1,0,$#powers);
  464:     my $power = $powers[$ind];
  465:     $ind=&Math::Random::random_uniform_integer(1,0,$#factors);
  466:     my $factor = $factors[$ind];
  467:     for ($ind=0;$ind<$number_of_bubbles;$ind++) {
  468: 	$bubble_values[$ind] = $answer*($factor**($power-$powers[$#powers-$ind]));
  469: 	$bubble_values[$ind] = &format_number($bubble_values[$ind],
  470: 					       $format,$target);
  471: 
  472:     }
  473:     return @bubble_values;
  474: }
  475: 
  476: sub get_tolrange {
  477:     my ($ans,$tol)=@_;
  478:     my ($high,$low);
  479:     if ($tol =~ /%$/) {
  480: 	chop($tol);
  481: 	my $change=$ans*($tol/100.0);
  482: 	$high=$ans+$change;
  483: 	$low=$ans-$change;
  484:     } else {
  485: 	$high=$ans+$tol;
  486: 	$low=$ans-$tol;
  487:     }
  488:     return ($high,$low);
  489: }
  490: 
  491: sub get_sigrange {
  492:     my ($sig)=@_;
  493:     &Apache::lonxml::debug("Got a sig of :$sig:");
  494:     my $sig_lbound;
  495:     my $sig_ubound;
  496:     if ($sig eq '') {
  497: 	$sig_lbound = 0; #SIG_LB_DEFAULT
  498: 	$sig_ubound =15; #SIG_UB_DEFAULT
  499:     } else {
  500: 	($sig_lbound,$sig_ubound) = split(/,/,$sig);
  501: 	if (!$sig_lbound) {
  502: 	    $sig_lbound = 0; #SIG_LB_DEFAULT
  503: 	    $sig_ubound =15; #SIG_UB_DEFAULT
  504: 	}
  505: 	if (!$sig_ubound) { $sig_ubound=$sig_lbound; }
  506:     }
  507:     return ($sig_ubound,$sig_lbound);
  508: }
  509: 
  510: sub start_stringresponse {
  511:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
  512:     my $result;
  513:     if ($target eq 'meta') {
  514: 	&Apache::response::start_response($parstack,$safeeval);
  515: 	$result=&Apache::response::meta_package_write('stringresponse');
  516: 	&Apache::response::end_response();
  517:     } else {
  518: 	$result.=&start_numericalresponse(@_);
  519:     }
  520:     return $result;
  521: }
  522: 
  523: sub end_stringresponse {
  524:     return end_numericalresponse(@_);
  525: }
  526: 
  527: sub start_formularesponse {
  528:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
  529:     my $result;
  530:     if ($target eq 'meta') {
  531: 	&Apache::response::start_response($parstack,$safeeval);
  532: 	$result=&Apache::response::meta_package_write('formularesponse');
  533: 	&Apache::response::end_response();
  534:     } else {
  535: 	$result.=&start_numericalresponse(@_);
  536:     }
  537:     return $result;
  538: }
  539: 
  540: sub end_formularesponse {
  541:     return end_numericalresponse(@_);
  542: }
  543: 
  544: 1;
  545: __END__
  546: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>