WeBWorK Main Forum

Adding pop-up lists to MultiAnswers

Adding pop-up lists to MultiAnswers

by Patrick Spencer -
Number of replies: 5
I was wondering if there was a way to combine PopUpLists with MultiAnswer choices? The problem we're working on goes like this: the student is presented with a graph of a polynomial and they have to find the value and multiplicity of each zero. They can enter the zero's in any order they please. We would like the multiplicity choice for each zero to be a PopUpList containing either "even" or "odd". I've attached a photo of part of the problem to this message. 

I thought about switching to the unorderedAnswers.pl helper functions but I didn't know how to group the pairs of solutions togethers.

I've also included the code we've been using below.

Thank you!
Patrick Spencer
University of Missouri

DOCUMENT();
loadMacros(
  "AnswerFormatHelp.pl",
  "MathObjects.pl",
  "PeriodicRerandomization.pl",
  "PGgraphmacros.pl",
  "PGstandard.pl",
  "parserMultiAnswer.pl",
"parserPopUp.pl",
);

TEXT(beginproblem());
PeriodicRerandomization("3");
$refreshCachedImages = 1;
$showPartialCorrectAnswers = 1;


#################################################################
# setup contexts and variables 
#################################################################
Context("Numeric");
Context()->strings->add("even"=>{}, "e"=>{alias=>"even"},
"odd"=>{}, "o"=>{alias=>"odd"},
"positive"=>{}, "pos"=>{alias=>"positive"}, "p"=>{alias=>"positive"},
"negative"=>{}, "neg"=>{alias=>"negative"}, "n"=>{alias=>"negative"});
Context()->{error}{msg}{"Operands of '*' can't be words"} = " ";
#Context()->{error}{msg}{"Can't convert an Empty Value to a Real Number"} = " ";
$numzeros = random(2,5);
do {</font></div><div><font face="courier new, courier, monospace">  # posszeros = possible zeros?</font></div><div><font face="courier new, courier, monospace">  @posszeros = (-10..10);</font></div><div><font face="courier new, courier, monospace">  # zeros = actual zeros?</font></div><div><font face="courier new, courier, monospace">  @zeros = (1..$numzeros);</font></div><div><font face="courier new, courier, monospace">  for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">    $zeros[$i] = list_random(@posszeros);</font></div><div><font face="courier new, courier, monospace">    if ($numzeros == 2 || $numzeros == 3) {</font></div><div><font face="courier new, courier, monospace">      $powers[$i] = random(2,3);</font></div><div><font face="courier new, courier, monospace">    } else {</font></div><div><font face="courier new, courier, monospace">      $powers[$i] = random(1,2);</font></div><div><font face="courier new, courier, monospace">    } 
    $removed = 0;
    $count = 0;
    do {</font></div><div><font face="courier new, courier, monospace">      if ($posszeros[$count] == $zeros[$i]) {</font></div><div><font face="courier new, courier, monospace">        $tmp = $posszeros[$count];</font></div><div><font face="courier new, courier, monospace">        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];</font></div><div><font face="courier new, courier, monospace">        $posszeros[scalar(@posszeros)-1] = $tmp;</font></div><div><font face="courier new, courier, monospace">        pop(@posszeros);</font></div><div><font face="courier new, courier, monospace">        $removed = 1;</font></div><div><font face="courier new, courier, monospace">      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
    $removed = 0;
    $count = 0;
    do {</font></div><div><font face="courier new, courier, monospace">      if ($posszeros[$count] == $zeros[$i]-1) {</font></div><div><font face="courier new, courier, monospace">        $tmp = $posszeros[$count];</font></div><div><font face="courier new, courier, monospace">        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];</font></div><div><font face="courier new, courier, monospace">        $posszeros[scalar(@posszeros)-1] = $tmp;</font></div><div><font face="courier new, courier, monospace">        pop(@posszeros);</font></div><div><font face="courier new, courier, monospace">        $removed = 1;</font></div><div><font face="courier new, courier, monospace">      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
    $removed = 0;
    $count = 0;
    do {</font></div><div><font face="courier new, courier, monospace">      if ($posszeros[$count] == $zeros[$i]+1) {</font></div><div><font face="courier new, courier, monospace">        $tmp = $posszeros[$count];</font></div><div><font face="courier new, courier, monospace">        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];</font></div><div><font face="courier new, courier, monospace">        $posszeros[scalar(@posszeros)-1] = $tmp;</font></div><div><font face="courier new, courier, monospace">        pop(@posszeros);</font></div><div><font face="courier new, courier, monospace">        $removed = 1;</font></div><div><font face="courier new, courier, monospace">      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
  }

  $yint = 1;
  for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">    $yint = $yint*((-$zeros[$i])**$powers[$i]);</font></div><div><font face="courier new, courier, monospace">  }

  # this sub routine represents what is to be the graphed polynomial
  sub poly {</font></div><div><font face="courier new, courier, monospace">    my $x = shift();  </font></div><div><font face="courier new, courier, monospace">    $prod = 1;</font></div><div><font face="courier new, courier, monospace">    for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">      $prod = $prod*(($x - $zeros[$i])**$powers[$i]);</font></div><div><font face="courier new, courier, monospace">    }
    return $prod;
  };

  # sort zeros from low to high;
  $swapped = 1;
  $count = 0;
  while ($swapped) {</font></div><div><font face="courier new, courier, monospace">    $swapped = 0;</font></div><div><font face="courier new, courier, monospace">    $count++;</font></div><div><font face="courier new, courier, monospace">    for ($i = 0; $i < $numzeros - $count; $i++) {</font></div><div><font face="courier new, courier, monospace">      if ($zeros[$i] > $zeros[$i+1]) {</font></div><div><font face="courier new, courier, monospace">        $tmp = $zeros[$i];</font></div><div><font face="courier new, courier, monospace">        $zeros[$i] = $zeros[$i+1];</font></div><div><font face="courier new, courier, monospace">        $zeros[$i+1] = $tmp;</font></div><div><font face="courier new, courier, monospace">        $swapped = 1;</font></div><div><font face="courier new, courier, monospace">      }
    }
  }

  # this next bit is to be sure that the gap between the low or high point 
  # between zeros and the x-axis is not too small
  for ($i = 0; $i < $numzeros-1; $i++) {</font></div><div><font face="courier new, courier, monospace">    $maxs[$i] = 0;</font></div><div><font face="courier new, courier, monospace">  }

  for ($j = 0; $j < $numzeros-1; $j++) {</font></div><div><font face="courier new, courier, monospace">    $steps = 100;</font></div><div><font face="courier new, courier, monospace">    $stepsize = ($zeros[$j+1] - $zeros[$j])/$steps;</font></div><div><font face="courier new, courier, monospace">    for ($k = 0; $k < $steps; $k++) {</font></div><div><font face="courier new, courier, monospace">      $tmp = abs(poly($zeros[$j]+$k*$stepsize));</font></div><div><font face="courier new, courier, monospace">      if ($tmp > $maxs[$j]) {</font></div><div><font face="courier new, courier, monospace">        $maxs[$j] = $tmp; </font></div><div><font face="courier new, courier, monospace">      } 
    }
  }

  $min = min(@maxs);
  $max = max(@maxs);
  $scale = random(5,9);
  $a = random(-1,1,2)*$scale/max($max);
  $tmp1 = abs($min*$a);
  $tmp2 = abs($max*$a);
} until (abs($tmp2/$tmp1) < 3*$scale/2);

$expn = sub {</font></div><div><font face="courier new, courier, monospace">  my $x = shift();  </font></div><div><font face="courier new, courier, monospace">  $prod = $a;</font></div><div><font face="courier new, courier, monospace">  for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">    $prod = $prod*(($x - $zeros[$i])**$powers[$i]);</font></div><div><font face="courier new, courier, monospace">  }
  return $prod;
};

$minx = min($zeros[0],0)-3;
$miny = -10;
$maxx = max($zeros[$numzeros-1],0)+3;
$maxy = 10;
$gsize = 400;

$graph = init_graph($minx, $miny, $maxx, $maxy, size=>[$gsize,$gsize]);
for ($i = $minx; $i <= $maxx; $i++) {</font></div><div><font face="courier new, courier, monospace">  $graph->moveTo($i,$miny);</font></div><div><font face="courier new, courier, monospace">  $graph->lineTo($i,$maxy,'gray',1);</font></div><div><font face="courier new, courier, monospace">}
for ($i = $miny; $i <= $maxy; $i++) {</font></div><div><font face="courier new, courier, monospace">  $graph->moveTo($minx,$i);</font></div><div><font face="courier new, courier, monospace">  $graph->lineTo($maxx,$i,'gray',1);</font></div><div><font face="courier new, courier, monospace">}
$graph->moveTo($minx, 0);
$graph->arrowTo($maxx, 0, 'black', 2);
$graph->arrowTo($minx, 0, 'black', 2);
$graph->moveTo(0, $miny);
$graph->arrowTo(0, $maxy, 'black', 2);
$graph->arrowTo(0, $miny, 'black', 2);
$graph->lb(new Label($maxx-0.1, 0.4, 'x', 'black', 'bottom', 'right'));
$graph->lb(new Label(0.4, $maxy-0.1, 'y', 'black', 'top', 'left'));

for ($i = $minx+1; $i < $maxx; $i++) {</font></div><div><font face="courier new, courier, monospace">  if ($i != 0 && $i % 5 == 0 || $i == 1) {</font></div><div><font face="courier new, courier, monospace">    $graph->lb(new Label($i,-0.1,$i, 'black', 'top','center'));</font></div><div><font face="courier new, courier, monospace">  }
}

for ($i = $miny+1; $i < $maxy; $i++) {</font></div><div><font face="courier new, courier, monospace">  if ($i != 0 && $i % 5 == 0 || $i == 1) {</font></div><div><font face="courier new, courier, monospace">    $graph->lb(new Label(-0.1,$i,$i, 'black', 'middle', 'right'));</font></div><div><font face="courier new, courier, monospace">  }
}

for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  $graph->stamps(closed_circle($zeros[$i],0,'blue'));</font></div><div><font face="courier new, courier, monospace">}

$fun = new Fun($expn, $graph);
$fun->steps(1500);
$fun->domain($minx,$maxx);

$zerosans = List(@zeros);

for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  if ($powers[$i] % 2 == 0) {</font></div><div><font face="courier new, courier, monospace">    $mltpy[$i] = "even";</font></div><div><font face="courier new, courier, monospace">  } else {</font></div><div><font face="courier new, courier, monospace">    $mltpy[$i] = "odd";</font></div><div><font face="courier new, courier, monospace">  }
}

for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  $answers[2*$i] = $zeros[$i];</font></div><div><font face="courier new, courier, monospace">  $answers[2*$i+1] = $mltpy[$i]</font></div><div><font face="courier new, courier, monospace">}

$ma = MultiAnswer(@answers)->with(
  singleResult => 0,
  allowBlankAnswers => 1,
  checker => sub {</font></div><div><font face="courier new, courier, monospace">    $num = scalar(@answers);</font></div><div><font face="courier new, courier, monospace">    my ($correct, $student, $self) = @_;</font></div><div><font face="courier new, courier, monospace">    my @ac = @{$correct};
    my @st = @{$student};
    my @ans = (0..scalar(@ac)/2);
    for ($i = 0; $i < $num; $i++) {</font></div><div><font face="courier new, courier, monospace">      $returnans[$i] = 0;</font></div><div><font face="courier new, courier, monospace">    }
    for ($i = 0; $i < $num/2; $i++) {</font></div><div><font face="courier new, courier, monospace">      $hasbeenused[$i] = 0;</font></div><div><font face="courier new, courier, monospace">    }
    for ($i = 0; $i < scalar(@ac)/2; $i++) {</font></div><div><font face="courier new, courier, monospace">      $ans[$i] = [$ac[2*$i],$ac[2*$i+1]];</font></div><div><font face="courier new, courier, monospace">    }
    for ($i = 0; $i < scalar(@ac)/2; $i++) {</font></div><div><font face="courier new, courier, monospace">      for ($j = 0; $j < scalar(@ac)/2; $j++) {</font></div><div><font face="courier new, courier, monospace">        if ($ans[$i][0] == $st[2*$j] && $ans[$i][1] == $st[2*$j+1] && $hasbeenused[$i] != 1) {</font></div><div><font face="courier new, courier, monospace">          $returnans[0][2*$j] = 1;</font></div><div><font face="courier new, courier, monospace">          $returnans[0][2*$j+1] = 1;</font></div><div><font face="courier new, courier, monospace">          $hasbeenused[$i] = 1;</font></div><div><font face="courier new, courier, monospace">        }
      }
    }
    for ($i = 0; $i < $num; $i++) {</font></div><div><font face="courier new, courier, monospace">      $reans[0][$i] = $returnans[0][$i]; </font></div><div><font face="courier new, courier, monospace">    }
    return @reans;
  }
);

$degree = $powers[0];
for ($i = 1; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  $degree = $degree + $powers[$i];</font></div><div><font face="courier new, courier, monospace">}
if ($degree % 2 == 0) {</font></div><div><font face="courier new, courier, monospace">  $degreeans = "even";</font></div><div><font face="courier new, courier, monospace">} else {</font></div><div><font face="courier new, courier, monospace">  $degreeans = "odd";</font></div><div><font face="courier new, courier, monospace">}

if ($a < 0) {</font></div><div><font face="courier new, courier, monospace">  $leadcoeffans = "negative";</font></div><div><font face="courier new, courier, monospace">} else {</font></div><div><font face="courier new, courier, monospace">  $leadcoeffans = "positive";</font></div><div><font face="courier new, courier, monospace">}

$dispzeros = "$zeros[0]";
$dispmults = "$mltpy[0]";
for ($i = 1; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  $dispzeros = ($dispzeros).", ".($zeros[$i]);</font></div><div><font face="courier new, courier, monospace">  $dispmults = ($dispmults).", ".($mltpy[$i]);</font></div><div><font face="courier new, courier, monospace">}

$degree = PopUp([" ","even", "odd"], "$degreeans");
$lead_coef_sgn = PopUp([" ","positive", "negative"], "$leadcoeffans");

#################################################################
# state the problem 
#################################################################

Context()->texStrings;
BEGIN_TEXT

$PAR
$BCENTER
\{ image(insertGraph($graph), width=>$gsize, height=>$gsize, tex_size=>300 ); \}
$ECENTER 
$PAR

Find the following information pertaining to the polynomial, \(f(x)\), graphed above. 
$PAR
(a) The zeros of \(f(x)\) are \(x = \) \{ans_rule(15)\} (separate by commas) and 
END_TEXT

for ($i = 0; $i < $numzeros; $i++) {</font></div><div><font face="courier new, courier, monospace">  if ($i == $numzeros-2) {</font></div><div><font face="courier new, courier, monospace">    BEGIN_TEXT</font></div><div><font face="courier new, courier, monospace">    $PAR</font></div><div><font face="courier new, courier, monospace">    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity and,
    $PAR
    END_TEXT
  } elsif ($i == $numzeros-1) {</font></div><div><font face="courier new, courier, monospace">    BEGIN_TEXT</font></div><div><font face="courier new, courier, monospace">    $PAR</font></div><div><font face="courier new, courier, monospace">    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity.
    $PAR
    END_TEXT
  } else {</font></div><div><font face="courier new, courier, monospace">    BEGIN_TEXT</font></div><div><font face="courier new, courier, monospace">    $PAR</font></div><div><font face="courier new, courier, monospace">    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity,
    $PAR
    END_TEXT
  }
}

BEGIN_TEXT
$PAR
(b) The degree of \(f(x)\) is \{$degree->menu()\}.
$PAR
(c) The leading coefficient of \(f(x)\) is \{$lead_coef_sgn->menu()\}.
END_TEXT


#################################################################
# check the answer  
#################################################################
ANS(Compute($zerosans)->cmp());
ANS($ma->cmp());
ANS($degree->cmp());
ANS($lead_coef_sgn->cmp());


#################################################################
# use PeriodicRerandomization to write the answer and generate a new
# version of the problem
#################################################################
if ($attempts_modp == 0 && $actualAttempts != 0) {</font></div><div><font face="courier new, courier, monospace">  BEGIN_TEXT</font></div><div><font face="courier new, courier, monospace">  $PAR</font></div><div><font face="courier new, courier, monospace">  ${BBOLD}Answer:${EBOLD}
  $PAR
  (a) The zeros are \(x = $dispzeros\) with $dispmults multiplicity, respectively.
  $PAR
  (b) The degree is $degreeans.
  $PAR
  (c) The leading coefficient is $leadcoeffans.
  $PAR
  END_TEXT
} else {</font></div><div><font face="courier new, courier, monospace">  BEGIN_TEXT</font></div><div><font face="courier new, courier, monospace">  $PAR</font></div><div><font face="courier new, courier, monospace">  ${BBOLD}Help:${EBOLD} Type ${BBOLD}even${EBOLD} or ${BBOLD}odd${EBOLD} for multiplicities and the degree. Type ${BBOLD}pos${EBOLD} for positive or ${BBOLD}neg${EBOLD} for negative for the leading coefficient. You must have the corresponding multiplicity correct for each zero in order to receive credit!
  $BR
  END_TEXT
}
Context()->normalStrings;
PeriodicStatus(); 


ENDDOCUMENT();

Attachment graph.png
In reply to Patrick Spencer

Re: Adding pop-up lists to MultiAnswers

by Davide Cervone -
In fact, here is a version that uses PopUp's in the way that I think you are suggesting:

DOCUMENT();

loadMacros(
  "AnswerFormatHelp.pl",
  "MathObjects.pl",
  "PeriodicRerandomization.pl",
  "PGgraphmacros.pl",
  "PGstandard.pl",
  "parserMultiAnswer.pl",
	"parserPopUp.pl",
);

TEXT(beginproblem());
PeriodicRerandomization("3");
$refreshCachedImages = 1;
$showPartialCorrectAnswers = 1;


#################################################################
# setup contexts and variables 
#################################################################
Context("Numeric");
Context()->strings->add("even"=>{}, "e"=>{alias=>"even"},
"odd"=>{}, "o"=>{alias=>"odd"},
"positive"=>{}, "pos"=>{alias=>"positive"}, "p"=>{alias=>"positive"},
"negative"=>{}, "neg"=>{alias=>"negative"}, "n"=>{alias=>"negative"});
Context()->{error}{msg}{"Operands of '*' can't be words"} = " ";
#Context()->{error}{msg}{"Can't convert an Empty Value to a Real Number"} = " ";
$numzeros = random(2,5);
do {
  # posszeros = possible zeros?
  @posszeros = (-10..10);
  # zeros = actual zeros?
  @zeros = (1..$numzeros);
  for ($i = 0; $i < $numzeros; $i++) {
    $zeros[$i] = list_random(@posszeros);
    if ($numzeros == 2 || $numzeros == 3) {
      $powers[$i] = random(2,3);
    } else {
      $powers[$i] = random(1,2);
    } 
    $removed = 0;
    $count = 0;
    do {
      if ($posszeros[$count] == $zeros[$i]) {
        $tmp = $posszeros[$count];
        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];
        $posszeros[scalar(@posszeros)-1] = $tmp;
        pop(@posszeros);
        $removed = 1;
      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
    $removed = 0;
    $count = 0;
    do {
      if ($posszeros[$count] == $zeros[$i]-1) {
        $tmp = $posszeros[$count];
        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];
        $posszeros[scalar(@posszeros)-1] = $tmp;
        pop(@posszeros);
        $removed = 1;
      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
    $removed = 0;
    $count = 0;
    do {
      if ($posszeros[$count] == $zeros[$i]+1) {
        $tmp = $posszeros[$count];
        $posszeros[$count] = $posszeros[scalar(@posszeros)-1];
        $posszeros[scalar(@posszeros)-1] = $tmp;
        pop(@posszeros);
        $removed = 1;
      }
      $count++;
    } until ($removed || $count == scalar(@posszeros));
  }

  $yint = 1;
  for ($i = 0; $i < $numzeros; $i++) {
    $yint = $yint*((-$zeros[$i])**$powers[$i]);
  }

  # this sub routine represents what is to be the graphed polynomial
  sub poly {
    my $x = shift();  
    $prod = 1;
    for ($i = 0; $i < $numzeros; $i++) {
      $prod = $prod*(($x - $zeros[$i])**$powers[$i]);
    }
    return $prod;
  };

  # sort zeros from low to high;
  $swapped = 1;
  $count = 0;
  while ($swapped) {
    $swapped = 0;
    $count++;
    for ($i = 0; $i < $numzeros - $count; $i++) {
      if ($zeros[$i] > $zeros[$i+1]) {
        $tmp = $zeros[$i];
        $zeros[$i] = $zeros[$i+1];
        $zeros[$i+1] = $tmp;
        $swapped = 1;
      }
    }
  }

  # this next bit is to be sure that the gap between the low or high point 
  # between zeros and the x-axis is not too small
  for ($i = 0; $i < $numzeros-1; $i++) {
    $maxs[$i] = 0;
  }

  for ($j = 0; $j < $numzeros-1; $j++) {
    $steps = 100;
    $stepsize = ($zeros[$j+1] - $zeros[$j])/$steps;
    for ($k = 0; $k < $steps; $k++) {
      $tmp = abs(poly($zeros[$j]+$k*$stepsize));
      if ($tmp > $maxs[$j]) {
        $maxs[$j] = $tmp; 
      } 
    }
  }

  $min = min(@maxs);
  $max = max(@maxs);
  $scale = random(5,9);
  $a = random(-1,1,2)*$scale/max($max);
  $tmp1 = abs($min*$a);
  $tmp2 = abs($max*$a);
} until (abs($tmp2/$tmp1) < 3*$scale/2);

$expn = sub {
  my $x = shift();  
  $prod = $a;
  for ($i = 0; $i < $numzeros; $i++) {
    $prod = $prod*(($x - $zeros[$i])**$powers[$i]);
  }
  return $prod;
};

$minx = min($zeros[0],0)-3;
$miny = -10;
$maxx = max($zeros[$numzeros-1],0)+3;
$maxy = 10;
$gsize = 400;

$graph = init_graph($minx, $miny, $maxx, $maxy, size=>[$gsize,$gsize]);
for ($i = $minx; $i <= $maxx; $i++) {
  $graph->moveTo($i,$miny);
  $graph->lineTo($i,$maxy,'gray',1);
}
for ($i = $miny; $i <= $maxy; $i++) {
  $graph->moveTo($minx,$i);
  $graph->lineTo($maxx,$i,'gray',1);
}
$graph->moveTo($minx, 0);
$graph->arrowTo($maxx, 0, 'black', 2);
$graph->arrowTo($minx, 0, 'black', 2);
$graph->moveTo(0, $miny);
$graph->arrowTo(0, $maxy, 'black', 2);
$graph->arrowTo(0, $miny, 'black', 2);
$graph->lb(new Label($maxx-0.1, 0.4, 'x', 'black', 'bottom', 'right'));
$graph->lb(new Label(0.4, $maxy-0.1, 'y', 'black', 'top', 'left'));

for ($i = $minx+1; $i < $maxx; $i++) {
  if ($i != 0 && $i % 5 == 0 || $i == 1) {
    $graph->lb(new Label($i,-0.1,$i, 'black', 'top','center'));
  }
}

for ($i = $miny+1; $i < $maxy; $i++) {
  if ($i != 0 && $i % 5 == 0 || $i == 1) {
    $graph->lb(new Label(-0.1,$i,$i, 'black', 'middle', 'right'));
  }
}

for ($i = 0; $i < $numzeros; $i++) {
  $graph->stamps(closed_circle($zeros[$i],0,'blue'));
}

$fun = new Fun($expn, $graph);
$fun->steps(1500);
$fun->domain($minx,$maxx);

$zerosans = List(@zeros);

for ($i = 0; $i < $numzeros; $i++) {
  if ($powers[$i] % 2 == 0) {
    $mltpy[$i] = "even";
  } else {
    $mltpy[$i] = "odd";
  }
}

for ($i = 0; $i < $numzeros; $i++) {
  $answers[2*$i] = $zeros[$i];
  <b>$answers[2*$i+1] = PopUp([" ","even","odd"],$mltpy[$i]);</b>
}

$ma = MultiAnswer(@answers)->with(
  singleResult => 0,
  allowBlankAnswers => 1,
  checker => sub {
    $num = scalar(@answers);
    my ($correct, $student, $self) = @_;
    my @ac = @{$correct};
    my @st = @{$student};
    my @ans = (0..scalar(@ac)/2);
    for ($i = 0; $i < $num; $i++) {
      $returnans[$i] = 0;
    }
    for ($i = 0; $i < $num/2; $i++) {
      $hasbeenused[$i] = 0;
    }
    for ($i = 0; $i < scalar(@ac)/2; $i++) {
      $ans[$i] = [$ac[2*$i],$ac[2*$i+1]];
    }
    for ($i = 0; $i < scalar(@ac)/2; $i++) {
      for ($j = 0; $j < scalar(@ac)/2; $j++) {
        if ($ans[$i][0] == $st[2*$j] && $ans[$i][1] == $st[2*$j+1] && $hasbeenused[$i] != 1) {
          $returnans[0][2*$j] = 1;
          $returnans[0][2*$j+1] = 1;
          $hasbeenused[$i] = 1;
        }
      }
    }
    for ($i = 0; $i < $num; $i++) {
      $reans[0][$i] = $returnans[0][$i]; 
    }
    return @reans;
  }
);

$degree = $powers[0];
for ($i = 1; $i < $numzeros; $i++) {
  $degree = $degree + $powers[$i];
}
if ($degree % 2 == 0) {
  $degreeans = "even";
} else {
  $degreeans = "odd";
}

if ($a < 0) {
  $leadcoeffans = "negative";
} else {
  $leadcoeffans = "positive";
}

$dispzeros = "$zeros[0]";
$dispmults = "$mltpy[0]";
for ($i = 1; $i < $numzeros; $i++) {
  $dispzeros = ($dispzeros).", ".($zeros[$i]);
  $dispmults = ($dispmults).", ".($mltpy[$i]);
}

$degree = PopUp([" ","even", "odd"], "$degreeans");
$lead_coef_sgn = PopUp([" ","positive", "negative"], "$leadcoeffans");

#################################################################
# state the problem 
#################################################################

Context()->texStrings;
BEGIN_TEXT

$PAR
$BCENTER
\{ image(insertGraph($graph), width=>$gsize, height=>$gsize, tex_size=>300 ); \}
$ECENTER 
$PAR

Find the following information pertaining to the polynomial, \(f(x)\), graphed above. 
$PAR
(a) The zeros of \(f(x)\) are \(x = \) \{ans_rule(15)\} (separate by commas) and 
END_TEXT

for ($i = 0; $i < $numzeros; $i++) {
  if ($i == $numzeros-2) {
    BEGIN_TEXT
    $PAR
    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity and,
    $PAR
    END_TEXT
  } elsif ($i == $numzeros-1) {
    BEGIN_TEXT
    $PAR
    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity.
    $PAR
    END_TEXT
  } else {
    BEGIN_TEXT
    $PAR
    $SPACE $SPACE $SPACE $SPACE  the zero \(x = \) \{$ma->ans_rule(5)\} has \{$ma->ans_rule(5)\} multiplicity,
    $PAR
    END_TEXT
  }
}

BEGIN_TEXT
$PAR
(b) The degree of \(f(x)\) is \{$degree->menu()\}.
$PAR
(c) The leading coefficient of \(f(x)\) is \{$lead_coef_sgn->menu()\}.
END_TEXT


#################################################################
# check the answer  
#################################################################
ANS(Compute($zerosans)->cmp());
ANS($ma->cmp());
ANS($degree->cmp());
ANS($lead_coef_sgn->cmp());


#################################################################
# use PeriodicRerandomization to write the answer and generate a new
# version of the problem
#################################################################
if ($attempts_modp == 0 && $actualAttempts != 0) {
  BEGIN_TEXT
  $PAR
  ${BBOLD}Answer:${EBOLD}
  $PAR
  (a) The zeros are \(x = $dispzeros\) with $dispmults multiplicity, respectively.
  $PAR
  (b) The degree is $degreeans.
  $PAR
  (c) The leading coefficient is $leadcoeffans.
  $PAR
  END_TEXT
} else {
  BEGIN_TEXT
  $PAR
  ${BBOLD}Help:${EBOLD} Type ${BBOLD}even${EBOLD} or
  ${BBOLD}odd${EBOLD} for multiplicities and the degree. 
  Type ${BBOLD}pos${EBOLD} for positive or ${BBOLD}neg${EBOLD}
  for negative for the leading coefficient. You must have the
  corresponding multiplicity correct for each zero in order to
  receive credit!
  $BR
  END_TEXT
}
Context()->normalStrings;
PeriodicStatus(); 


ENDDOCUMENT();
In reply to Patrick Spencer

Re: Adding pop-up lists to MultiAnswers

by Davide Cervone -
You might also try using something like
     singleResult => 1,
     format => "%s is %s, %s is %s, %s is %s",
     tex_format => "%s\text{ is }%s,\ %s\text{ is }%s,\ %s \text{ is } %s",
with the MultiAnswer object to reduce the size of the results table when a student enters their answers.
In reply to Davide Cervone

Re: Adding pop-up lists to MultiAnswers

by Patrick Spencer -
Davide,

Thank you for the help and sorry for the late reply, I had notifications turned off.

I'm a little confused about what was the part in your first reply you were suggesting I implement. I didn't see a reference to the $ma = MultiAnswer(@answers) object.

I think we are just going to leave it as it is because the chance of messing something up is too much.

Again thanks for the reply! There's a lot of good perl code I hadn't known about and can use later.

Best,
Patrick
In reply to Patrick Spencer

Re: Adding pop-up lists to MultiAnswers

by Davide Cervone -
Sorry, my post got mangled. (The less-than signs got interpreted as HTML, and so large chunks of the code was lost.)

I've fixed the post, and highlighted the one line that does the popup. It is right above the definition of the MultiAnswer object.