Parent Directory
|
Revision Log
Added two methods for naming the blanks in ans_array. The names now have the format ArRaY3[1,0,2] (this would be the name of the 3rd answer (it's taken from main::answer_count which is then incremented so the answer before it is AnSwEr2 and the answer after it is AnSwEr4) and it would be the second matrix or vector in the answer ( I need to take multiple vectors for things like basis cmp, so ans_array_extension puts the vectors in different locations) and the 0 and 2 are row and column in that matrix or vector.
1 #!/usr/local/bin/webwork-perl 2 3 # This file provided the fundamental macros for the pg language 4 # These macros define the interface between the problems written by 5 # the professor and the processing which occurs in the script 6 # processProblem.pl 7 8 9 BEGIN { 10 be_strict(); 11 } 12 13 sub _PG_init{ 14 15 } 16 17 #package PG; 18 19 20 =head1 NAME 21 22 PG.pl --- located in the courseScripts directory. 23 Defines the Program Generating language at the most basic level. 24 25 =head1 SYNPOSIS 26 27 The basic PG problem structure: 28 29 DOCUMENT(); # should be the first statment in the problem 30 loadMacros(.....); # (optional) load other macro files if needed. 31 # (loadMacros is defined in F<dangerousMacros.pl>) 32 33 HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems. 34 35 # # insert text of problems 36 TEXT("Problem text to be", 37 "displayed. Enter 1 in this blank:", 38 ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long. 39 # It is defined in F<PGbasicmacros.pl> 40 ); 41 42 43 ANS( answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors. 44 45 ENDDOCUMENT() # must be the last statement in the problem 46 47 48 49 =head1 DESCRIPTION 50 51 As described in the synopsis, this file and the macros C<DOCUMENT()> and C<ENDDOCUMENT()> determine 52 the interface between problems written in the PG language and the rest of B<WeBWorK>, in particular 53 the subroutine C<createPGtext(()> in the file F<translate.pl>. 54 55 C<DOCUMENT()> must be the first statement in each problem template. 56 It initializes variables, 57 in particular all of the contents of the 58 environment variable become defined in the problem enviroment. 59 (See 60 L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>) 61 62 ENDDOCUMENT() must the last executable statement in any problem template. It returns 63 the rendered problem, answer evaluators and other flags to the rest of B<WeBWorK>, specificially 64 to the routine C<createPGtext()> defined in F<translate.pl> 65 66 67 The C<HEADER_TEXT()>, C<TEXT()>, and C<ANS()> functions load the 68 header text string, the problem text string. 69 and the answer evaulator queue respectively. 70 71 72 =cut 73 74 75 # Private variables for the PG.pl file. 76 77 my ($STRINGforOUTPUT, $STRINGforHEADER_TEXT, @PG_ANSWERS, @PG_UNLABELED_ANSWERS); 78 my %PG_ANSWERS_HASH ; 79 80 # DOCUMENT must come early in every .pg file, before any answers or text are 81 # defined. It initializes the variables. 82 # It can appear only once. 83 84 =head2 DOCUMENT() 85 86 C<DOCUMENT()> must be the first statement in each problem template. It can 87 only be used once in each problem. 88 89 C<DOCUMENT()> initializes some empty variables and via C<INITIALIZE_PG()> unpacks the 90 variables in the C<%envir> variable which is implicitly passed to the problem. It must 91 be the first statement in any problem template. It 92 also unpacks any answers submitted and places them in the C<@submittedAnswer> list, 93 saves the problem seed in C<$PG_original_problemSeed> in case you need it later, and 94 initializes the pseudo random number generator object in C<$PG_random_generator>. 95 96 You can reset the standard number generator using the command: 97 98 $PG_random_generator->srand($new_seed_value); 99 100 (See also C<SRAND> in the L<PGbasicmacros.pl> file.) 101 102 The 103 environment variable contents is defined in 104 L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html> 105 106 107 =cut 108 109 sub DOCUMENT { 110 $STRINGforOUTPUT =""; 111 $STRINGforHEADER_TEXT =""; 112 @PG_ANSWERS=(); 113 @main::PG_ANSWER_ENTRY_ORDER = (); 114 @PG_UNLABELED_ANSWERS = (); 115 %PG_ANSWERS_HASH = (); 116 $main::ANSWER_PREFIX = 'AnSwEr'; 117 %main::PG_FLAGS=(); #global flags 118 $main::showPartialCorrectAnswers = 0 unless defined($main::showPartialCorrectAnswers ); 119 $main::showHint = 1 unless defined($main::showHint); 120 $main::solutionExists =0; 121 $main::hintExists =0; 122 %main::gifs_created = (); 123 124 die "The environment variable envir has not been defined" unless defined(%main::envir); 125 126 foreach my $var ( keys %main::envir ) { 127 eval("\$main::$var =\$main::envir{'$var'}"); 128 warn "Problem defining ", q{\$main::$var}, " while inititializing the PG problem: $@" if $@; 129 } 130 131 @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers); 132 $main::PG_original_problemSeed = $main::problemSeed; 133 $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator."; 134 $main::ans_rule_count = 0; # counts questions 135 136 # end unpacking of environment variables. 137 } 138 139 # HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such 140 # as javaScript code. 141 142 =head2 HEADER_TEXT() 143 144 145 HEADER_TEXT("string1", "string2", "string3"); 146 147 The C<HEADER_TEXT()> 148 function concatenates its arguments and places them in the output 149 header text string. It is used for material which is destined to be placed in 150 the header of the html problem -- such as javaScript code. 151 It can be used more than once in a file. 152 153 154 =cut 155 156 sub HEADER_TEXT { 157 my @in = @_; 158 $STRINGforHEADER_TEXT .= join(" ",@in); 159 } 160 161 # TEXT is the function which defines text which will appear in the problem. 162 # All text must be an argument to this function. Any other statements 163 # are calculations (done in perl) which will not directly appear in the 164 # output. Think of this as the "print" function for the .pg language. 165 # It can be used more than once in a file. 166 167 =head2 TEXT() 168 169 TEXT("string1", "string2", "string3"); 170 171 The C<TEXT()> function concatenates its arguments and places them in the output 172 text string. C<TEXT()> is the function which defines text which will appear in the problem. 173 All text must be an argument to this function. Any other statements 174 are calculations (done in perl) which will not directly appear in the 175 output. Think of this as the "print" function for the .pg language. 176 It can be used more than once in a file. 177 178 =cut 179 180 sub TEXT { 181 my @in = @_; 182 $STRINGforOUTPUT .= join(" ",@in); 183 } 184 185 186 187 =head2 ANS() 188 189 ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...) 190 191 Places the answer evaluators in the unlabeled answer_evaluator queue. They will be paired 192 with unlabeled answer rules (answer entry blanks) in the order entered. This is the standard 193 method for entering answers. 194 195 LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...) 196 197 Places the answer evaluators in the labeled answer_evaluator hash. This allows pairing of 198 labeled answer evaluators and labeled answer rules which may not have been entered in the same 199 order. 200 201 =cut 202 203 sub ANS{ # store answer evaluators which have not been explicitly labeled 204 my @in = @_; 205 while (@in ) { 206 warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to 207 subroutines<BR>") 208 unless ref($in[0]); 209 push(@PG_ANSWERS, shift @in ); 210 } 211 } 212 sub LABELED_ANS { #a better alias for NAMED_ANS 213 &NAMED_ANS; 214 } 215 216 sub NAMED_ANS{ # store answer evaluators which have been explicitly labeled (submitted in a hash) 217 my @in = @_; 218 while (@in ) { 219 my $label = shift @in; 220 my $ans_eval = shift @in; 221 TEXT("<BR><B>Error in NAMED_ANS:$in[0]</B> 222 -- inputs must be references to subroutines<BR>") 223 unless ref($ans_eval); 224 $PG_ANSWERS_HASH{$label}= $ans_eval; 225 } 226 } 227 sub RECORD_ANS_NAME { # this maintains the order in which the answer rules are printed. 228 my $label = shift; 229 push(@main::PG_ANSWER_ENTRY_ORDER, $label); 230 $label; 231 } 232 233 sub NEW_ANS_NAME { # this keeps track of the answers which are entered implicitly, 234 # rather than with a specific label 235 my $number=shift; 236 my $label = "$main::ANSWER_PREFIX$number"; 237 push(@PG_UNLABELED_ANSWERS,$label); 238 $label; 239 } 240 sub ANS_NUM_TO_NAME { # This converts a number to an answer label for use in 241 # radio button and check box answers. No new answer 242 # name is recorded. 243 my $number=shift; 244 my $label = "$main::ANSWER_PREFIX$number"; 245 $label; 246 } 247 248 my $vecnum; 249 250 sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers which are entered implicitly, 251 # rather than with a specific label 252 my $number=shift; 253 $vecnum = 0; 254 my $row = shift; 255 my $col = shift; 256 my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]"; 257 push(@PG_UNLABELED_ANSWERS,$label); 258 $label; 259 } 260 261 sub NEW_ANS_ARRAY_NAME_EXTENSION { # this keeps track of the answers which are entered implicitly, 262 # rather than with a specific label 263 my $number=shift; 264 my $row = shift; 265 my $col = shift; 266 if( $row == 0 && $col == 0 ){ 267 $vecnum += 1; 268 } 269 my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]"; 270 $label; 271 } 272 273 # ENDDOCUMENT must come at the end of every .pg file. 274 # It exports the resulting text of the problem, the text to be used in HTML header material 275 # (for javaScript), the list of answer evaluators and any other flags. It can appear only once and 276 # it MUST be the last statement in the problem. 277 278 =head2 ENDDOCUMENT() 279 280 ENDDOCUMENT() must the last executable statement in any problem template. It can 281 only appear once. It returns 282 an array consisting of 283 284 A reference to a string containing the rendered text of the problem. 285 A reference to a string containing text to be placed in the header 286 (for javaScript) 287 A reference to the array containing the answer evaluators. 288 (May be changed to a hash soon.) 289 A reference to an associative array (hash) containing various flags. 290 291 The following flags are set by ENDDOCUMENT: 292 (1) showPartialCorrectAnswers -- determines whether students are told which 293 of their answers in a problem are wrong. 294 (2) recordSubmittedAnswers -- determines whether students submitted answers 295 are saved. 296 (3) refreshCachedImages -- determines whether the cached image of the problem 297 in typeset mode is always refreshed (i.e. setting this to 1 means cached 298 images are not used). 299 (4) solutionExits -- indicates the existence of a solution. 300 (5) hintExits -- indicates the existence of a hint. 301 (6) showHintLimit -- determines the number of attempts after which hint(s) will be shown 302 303 (7) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order 304 (a) A problem grader specified by the problem using: 305 install_problem_grader(\&grader); 306 (b) One of the standard problem graders defined in PGanswermacros.pl when set to 307 'std_problem_grader' or 'avg_problem_grader' by the environment variable 308 $PG_environment{PROBLEM_GRADER_TO_USE} 309 (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE} 310 (d) The default &std_problem_grader defined in PGanswermacros.pl 311 312 313 =cut 314 315 sub ENDDOCUMENT { 316 317 my $index=0; 318 foreach my $label (@PG_UNLABELED_ANSWERS) { 319 if ( defined($PG_ANSWERS[$index]) ) { 320 $PG_ANSWERS_HASH{"$label"}= $PG_ANSWERS[$index]; 321 } else { 322 warn "No answer provided by instructor for answer $label"; 323 } 324 $index++; 325 } 326 327 $STRINGforOUTPUT .="\n"; 328 ##eval q{ #make sure that "main" points to the current safe compartment by evaluating these lines. 329 $main::PG_FLAGS{'showPartialCorrectAnswers'} = $main::showPartialCorrectAnswers; 330 $main::PG_FLAGS{'recordSubmittedAnswers'} = $main::recordSubmittedAnswers; 331 $main::PG_FLAGS{'refreshCachedImages'} = $main::refreshCachedImages; 332 $main::PG_FLAGS{'hintExists'} = $main::hintExists; 333 $main::PG_FLAGS{'showHintLimit'} = $main::showHint; 334 $main::PG_FLAGS{'solutionExists'} = $main::solutionExists; 335 $main::PG_FLAGS{ANSWER_ENTRY_ORDER} = \@main::PG_ANSWER_ENTRY_ORDER; 336 $main::PG_FLAGS{ANSWER_PREFIX} = $main::ANSWER_PREFIX; 337 # install problem grader 338 if (defined($main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) ) { 339 # problem grader defined within problem -- no further action needed 340 } elsif ( defined( $main::envir{PROBLEM_GRADER_TO_USE} ) ) { 341 if (ref($main::envir{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) { # user defined grader 342 $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = $main::envir{PROBLEM_GRADER_TO_USE}; 343 } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) { 344 if (defined(&std_problem_grader) ){ 345 $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl 346 } # std_problem_grader is the default in any case so don't give a warning. 347 } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) { 348 if (defined(&avg_problem_grader) ){ 349 $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl 350 } 351 #else { # avg_problem_grader will be installed by PGtranslator so there is no need for a warning. 352 # warn "The problem grader 'avg_problem_grader' has not been defined. Has PGanswermacros.pl been loaded?"; 353 #} 354 } else { 355 warn "Error: $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} is not a known program grader."; 356 } 357 } elsif (defined(&std_problem_grader)) { 358 $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl 359 } else { 360 # PGtranslator will install its default problem grader 361 } 362 ##}; 363 warn "ERROR: The problem grader is not a subroutine" unless ref( $main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) eq 'CODE' 364 or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'std_problem_grader' 365 or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'avg_problem_grader'; 366 # return results 367 (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,\%main::PG_FLAGS); 368 } 369 370 371 372 =head2 INITIALIZE_PG() 373 374 This is executed each C<DOCUMENT()> is called. For backward compatibility 375 C<loadMacros> also checks whether the C<macroDirectory> has been defined 376 and if not, it runs C<INITIALIZE_PG()> and issues a warning. 377 378 =cut 379 380 381 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |