blank.gif

webreview.com - Cross-Training for Web Teams
Search for:  
Jump to: 
blank.gif
blank.gif

Perl
Related Articles

Find
Search
List Issues
List Departments
List Topics

Web Tools Guide

NEW!
Buy Software at the
Web Tools Store


Community
Ask Away

Authoring
HTML
Dynamic HTML
JavaScript
Style Sheets

Design
Fonts
Graphics
Navigation
Usability
Web Design

Development
Databases
Java
Perl
XML

eCommerce
Advertising
Legal
Storefronts

Multimedia
Audio/Video
Animation
Shockwave

Site Management
Networks
Security
Servers
Traffic

 

A Songline PACE Production

Online QuiZZer Version 1.2

by Brent Michalski
Jan. 22, 1999

Welcome to part 3 of the continuing Online QuiZZer saga. Parts of this program have been difficult, but they have been well worth the trouble. Without problems to solve, a programmer's life would be pretty boring.

Previous articles in this series:

Dec. 18:
An Online QuiZZer
Jan. 8:
An Online QuiZZer Version 1.1
View the demo
View the demo of this week's program.

In this version of the QuiZZer program, we get to add a routine that allows the user to jump back and answer any questions that they may have skipped. We also add a simple scoring subroutine so that we can present the user with their score when they are finished.

Diving in

The program this week is quite long, 242 lines, so I want to jump right in!

There are a couple subroutines in this week's listing that didn't change from the last article. For sake of brevity, I will provide a link back to the previous article instead of explaining all of the code again.

The program is run by calling the script directly, and passing the name of the quiz text file (ie http://webreview.com/1999/01/22/perl/quizzer.cgi?test1.txt ). It uses the text file for its questions and answers.

I have numbered the lines of code, the line numbers are not part of the program. You can also view the program without the line numbers. The line numbers make it easier for me to talk about the program.

 1: #!/usr/bin/perl -T
 2: #######################
 3: # Online Quiz Program #
 4: # By: Brent Michalski #
 5: # Version: 1.2        #
 6: #######################
 7: use CGI qw(:standard);
 8: print header;
 9: $script = "/cgi-bin/quizzer.cgi";  # The script name.
10: $test_name = $ENV{QUERY_STRING};
11: $[ = 1;  # Sets index of first array element to 1.
12: $counter = 1;
13: $FINALIZE = "";
14: @ANS = ('A','B','C','D','E');
15: $finalize_test = param(finalize);
16: if(param(button_val) =~ /prev/i){
17:   $current = param(prev);
18:  } elsif(param(button_val) =~ /score/i){
19:   &score_test;
20:  } elsif(param(finalize_sub) =~ /finalize/i){
21:   $FINALIZE = "<INPUT TYPE=HIDDEN NAME=\"finalize\"
        VALUE=\"finalize\">";
22:  } else {
23:   $current = param(next_rec);
24: } # End of if.
        
25: $current  = 1 if(($current eq "") || ($current < 1));
26: if(param(GoTo) ne ""){
27:     $goto = param(GoTo);
28:     $goto =~ s/[ \*]//g;
29:     $current = $goto;
30: }

31: $next     = $current + 1;
32: $prev     = $current - 1;
33: if($prev < 1){ $prev = 1; }
34: $question = "Q".$current; # The Question placeholder.
35: &make_current;
36: $total_questions = @question;
37: &make_saved_hash;
38: if($FINALIZE eq ""){ &get_answer; }
39: &make_saved_variable;
40: if($current > $total_questions){ &finalize; }
41: if($finalize_test ne "")       { &finalize; }
42: &print_question;
43: ############################################
44: ##         End of main program.           ##
45: ############################################
46: sub print_question{
47: print<<HTML;
48:  <HTML><HEAD><TITLE>Online Quizzer</TITLE></HEAD>
49:   <BODY BGCOLOR="#FFFFFF">
50:    <CENTER>
51:     <H2>Question $current of $total_questions 
        questions</H2>
52:    </CENTER>
53:    <P><HR>
54:    <FORM METHOD=POST ACTION="$script?$test_name">
55:     <B>
56:      $question[$current]->{QUESTION}
57:     </B>
58:     <BLOCKQUOTE>
59: HTML
60: foreach $val (@ANS){
61:   $CHECKED = ""; # Set this variable to nothing.
62:   if($question[$current]->{$val} ne ""){
63:     if ($answer{$current} =~ /$val/i) { 
        $CHECKED = "CHECKED"; }
64:     print "<INPUT TYPE=CHECKBOX NAME=$question 
        VALUE=$val $CHECKED>
65:            $question[$current]->{$val}<BR>";
66:   }
67: }
68: print<<HTML;
69:     </BLOCKQUOTE>
70:    <P><HR>
71:    <CENTER>
72:     <INPUT TYPE=HIDDEN NAME=saved_answers 
        VALUE="$saved_answers">
73:     <INPUT TYPE=HIDDEN NAME=current VALUE=$current>
74:     <INPUT TYPE=HIDDEN NAME=next_rec VALUE=$next>
75:     <INPUT TYPE=HIDDEN NAME=prev VALUE=$prev>
76:     $FINALIZE
77: HTML
78:   if($FINALIZE eq ""){
79:     print<<HTML;
80:     <INPUT TYPE=SUBMIT VALUE="Answer And Move On" 
        NAME="button_val">
81:     <P>
82:     <INPUT TYPE=SUBMIT VALUE="Previous Question" 
        NAME="button_val">  
83: HTML
84:    } else {
85:      print "<INPUT TYPE=SUBMIT VALUE=\"Answer Question\" 
        NAME=\"button_val\">";
86:    }  
87:    print<<HTML;
88:    </FORM>
89:   </CENTER>
90:  </BODY>
91: </HTML>
92: HTML
93: exit;
94: } # End of print_question subroutine.

95: sub make_record{
96:   $record = {
97:     QUESTION => $QUESTION,
98:     A        => $A,
99:     B        => $B,
100:     C        => $C,
101:     D        => $D,
102:     E        => $E,
103:     ANSWER   => $ANSWER,
104:   };
105:   $question[$counter] = $record;        
106:   $QUESTION=$A=$B=$C=$D=$E=$ANSWER="";
107: } # End of make_record subroutine.

108: sub make_current{
109:   open (QUIZ,"$test_name") || 
        die "Couldn't open file! $!\n";
110:    while (<QUIZ>){
111:     if(/^(A|B|C|D|E)\)/){
112:       $$1 = $_;
113:      } elsif (/^ANSWER:/){
114:       $ANSWER = $_;
115:      } elsif (/^(\015?\012)$/){ 
116:       &make_record;
117:       $counter++;
118:      } else {
119:       $QUESTION .= $_;
120:       $QUESTION =~ s/\015?\012/<BR>/g;
121:     } # End of if..elsif..else
122:   }  # End of while
123:   close(QUIZ);
124: } # End of make_current subroutine.

125: sub get_answer{
126:   my $current = param(current);
127:   $q_num = "Q".$current;
128:   @current_answers = param($q_num);
  
129:   foreach(@current_answers){ 
130:     $curr_answer .= $_; 
131:   } # End of foreach.
132:   $answer{$current} = $curr_answer;
133: } # End of get_answer.

134: sub make_saved_hash{
135:   @saved_array = split '~', param(saved_answers);
  
136:   foreach (@saved_array){
137:     ($key, $value) = split '=';
138:     $answer{$key}  = $value;
139:   } # End of foreach.
  
140: } # End of make_saved_hash.

141: sub make_saved_variable{
142:   foreach $key (keys %answer){
143:     $saved_answers .= 
        $key . '=' . $answer{$key} . '~';
144:     $saved_answers =~ s/^=~//;
145:   } # End of foreach.
  
146: } # End of make_saved_variable.
147: sub finalize{
148:   &make_saved_hash;
149:   &get_answer;
150:  print<<HTML;
151:  <HTML><HEAD><TITLE>Online Quizzer</TITLE></HEAD>
152:   <BODY BGCOLOR="#FFFFFF">
153:    <CENTER>
154:     <H2>Ready For Your Score?</H2>
155:    </CENTER>
156:    <CENTER><TABLE WIDTH=75% BORDER=0><TD>
157:    <FORM METHOD=POST ACTION="$script?$test_name">
158:    <P><HR>
159:    <CENTER><B>You have reached the end of the test.</B>
160:    <P>
161:    <TABLE BORDER=1 CELLSPACING=0>
162:    <TR><TD BGCOLOR="d0d0d0"><CENTER><B>Questions</B>
        </TD></TR>
163:    <TR><TD BGCOLOR="e0e0e0"><CENTER>
164: HTML
   
165:   $y=0; 
166:   for ($x=1;$x<=$total_questions;$x++){
167:     $this_answer = $answer{$x};
168:     if($answer{$x} eq ""){
169:       print "<INPUT TYPE=SUBMIT VALUE=\" *$x* 
        \" NAME=\"GoTo\"> ";
170:     } else {
171:       print "<INPUT TYPE=SUBMIT VALUE=\"  $x  
        \" NAME=\"GoTo\"> ";
172:     } # End of if..else.
173:     $y++;
174:     if(($y >= 5) && ($y < $total_questions)){
175:            print "</CENTER></TD></TR>
        <TR><TD BGCOLOR=\"e0e0e0\"><CENTER>";
176:            $y=0;
177:     } # End of if.
178:   } # End of for loop.
179:   print<<HTML;
180:    </CENTER></TD></TR></TABLE>
181:    <P>
182:     You may click on the numbered buttons to 
183:     review/change your answers.  Any numbers 
        with astericks (*) next to them 
        are unanswered questions.  <P> 
184:     You may want to go back and answer those.
185:    <P><HR>
186:    <CENTER>
187:     <INPUT TYPE=HIDDEN NAME=finalize_sub 
        VALUE=\"finalize\">
188:     <INPUT TYPE=HIDDEN NAME=saved_answers 
        VALUE="$saved_answers">
189:     <INPUT TYPE=HIDDEN NAME=current VALUE=$current>
190:     <INPUT TYPE=HIDDEN NAME=next_rec VALUE=$next>
191:     <INPUT TYPE=HIDDEN NAME=prev VALUE=$prev>
192:     $FINALIZE
193:     <INPUT TYPE=SUBMIT VALUE="I can't wait, 
        score the test already!" NAME="button_val">
194:     <P>
195:     <B><I>Note:</I></B> Once you score the test, 
        you cannot change your answers.
196:       Please make any answer changes <I>before</I> 
        you click the "score" button.
197:    </FORM>
198:    </TD></TABLE></CENTER>
199:   </CENTER>
200:  </BODY>
201: </HTML>
202: HTML
        
203:   exit;
204: } # End of finalize.
205: sub score_test{
206:   &make_current;
207:   &make_saved_hash;
208:   $Score = 0;
209:   print<<HTML;
210:   <HTML><BODY BGCOLOR="#FFFFFF"><FONT SIZE=6><CENTER>
211:   Here is your score
212:   </CENTER></FONT><HR WIDTH=75%>
213:   <CENTER><TABLE BORDER=0><TD>
214:   <PRE>
215: HTML
 
216:   for($x=1;$x<$counter;$x++){
217:     $q_score            = 0;
218:    @you                = split //, $answer{$x};
219:    $correct_ans        = $question[$x]->{ANSWER};
220:    $correct_ans        =~ s/^ANSWER:|\W//g;
221:    @correct            = split //, $correct_ans;
222:      $possible_this_ques = @correct;
223:    $total_possible     = $counter-1;
        
224:    foreach $temp (@you){
225:            if($correct_ans =~ /$temp/){ $q_score++; }
226:            if($correct_ans !~ /$temp/){ $q_score--; }
227:            if($q_score < 0)           { $q_score = 0; }
228:     }
     
229:     $points  = ($q_score/$possible_this_ques);
230:     $goodjob = "Good Job!\n\n" if($points == 1);
231:     $goodjob = "Not Bad!\n\n"  if(($points < 1) && 
        ($points > .5));
232:     $goodjob = "Oops!\n\n"     if($points < .5);
    
233:     print "Question $x: \n";
234:     print " - You answered: $answer{$x} -- 
        Correct answer is: $correct_ans\n";
235:     printf ("  Points: %.2f $goodjob", $points);
236:     $Score += $points;
237:   } # End of for.
        
238:   printf ("You got %.2f out of a possible 
        $total_possible\n", $Score);
239:   printf ("For a grade of: %.2f\%", 
        (($Score/$total_possible) * 100));      
240:   print "</PRE></TD></TABLE></CENTER>
        <HR WIDTH=75%></BODY></HTML>";    
 
241:   exit;
242: } # End of score_test subroutine.

Line-by-line explanation

Line 1: Tells the program where to find Perl on the Web server. This line will vary depending on where Perl is installed on your server so you need to make any necessary changes. On a UNIX server, this line is required. If you are running this program on an NT server, this line is not required but won't hurt anything if included.

Lines 2-6: A comment that identifies the program and who wrote it.

Line 7: Loads the CGI.pm module into the program and imports the standard function definitions. By using the standard definitions, you don't have to use the $cgi->function conventions.

Line 8: Prints the standard header for CGI scripts. The header tells the Web server what kind of data it is sending. This line is equivalent to the following line:

print "Content-type: text/html\n\n";

Line 9: Creates a variable which holds the path and name of this script. We use this later in the HTML forms.

Line 10: Reads the test name from the URL and stores it in the variable $test_name. In the previous version, we passed both the test name and the current question number on the URL. In this version, I stopped passing the question number via the URL and instead, put it into a hidden HTML form variable.

Anything that is passed after the ? on the URL is sent via the QUERY_STRING environment variable, so that is how we end up getting this value from the URL.

Line 11: This is what I call one of Perl's funky variables. The $[ variable sets the index of the first element in the arrays. I am setting it to 1 because the questions are numbered from 1 and up, so I thought it would be easier if we stored them with the index starting at 1.

Line 12: Sets a variable called $counter to 1.

Line 13: Sets a variable called $FINALIZE to nothing. We'll use this variable a bit later.

Line 14: Sets up an array of answer values. This is used later when we loop and display the answer choices.

Line 15: Reads in the value of the finalize HTML form value from the calling HTML form. The subroutine param is part of the CGI module. It reads in and tidies up the values passed via the HTML forms.

Line 16: Begins an if..elsif..else block that determines what we should do at this point. This first if portion checks the value of the form button named button_val from the calling page. If it is equal to prev, the if statement evaluates true and the code inside it is executed.

The param(button_val) =~ /prev/i inside of the if statement means:

The =~ is the binding operator, it binds the expression to the left of it to the expression on the right. This means that the code on the right side is performing its operation on the value from the left side of the binding operator.

The /prev/i is the matching operator. (Actually the // by itself is the matching operator. The text in between the //'s is what we are looking for and the i at the end tells Perl to ignore the case of what we are trying to match.

Line 17: Sets $current to the value passed in from the prev HTML form item on the calling page.

Line 18: Checks to see if the button value was score, if it was, then the code inside this block gets executed.

Line 19: Calls the score_test subroutine.

Line 20: Checks to see if the value of the finalize_sub variable from the calling web page contained finalize, if so - the code on line 21 is executed.

Line 21: Sets the $FINALIZE variable to the value on the right.

Line 22: Our else condition. If none of the above conditions matched, we go here.

Line 23: Sets the $current variable to the value that was passed in from the next_rec HTML form element.

Line 24: Ends the if..elsif..else statement.

Line 25: Sets the $current variable to 1 if it was blank or less than 1.

Line 26: If the HTML form value GoTo contains something, we enter this block of code.

Line 27: Sets a variable valled $goto to the value passed from the calling HTML form element named GoTo.

Line 28: Gets rid of any spaces or asterisks in the $goto variable.

Line 29: Sets the $current variable to the value stored in $goto. This is used for jumping to arbitrary questions to change answers before the test is scored.

Line 30: Closes the if block.

Line 31: Sets $next to one greater than $current. This allows us to get the next question.

Line 32: Sets $prev to one less than $current. This allows us to get the previous question.

Line 33: If the value of $prev is less than 1, we set it to 1.

Line 34: Creates a variable that we use in the HTML form later on, it will become the name of the checkboxes on the form. With all of the checkboxes having the same name, it causes a list of values to be sent if there are multiple answers.

Line 35: Calls the make_current subroutine. This subroutine creates the records which contain all of the test data.

Line 36: Counts the number of questions for us and stores the result in $total_questions

Line 37: Calls the make_saved_hash subroutine. This subroutine creates a hash with all of the previous answers in it.

Line 38: If $FINALIZE is blank, calls the get_answer subroutine. This subroutine gets what the user answered for the previous question. When I refer to the previous question, I mean the question that was just answered by the user.

We don't want to get the previous answer if we are in the finalize subroutine. If we do, we end up losing the previous answer.

Line 39: Calls the make_saved_variable subroutine. This subroutine reconstructs the hash we created on line 37 so that we can pass it back to the HTML form.

Line 40: Calls the finalize subroutine if we are past the last question. The finalize subroutine checks to make sure we answered all of the questions. It then presents us with one last chance to review questions before scoring the test.

Line 41: If the finalize_test variable has a value in it, then we call the finalize subroutine.

Line 42: Calls the print_question subroutine to display the question.

Lines 43-45: A fancy-looking comment.

Lines 46-53: Begin the print_question suboutine. This subroutine prints out the current question.

Line 54: Notice the ACTION value in the FORM tag. It contains the script name. This line was changed from the last version.

Lines 55-59: More HTML for the question page.

Note: The block which begins on line 47 and ends on line 59 is called a here document. A here document allows you to print a bunch of text without having to escape quotes or put the word print on every line.

The HTML on the lines is simply the tag which begins and ends the here document. It can be named just about anything, I commonly use HTML but you could easily use something like BRENT.

One important note that is a major gotcha for programmers is that the closing tag must be flush to the left and there can be nothing else on the line, not even a comment.

Line 60: Begins a foreach loop that iterates through the @ANS array.

Line 61: Sets the variable $CHECKED to nothing.

Line 62: An if statement to check and see if the current value is not blank.

Line 63: Checks to see if the value in $answer{$current} is also in $val, if so, the user had previously checked this value so we want to keep it checked. Therefore, we set the variable $CHECKED to CHECKED.

Lines 64-65: Prints out the CHECKBOX in HTML and puts the current answer on the line next to it.

Lines 66-67: Close the if statement and the foreach loop.

Lines 68-77: Print out more HTML for the page. Most of this HTML code is hidden variables that we use to keep track of where we are and what we are doing. Line 76 only prints something if there is a value stored in $FINALIZE.

Line 78: Checks to see if the $FINALIZE variable has a value in it. If it does not, we enter this block of code.

Lines 79-83: Print out the buttons for the HTML form.

Line 84: If $FINALIZE has a value, then we go into the else block.

Line 85: This also prints out a button for the HTML form, but in this case there is only one button instead of two.

Line 86: Closes the if..else block.

Lines 87-92: Finish off the HTML for the page.

Line 93: Exits the program, we did what we needed to do so we stop execution at this point.

Line 94: Closes the print_question subroutine block.

Lines 95 - 124: Correspond to lines 58 - 87 of the last article.

Line 125: Begins the get_answer subroutine.

Line 126: Creates a my variable called $current and sets the value to the value stored in current from the calling Web page form. A my variable is private or local to the subroutine. The reason I used it was because I didn't remember if I had used the variable name $current elsewhere in the script and didn't want to overwrite any value it may have contained.

Line 127: Sets the $q_num variable to Q plus the number of the previous question. We need to set it to the previous question because when you move on, all of the values are now refering to the current question and we haven't answered that one yet.

Line 128: Gets all of the values that were checked and stores them in an array called @current_answers.

Line 129: Begins a foreach loop that iterates through each of the values in @current_answers.

Line 130: Sets the variable $curr_answer to whatever it previously contained plus the current value read from the array. The .= operator means append onto this variable on my left. It leaves whatever data was stored in it alone.

Line 131: Ends the foreach loop.

Line 132: Sets the hash value at $prev to the value in $curr_answer. So if we just answered question 2 and we are now on question 3, it sets the hash value for question 2 to what we answered. Remember, we are viewing question 3 but have not sent the answer to the server yet.

Line 133: Ends the get_answer subroutine.

Lines 134 - 140: Correspond to lines 114 - 120 of the last article.

Lines 141 - 146: Correspond to lines 121 - 125 of the last article. Except for line 144.

Line 144 was added simply to remove the leading =~ which kept popping up in the variable. It uses the substitution operator which is much like the match operator. The substitution operator has an extra forward slash. This is where the replacement value is written. Like this:

s/look for/replace with/;

Line 147: Begins the finalize subroutine. This subroutine handles checking which questions were skipped and it also allows the user to go back and review/change answers on the test.

Line 148: Calls the make_saved_hash subroutine. This gets all of the previous answers.

Line 149: Calls the get_answer subroutine. If this page was called because we passed the last question, we still need to process that answer. This subroutine call does that for us.

Lines 150-164: A here document which prints out the beginning HTML for the page.

Line 165: Sets a variable called $y to 0.

Line 166: Begins a for loop which goes through each of the questions and checks to see if the user provided an answer or skipped the question.

Line 167: Sets a variable called $this_answer to the value stored in the hash called $answer{$x}. This hash was created by the make_saved_hash subroutine.

Line 168: If the answer was blank, we execute the code inside this block.

Line 169: Sets the button value to the question number with * asterisks around it.

Line 170: If the answer is not blank execute this block.

Line 171: Sets the button value to the question number without asterisks around it.

Line 172: Closes the if..else block.

Line 173: Increments the $y variable.

Line 174: Checks to see if $y is greater than or equal to 5 and less than $total_questions. We are checking this because on the finalize screen, we present the user with buttons which represent the the questions. This makes it so there are no more that 5 buttons per row. You can change the 5 to any number you want to make more or less buttons per row.

Line 175: Prints the HTML needed to end the current row and start a new row.

Line 176: Sets $y back to 0. This is how we keep track of how many items are currently in the row.

Line 177: Closes the if condition.

Line 178: Closes the for loop.

Lines 179-202: These lines are another here document which prints out the rest of the HTML needed for the page.

Lines 187-191 (a little more detail): These lines are the hidden HTML values that store the information we need to score the test and to know where the user is in the test. When you are taking the test, view the HTML source and take a look at the hidden form fields and how they change when you answer questions. (You have to view the source each time you answer a question to see the different values.

Line 203: Exits the program. We have done what we needed so we quit. If we didn't exit, the program would pick up execution a the point where we called this subroutine.

Line 204: Closes the finalize subroutine.

Line 205: Begins the score_test subroutine.

Line 206: Calls the make_current subroutine. This creates the hashes which make up the whole test. It allows us to easily access the test information.

Line 207: Calls the make_saved_hash subroutine. This is the subroutine which reads the answers in from the hidden HTML field and places them in to an easy-to-use hash.

Line 208: Sets $Score to 0.

Lines 209-215: Begins a here document which prints the HTML code for the beginning of the page.

Line 216: Begins a for loop which counts from 1 to $counter. This allows us to go through each test question in order because we used the question number as the key in the hash.

Line 217: Sets $q_score to 0.

Line 218: Splits out the current answer which was stored in the hash %answer and places the results in an array called @you.

We reference the hash like this: $answer{$x} This tells Perl to reference the answer hash and get the value stored with the key $x.

We split at nothing, //, which causes Perl to split at each character. This allows us to get each individual item for the questions that had multiple answers.

So if you had answered A and D, the @you array would have A at element 1 and D at element 2. Normally they would be at elements 0 and 1, but remember we changed this on line 11.

Line 219: Gets the correct answer from the hash and stores it in $correct_ans.

Line 220: Gets rid of ANSWER: which is prepended before the answers in the test file itself.

The ^ tells Perl that this must be at the beginning of the line. So, if you had ANSWER: somewhere in the file but not at the beginning of a line it would not match because the ^ only matches if it is at the line beginning.

Line 221: Now we split the correct answer and store the individual values in the array @correct. We do this for the same resons we did on line 218. It allows us to have multiple answers for a question.

Line 222: Counts the number of possible answers for this question and stores the result in $possible_this_ques. I did this so that if you got 2 parts right but missed a third correct answer, you would only get 2/3 of a point.

Line 223: Gets the total possible points and stores it in $total_possible

Line 224: Starts a foreach loop that goes through each of the values stored in @you. The current value gets stored in $temp.

Line 225: Checks to see if we have a correct answer. If so, we increment $q_score.

Line 226: Checks to see if we have an answer that is not a correct one. If so, we de-increment $q_score.

Line 227: If the test taker gets more wrong than possible, we are nice and only give them 0 points instead of negative points.

Line 228: Closes the foreach loop.

Line 229: Calculates the number of $points for the current question by taking the $q_score and dividing it by $possible_this_ques

Lines 230-232: Check the value of $points and create a text message based upon how the user did. This part adds nothing to the actual functionality of the program, but it will hopefully spawn some other, creative ideas.

Line 233: Prints the question number.

Line 234: Prints what the user answered and what the correct answer is.

Line 235: Prints the number of points for this question. Notice that I used printf here. printf works the same way in Perl as it does in C. The %.2f tells Perl that I want a floating point number with 2 places after the decimal. It makes for a much nicer looking program. Try to use a regular print statement and see the difference.

Line 236: Increments $Score by the value in $points.

Line 237: Closes the for loop.

Line 238: Prints the total $Score.

Line 239: Prints the average. For the average I simply took the $Score and divided it by $total_possible (which was the total number of questions, or points) and then multiplied the result by 100 so we could get a percentage.

Line 240: Finishes the HTML for the page.

Line 241: Exits the program.

Line 219: Closes the score_test subroutine.

Wrapping it up

Well, that does it for this long program. Actually, it really isn't that long.

I am still not sure whether I'll continue to add more features to it, or if I'll let it rest for a while and let you add the extra features that you need. I look at these articles as starting points for people to build upon. Drop me a line and let me know if I should tackle another subject for a while or continue with this one. Remember that just because I take a break from a program for a while doesn't mean that I won't come back to it at a later date.

Perl is a very powerful language which allows you to write concise programs. Actually, with Perl you are free to write concise programs, long programs, obfuscated programs or just about any type you want. Perl lets you be free of the rigid rules which most programming languages impose upon you. Perl lets your artistic side come out!

Until next time, Perl on... ;-)


Source Code for Online QuiZZer Version 1.2
View and download the source to this week's script.


Web Review copyright © 1995-99 Songline Studios, Inc.
Web Techniques and Web Design and Development copyright © 1995-99 Miller Freeman, Inc.
ALL RIGHTS RESERVED