#!/usr/bin/perl BEGIN{ be_strict; } package main; =head1 NAME PGchoicemacros.pl --- located in the courseScripts directory =head1 SYNPOSIS =for html There are two types of choice macros. The older versions are simply scripts. The newer versions involve the List class and its sub-classes and the use of objects based on these classes. The list sub-classes are: Match which aids in setting up matching question and answer lists, Select which aids in selecting and presenting a subset of questions with short answers (e.g. true/false questions) from a larger question set, and Multiple which aids in setting up a standard style, one question, many answers type multiple choice question. =head1 DESCRIPTION Typical use varies depending on the type of list being used. =for html See the documentation for Multiple.pm, Match.pm, and Select.pm =cut =head2 Matching List macros =head3 new_match_list Matching list object creation macro Useage: =for html
	$ml = new_match_list;
Which is equivalent to the following direct call to Match =for html
	$ml = new Match(random(1,2000,1), ~~&std_print_q, ~~&std_print_a);
=for html Either call will create a matching list object in the variable $ml. ( $ml cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block. The printing methods are passed as references (~~ in PG equals \ in perl) to subroutines so that no matter what printing subroutines are used, those subroutines can be used by saying $ml->print_q and $ml->print_a. This also means that other subroutines can be used instead of the default ones. An example of how to do this is demonstrated with pop_up_list_print_q below. =for html

See the documentation for Match.pm to see how to use this object to create a matching question. =head4 std_print_q Standard method for printing questions =for html This simple printing routine is used to print the questions for each of the three sub-classes of List. When a match list, select list, or multiple choice object is created, a reference to std_print_q is passed to that object so that it can be used from within the object later. std_print_q checks which mode the user is trying to print the questions from and returns the appropriately formatted string. =head4 std_print_a Standard method for printing answers with answer boxes This simple printing routine is used to print the answers for matching lists (and technically select list, even though answers are not printed with a select list). When a match list or select list object is created, a reference to std_print_q is passed to that object so that it can be used from within the object later. std_print_a checks which mode the user is trying to print the answers from and returns the appropriately formatted string. =head2 Select List macros =head3 new_select_list Select list object creation macro Useage: =for html

	$sl = new_select_list;
Which is equivalent to this direct call to Select =for html
	$sl = new Select(random(1,2000,1), ~~&std_print_q, ~~&std_print_a);
=for html Either call will create a select list object in the variable $sl. ( Note that $sl cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block.) The printing methods are passed as references (~~ in PG equals \ in perl) to subroutines so that no matter what printing subroutines are used, those subroutines can be used by saying $sl->print_q and $sl->print_a. This also means that other subroutines can be used instead of the default ones. An example of how to do this is demonstrated with pop_up_list_print_q below. =for html

See the documentation for Select.pm to see how to use this object to create a true/false question. =head4 std_print_q Standard method for printing questions with answer boxes See std_print_q under Matching Lists above. =head4 std_print_a This is only intended to be used for debugging as there is rarely a reason to print out the answers to a select list. See std_print_a under Matching Lists above. =head3 new_pop_up_select_list Select list object creation macro Useage: =for html

	$sl = new_pop_up_select_list;
Which is equivalent to this direct call to Select =for html
	$sl = new Select(random(1,2000,1), ~~&pop_up_list_print_q, ~~&std_print_a);
=for html Either call will create a select list object in the variable $sl. ( Note that $sl cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block.) The printing methods are passed as references (~~ in PG equals \ in perl) to subroutines so that no matter what printing subroutines are used, those subroutines can be used by saying $sl->print_q and $sl->print_a. This also means that other subroutines can be used instead of the default ones. =for html

See the documentation for Select.pm to see how to use this object to create a true/false question. =head4 std_print_q Standard method for printing questions with answer boxes See std_print_q under Matching Lists above. =head4 pop_up_list_print_q Alternate method for print questions with pop up lists. Useage: This printing routine is used to print the questions for a true/false or other select list with a preceding pop up list of possible answers. A list of values and labels need to be given to the pop_up_list so that the intended answer is returned when a student selects an answer form the list. Notethe use of => to associate the values on the left with the labels on the right, this means that, for instance, the student will see the word True in the pop_up_list but the answer that is returned to the grader is T, so that it corresponds with what the professor typed in as the answer when using $sl->qa('blah blah', 'T'); =for html

	$sl->ra_pop_up_list([value => label,
							T => 'True',
							F => 'False']);
=head4 std_print_a This is only intended to be used for debugging as there is rarely a reason to print out the answers to a select list. See std_print_a under Matching Lists above. =head2 Multiple Choice macros =head3 new_multiple_choice Multiple choice object creation macro Useage: =for html
	$mc = new_multiple_choice;
Which is equivalent to this direct call to Multiple =for html
	$mc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&std_print_a);
Either call will create a multiple choice object in the variable $mc. Note that $mc cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block. =for html

See the documentation for Multiple.pm to see how to use this object to create a multiple choice question. =head4 std_print_q Standard method for printing questions See std_print_q under Matching Lists above. =head4 radio_print_a Method for printing answers with radio buttons This simple printing routine is used to print the answers to multiple choice questions in a bulleted style with radio buttons preceding each possible answer. When a multiple choice object is created, a reference to radio_print_a is passed to that object so that it can be used from within the object later. radio_print_a checks which mode the user is trying to print the answers from and returns the appropriately formatted string. =head3 new_checkbox_multiple_choice Checkbox multiple choice object creation macro Useage: =for html

	$cmc = new_checkbox_multiple_choice;
Which is equivalent to this direct call to Multiple =for html
	$cmc = new Multiple(random(1,2000,1), ~~&std_print_q, ~~&checkbox_print_a);
Either call will create a checkbox multiple choice object in the variable $cmc. Note that $cmc cannot be a my variable if it is to be used within a BEGIN_TEXT/END_TEXT block. =for html

See the documentation for Multiple.pm to see how to use this object to create a multiple choice question. =head4 std_print_q Standard method for printing questions See std_print_q under Matching Lists above. =head4 checkbox_print_a Method for printing answers with radio buttons This simple printing routine is used to print the answers to multiple choice questions in a bulleted style with checkboxes preceding each possible answer. When a multiple choice object is created, a reference to checkbox_print_a is passed to that object so that it can be used from within the object later. checkbox_print_a checks which mode the user is trying to print the answers from and returns the appropriately formatted string. =cut #Useage: $ml = new_match_list #Note that $ml cannot be a my variable if used within a BEGIN_TEXT/END_TEXT block sub new_match_list { new Match(random(1,2000,1), \&std_print_q, \&std_print_a); } #Useage: $sl = new_select_list #Note that $sl cannot be a my variable if used within a BEGIN_TEXT/END_TEXT block sub new_select_list { new Select(random(1,2000,1), \&std_print_q, \&std_print_a); } #Useage: $pusl = new_pop_up_select_list sub new_pop_up_select_list { new Select(random(1,2000,1), \&pop_up_list_print_q, \&std_print_a); } #Useage: $mc = new_multiple_choice #Note that $mc cannot be a my variable if used within a BEGIN_TEXT/END_TEXT block sub new_multiple_choice { new Multiple(random(1,2000,1), \&std_print_q, \&radio_print_a); } #Useage: $mcc = new_checkbox_multiple_choice sub new_checkbox_multiple_choice { new Multiple(random(1,2000,1), \&std_print_q, \&checkbox_print_a); } #Useage: $sl->rf_print_a(~~&pop_up_list_print_q); # $sl->ra_pop_up_list([value => label, T => 'True', F => 'False']); sub pop_up_list_print_q { my $self = shift; my (@questions) = @_; my $length = $self->{ans_rule_len}; my @list = @{$self->{ra_pop_up_list} }; my $out = ""; if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { my $i=1; my $quest; foreach $quest (@questions) { $out.= "\n

" . pop_up_list(@list) . " $i. $quest"; $i++; } $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { my $i=1; my $quest; foreach $quest (@questions) { $out.= " \\begin{rawhtml}

\\end{rawhtml}" . pop_up_list(@list) . " $i. \\begin{rawhtml}\\end{rawhtml} $quest"; $i++; } $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { $out = "\n\\par\\begin{enumerate}\n"; my $i=1; my $quest; foreach $quest (@questions) { $out .= "\\item[" . pop_up_list(@list) . "$i.] $quest\n"; $i++; } $out .= "\\end{enumerate}\n"; } else { $out = "Error: PGchoicemacros: pop_up_list_print_q: Unknown displayMode: $main::displayMode.\n"; } $out; } #Standard method of printing answers in a matching list sub std_print_a { my $self = shift; my(@array) = @_; my $i = 0; my $out= &main::M3( "\\begin{enumerate}\n", " \\begin{rawhtml}

    \\end{rawhtml} ", "
      \n" ) ; my $elem; foreach $elem (@array) { $out .= &main::M3( "\\item[$main::ALPHABET[$i].] $elem\n", " \\begin{rawhtml}
    1. \\end{rawhtml} $elem ", "
    2. $elem\n" ) ; $i++; } $out .= &main::M3( "\\end{enumerate}\n", " \\begin{rawhtml}
    \n \\end{rawhtml} ", "
\n" ) ; $out; } #Alternate method of printing answers as a list of radio buttons for multiple choice #radio_print_a2 is used instead now # sub radio_print_a { # my $self = shift; # my (@answers) = @_; # my $num = ++$main::ans_rule_count; # my $out = ""; # if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { # my $ans = shift @answers; # $out .= "\n
" . ' ' x 5 . NAMED_ANS_RADIO(NEW_ANS_NAME($num), $ans, $ans); # foreach $ans (@answers) { # $out.= "\n
" . ' ' x 5 . NAMED_ANS_RADIO_OPTION(ANS_NUM_TO_NAME($num), $ans, $ans); # } # $out .= "
\n"; # } elsif ($main::displayMode eq 'Latex2HTML') { # my $ans = shift @answers; # $out .= "\\begin{rawhtml}
\\end{rawhtml}" . NAMED_ANS_RADIO(NEW_ANS_NAME($num), $ans, $ans); # foreach $ans (@answers) { # $out.= "\\begin{rawhtml}
\\end{rawhtml}" . NAMED_ANS_RADIO_OPTION(ANS_NUM_TO_NAME($num), $ans, $ans); # } # $out .= " \\begin{rawhtml}
\\end{rawhtml} "; # } elsif ($main::displayMode eq 'TeX') { # $out = "\n\\par\\begin{itemize}\n"; # my $ans; # foreach $ans (@answers) { # $out .= "\\item[" . $ans . "\n"; # } # $out .= "\\end{itemize}\n"; # } else { # $out = "Error: PGchoicemacros: match_questions_list_varbox: Unknown displayMode: $main::displayMode.\n"; # } # $out; # # } #Alternate method of printing answers as a list of radio buttons for multiple choice sub radio_print_a { my $self = shift; my (@answers) = @_; my $out = ""; my $i =0; my @in = (); if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], " $main::ALPHABET[$i]. $ans")); $i++; } my @radio_buttons = ans_radio_buttons(@in); $out = "\n
" . join "\n
", @radio_buttons; $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], "\\begin{rawhtml} $main::ALPHABET[$i]. \\end{rawhtml} $ans")); $i++; } my @radio_buttons = ans_radio_buttons(@in); $out = "\\begin{rawhtml}
\\end{rawhtml}" . join "\\begin{rawhtml}
\\end{rawhtml}", @radio_buttons; $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], "$main::ALPHABET[$i]. $ans")); $i++; } my @radio_buttons = ans_radio_buttons(@in); #$out = "\n\\par\\begin{itemize}\n"; $out .= join '', @radio_buttons; #$out .= "\\end{itemize}\n"; } else { $out = "Error: PGchoicemacros: radio_print_a: Unknown displayMode: $main::displayMode.\n"; } $out; } #Second alternate method of printing answers as a list of radio buttons for multiple choice #Method for naming radio buttons is no longer round about and hackish sub checkbox_print_a { my $self = shift; my (@answers) = @_; my $out = ""; my $i =0; my @in = (); if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], " $main::ALPHABET[$i]. $ans")); $i++; } my @checkboxes = ans_checkbox(@in); $out = "\n
" . join "\n
", @checkboxes; $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], "\\begin{rawhtml} $main::ALPHABET[$i]. \\end{rawhtml} $ans")); $i++; } my @checkboxes = ans_checkbox(@in); $out = "\\begin{rawhtml}
\\end{rawhtml}" . join "\\begin{rawhtml}
\\end{rawhtml}", @checkboxes; $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { foreach my $ans (@answers) { push (@in, ($main::ALPHABET[$i], "$main::ALPHABET[$i]. $ans")); $i++; } my @radio_buttons = ans_checkbox(@in); #$out = "\n\\par\\begin{itemize}\n"; $out .= join '', @radio_buttons ; #$out .= "\\end{itemize}\n"; } else { $out = "Error: PGchoicemacros: checkbox_print_a: Unknown displayMode: $main::displayMode.\n"; } $out; } #Standard method of printing questions in a matching or select list sub std_print_q { my $self = shift; my (@questions) = @_; my $length = $self->{ans_rule_len}; my $out = ""; if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { my $i=1; my $quest; foreach $quest (@questions) { $out.= "\n
" . ans_rule($length) . "$i. $quest"; $i++; } $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { my $i=1; my $quest; foreach $quest (@questions) { $out.= " \\begin{rawhtml}
\\end{rawhtml} " . ans_rule($length) . "\\begin{rawhtml}\\end{rawhtml} $i. \\begin{rawhtml}\\end{rawhtml} $quest"; #"$i. $quest"; $i++; } $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { $out = "\n\\par\\begin{enumerate}\n"; my $i=1; my $quest; foreach $quest (@questions) { $out .= "\\item[" . ans_rule($length) . "$i.] $quest\n"; $i++; } $out .= "\\end{enumerate}\n"; } else { $out = "Error: PGchoicemacros: std_print_q: Unknown displayMode: $main::displayMode.\n"; } $out; } #legacy macros #these are only needed for backward compatibility and should be taken out when no longer needed #except for NchooseK which has become common enough that it should probably be moved to a #different macros file and given some documentation sub qa { my($questionsRef,$answersRef,@questANDanswer) = @_; while (@questANDanswer) { push(@$questionsRef,shift(@questANDanswer)); push(@$answersRef,shift(@questANDanswer)); } } sub invert { my @array = @_; my @out = (); my $i; for ($i=0;$i<=$#array;$i++) { $out[$array[$i]]=$i; } @out; } sub NchooseK { my($n,$k)=@_;; my @array = 0..($n-1); my @out = (); while (@out<$k) { push(@out, splice(@array, random(0,$#array,1) , 1) ); } @out; } sub shuffle { my ($i) = @_; my @out = &NchooseK($i,$i); @out; } sub match_questions_list { my (@questions) = @_; my $out = ""; if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { my $i=1; my $quest; foreach $quest (@questions) { $out.= "\n
" . ans_rule(4) . "$i. $quest"; $i++; } $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { my $i=1; my $quest; foreach $quest (@questions) { $out.= " \\begin{rawhtml}
\\end{rawhtml} " . ans_rule(4) . "\\begin{rawhtml}\\end{rawhtml} $i. \\begin{rawhtml}\\end{rawhtml} $quest"; #"$i. $quest"; $i++; } $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { $out = "\n\\par\\begin{enumerate}\n"; my $i=1; my $quest; foreach $quest (@questions) { $out .= "\\item[" . ans_rule(3) . "$i.] $quest\n"; $i++; } $out .= "\\end{enumerate}\n"; } else { $out = "Error: PGchoicemacros: match_questions_list: Unknown displayMode: $main::displayMode.\n"; } $out; } sub match_questions_list_varbox { my ($length, @questions) = @_; my $out = ""; if ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth') { my $i=1; my $quest; foreach $quest (@questions) { $out.= "\n
" . ans_rule($length) . "$i. $quest"; $i++; } $out .= "
\n"; } elsif ($main::displayMode eq 'Latex2HTML') { my $i=1; my $quest; foreach $quest (@questions) { $out.= " \\begin{rawhtml}
\\end{rawhtml} " . ans_rule($length) . "\\begin{rawhtml}\\end{rawhtml} $i. \\begin{rawhtml}\\end{rawhtml} $quest"; #"$i. $quest"; $i++; } $out .= " \\begin{rawhtml}
\\end{rawhtml} "; } elsif ($main::displayMode eq 'TeX') { $out = "\n\\par\\begin{enumerate}\n"; my $i=1; my $quest; foreach $quest (@questions) { $out .= "\\item[" . ans_rule($length) . "$i.] $quest\n"; $i++; } $out .= "\\end{enumerate}\n"; } else { $out = "Error: PGchoicemacros: match_questions_list_varbox: Unknown displayMode: $main::displayMode.\n"; } $out; } 1;