[system] / trunk / pg / macros / PG.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (download) (as text) (annotate)
Wed Jun 11 14:54:27 2003 UTC (16 years, 8 months ago) by lr003k
File size: 13744 byte(s)
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