![]() |
![]() Second Summer 2004 |
The problem was this.
So I started by writing this program:
Then Jesse improved on it (disregard the lack of indentation):<? session_start(); if ($age >= 1 && ! $reset) { if ($sum == $answer) { $correct += 1; $message = "Your answer was correct.<p>"; } else { $message = "Your answer was NOT correct.<p>"; } $attempts += 1; $age += 1; $one = rand(0, 100); $two = rand(0, 100); $sum = $one + $two; } else { $correct = 0; session_register("correct"); $attempts = 0; session_register("attempts"); $age = 1; session_register("age"); $message = "Welcome to the game.<p>"; session_register("message"); $one = rand(0, 100); $two = rand(0, 100); $sum = $one + $two; session_register("sum"); } $message .= "What is " . $one . " + " . $two . "?<p>Current state is:" . "(" . $correct . "/" . $attempts . ":" . $age . ")<p>"; ?> <html> <form> <?=$message?> Type your answer here: <input type="text" name="answer"> <p> When done please press <input type="submit" name="proceed" value="Proceed"> <p> <hr> (Or press <input type="submit" name="reset" value="Reset"> to reset the game.) </form> </html>
And he provided a client-side version of it:<? session_start(); if (session_is_registered("stamp") && ! $reset) { if($stampCopy == $stamp){ if ($sum == $answer) { $correct += 1; $message = "Your answer was correct.<p>"; } else { $message = "Your answer was NOT correct.<p>"; } $attempts += 1; $stamp += 1; $one = rand(0, 100); $two = rand(0, 100); $sum = $one + $two; }else{ $message ="Reloading should give you nothing!<p>"; } } else { session_destroy(); session_start(); $stamp = 1; session_register("stamp"); $correct = 0; session_register("correct"); $attempts = 0; session_register("attempts"); $message = "Welcome to the game.<p>"; session_register("message"); $one = rand(0, 100); session_register("one"); $two = rand(0, 100); session_register("two"); $sum = $one + $two; session_register("sum"); } if ($attempts == 10){ $message.="<b>You finished with a score of " . $correct . "/" .$attempts ."</b><p>"; $correct =0; $stamp = 1; $attempts = 0; } $message .= "What is " . $one . " + " . $two . "?<p>Current state is:" . "(" . $correct . "/" . $attempts . ":" . $stamp . ")<p>"; ?> <html> <form> <?=$message?> Type your answer here: <input type="text" name="answer"> <p> When done please press <input type="submit" name="proceed" value="Proceed"> <p> <hr> (Or press <input type="submit" name="reset" value="Reset"> to reset the game.) <input type="hidden" name="stampCopy" value="<?=$stamp?>"> </form> </html>
So I wrote a CGI with hidden fields version of it:<? if ($stamp >= 1 && ! $reset) { if ($one + $two == $answer) { $correct += 1; $message = "Your answer was correct.<p>"; } else { $message = "Your answer was NOT correct.<p>"; } $attempts += 1; $stamp += 1; if ($attempts == 10){ $message .= "<b>You finished with a score of " . $correct . "/" .$attempts . "</b><p>"; $correct =0; $stamp = 1; $attempts = 0; } $one = rand(0, 100); $two = rand(0, 100); $sum = $one + $two; } else { $stamp = 1; $correct = 0; $attempts = 0; $message = "Welcome to the game.<p>"; $one = rand(0, 100); $two = rand(0, 100); $sum = $one + $two; } $message .= "What is " . $one . " + " . $two . "?<p>Current state is:" . "(" . $correct . "/" . $attempts . ":" . $stamp . ")<p>"; ?> <html> <form> <?=$message?> Type your answer here: <input type="text" name="answer"> <p> When done please press <input type="submit" name="proceed" value="Proceed"> <p> <hr> (Or press <input type="submit" name="reset" value="Reset"> to reset the game.) <input type="hidden" name="stamp" value="<?=$stamp?>"> <input type="hidden" name="correct" value="<?=$correct?>"> <input type="hidden" name="attempts" value="<?=$attempts?>"> <input type="hidden" name="one" value="<?=$one?>"> <input type="hidden" name="two" value="<?=$two?>"> </form> </html>
And we converted most of that to CGI/DBI in class on Thu:use CGI; $q = new CGI; print $q->header; print $q->start_html; $stamp = $q->param('stamp'); $correct = $q->param('correct'); $attempts = $q->param('attempts'); $message = $q->param('message'); $one = $q->param('one'); $two = $q->param('two'); $reset = $q->param('reset'); $proceed = $q->param('proceed'); if ($stamp >= 1 && ! $reset) { $answer = $q->param('answer'); if ($one + $two == $answer) { $correct += 1; $message = "Your answer was correct.<p>"; } else { $message = "Your answer was NOT correct.<p>"; } $attempts += 1; $stamp += 1; if ($attempts == 10){ $message .= "<b>You finished with a score of " . $correct . "/" .$attempts . "</b><p>"; $correct =0; $stamp = 1; $attempts = 0; } $one = int(rand(100)); $two = int(rand(100)); } else { $stamp = 1; $correct = 0; $attempts = 0; $message = "Welcome to the game.<p>"; $one = int(rand(100)); $two = int(rand(100)); $sum = $one + $two; } $message .= "What is " . $one . " + " . $two . "?<p>Current state is:" . "(" . $correct . "/" . $attempts . ":" . $stamp . ")<p>"; print qq{ <form> $message Type your answer here: <input type="text" name="answer"> <p> When done please press <input type="submit" name="proceed" value="Proceed"> <p> <hr> (Or press <input type="submit" name="reset" value="Reset"> to reset the game.) <input type="hidden" name="stamp" value="$stamp"> <input type="hidden" name="correct" value="$correct"> <input type="hidden" name="attempts" value="$attempts"> <input type="hidden" name="one" value="$one"> <input type="hidden" name="two" value="$two"> </form> }; print $q->end_html;
But we tweaked Fibonacci into an almost quiz program on Wed:#!/usr/bin/perl use CGI; use DBI; use MD5; $DB = "DBI:mysql:a348"; $username = "a348"; $password = "a348AG"; $DB_TABLE = "dgerman_quiz_prex"; $SECRET = "something secret"; $EXPIRE = 30 * 60 * 60 * 24; # one month $MAX_TRIES = 10; $ID_LENGTH = 8; $q = new CGI; $DBH = DBI->connect($DB, $username, $password, { PrintError => 0 }) || die "Couldn't open database: ", $DBI::errstr; my ($session_id) = &get_session_id(); print $q->header, $q->start_html; my $state = &get_state($session_id); if ($state->{age} < 1) { $state = &initialize($state); } else { $state = &calculate($state); } &save_state($state, $session_id); &status($state); &show_form(); print $q->end_html; $DBH->disconnect; #--------------------------------(end of main program)------ sub show_form { print $q->start_form(), "Type your answer here: <input type=\"text\" name=\"answer\"> " . " <p> When done please press ", $q->submit(-value=>'Proceed'), $q->end_form(); } #--------------------------------(this was our basic form)--- sub get_session_id { &expire_old_sessions(); my ($id) = $q->path_info =~ m:^/([a-h0-9]{$ID_LENGTH}):o; return $id if $id and &check_id($id); my $session_id = &generate_id; die "Couldn't make a new session_id" unless $session_id; print $q->redirect($q->script_name() . "/$session_id"); exit(0); } #--------------------------------(needed above)-------------- sub expire_old_sessions { $DBH->do(<<END); DELETE FROM $DB_TABLE WHERE (unix_timestamp() - unix_timestamp(modified)) > $EXPIRE END } #--------------------------------(also needed above)--------- sub generate_id { my $tries = 0; my $id = &hash($SECRET . rand()); while ($tries++ < $MAX_TRIES) { last if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); $id = &hash($SECRET . rand()); } return undef if $tries >= $MAX_TRIES; return $id; } sub hash { my $value = shift; return substr(MD5->hexhash($value), 0, $ID_LENGTH); } #--------------------------------(last one needed)----------- sub check_id { my $id = shift; return $id if $DBH->do("SELECT 1 FROM $DB_TABLE WHERE session_id = '$id'") > 0; return $id if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); return ''; } #--------------------------------(retrieve acc)-------------- sub get_state { my $id = shift; my $query = "SELECT * FROM $DB_TABLE WHERE session_id = '$id'"; my $sth = $DBH->prepare($query) || die "Prepare: ", $DBH->errstr; $sth->execute || die "Execute: ", $sth->errstr; my $state = $sth->fetchrow_hashref; $sth->finish; return $state; } #--------------------------------(calculate new acc)--------- sub calculate { my $state = shift; $answer = $q->param('answer'); if ($answer == $state->{one} + $state->{two}) { print "Good answer.<p>"; $state->{attempts} += 1; $state->{correct} += 1; } else { print "Bad answer.<p>"; $state->{attempts} += 1; } $state->{age} += 1; $state->{message} = "<p>Transaction no." . $state->{age} . " (" . $state->{correct} . "/" . $state->{attempts} . ")"; $state->{one} = int(rand(100)); $state->{two} = int(rand(100)); return $state; } #--------------------------------(store new acc)------------- sub save_state { my ($state, $id) = @_; my $sth = $DBH->prepare(<<END) || die "Prepare: ", $DBH->errstr; UPDATE $DB_TABLE SET attempts = ?, correct = ?, age = ?, message = ?, one = ?, two = ? WHERE session_id = '$id' END $sth->execute(@{$state}{qw(attempts correct age message one two)}) || die "Execute: ", $DBH->errstr; $sth->finish; } #--------------------------------(print current acc)--------- sub status { my ($state) = @_; print qq{ $state->{message} <p> What is: $state->{one} + $state->{two}? <p> }; } sub initialize { my $state = shift; $state = {} unless $state; $state->{correct} = 0; $state->{attempts} = 0; $state->{age} = 1; $state->{message} = "Welcome"; $state->{one} = int(rand(100)); $state->{two} = int(rand(100)); return $state; }
And the final version required the creation of a new table:#!/usr/bin/perl use CGI; use DBI; use MD5; $DB = "DBI:mysql:a348"; $username = "a348"; $password = "a348AG"; $DB_TABLE = "dgerman_mar4"; $SECRET = "something secret"; $EXPIRE = 30 * 60 * 60 * 24; # one month $MAX_TRIES = 10; $ID_LENGTH = 8; $q = new CGI; $DBH = DBI->connect($DB, $username, $password, { PrintError => 0 }) || die "Couldn't open database: ", $DBI::errstr; my ($session_id) = &get_session_id(); # [1] print $q->header, $q->start_html; my $state = &get_state($session_id); # [2] if (! $state->{one}) { $state = &initialize($state); } # [3] else { $state = &calculate($state); } # [4] &save_state($state, $session_id); # [5] &status($state); # [6] &show_form(); # [7] print $q->end_html; $DBH->disconnect; #--------------------------------(end of main program)------ sub show_form { print $q->start_form(), "Answer: <input type=\"text\" name=\"answer\"> <p> When done please press ", $q->submit(-value=>'Proceed'), $q->end_form(); } #--------------------------------(this was our basic form)--- sub get_session_id { &expire_old_sessions(); my ($id) = $q->path_info =~ m:^/([a-h0-9]{$ID_LENGTH}):o; return $id if $id and &check_id($id); my $session_id = &generate_id; die "Couldn't make a new session_id" unless $session_id; print $q->redirect($q->script_name() . "/$session_id"); exit(0); } #--------------------------------(needed above)-------------- sub expire_old_sessions { $DBH->do(<<END); DELETE FROM $DB_TABLE WHERE (unix_timestamp() - unix_timestamp(modified)) > $EXPIRE END } #--------------------------------(also needed above)--------- sub generate_id { my $tries = 0; my $id = &hash($SECRET . rand()); while ($tries++ < $MAX_TRIES) { last if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); $id = &hash($SECRET . rand()); } return undef if $tries >= $MAX_TRIES; return $id; } sub hash { my $value = shift; return substr(MD5->hexhash($value), 0, $ID_LENGTH); } #--------------------------------(last one needed)----------- sub check_id { my $id = shift; return $id if $DBH->do("SELECT 1 FROM $DB_TABLE WHERE session_id = '$id'") > 0; return $id if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); return ''; } #--------------------------------(retrieve acc)-------------- sub get_state { my $id = shift; my $query = "SELECT * FROM $DB_TABLE WHERE session_id = '$id'"; my $sth = $DBH->prepare($query) || die "Prepare: ", $DBH->errstr; $sth->execute || die "Execute: ", $sth->errstr; my $state = $sth->fetchrow_hashref; $sth->finish; return $state; } #--------------------------------(calculate new acc)--------- sub calculate { my $state = shift; $answer = $q->param('answer'); if ($answer == $state->{three}) { print "Good answer.<p>"; } else { print "Bad answer.<p>"; } $state->{one} = int(rand(100)); $state->{two} = int(rand(100)); $state->{three} = $state->{one} + $state->{two}; return $state; } #--------------------------------(store new acc)------------- sub save_state { my ($state, $id) = @_; my $sth = $DBH->prepare(<<END) || die "Prepare: ", $DBH->errstr; UPDATE $DB_TABLE SET one = ?, two = ?, three = ? WHERE session_id = '$id' END $sth->execute(@{$state}{qw(one two three)}) || die "Execute: ", $DBH->errstr; $sth->finish; } #--------------------------------(print current acc)--------- sub status { my ($state) = @_; print qq{ One: $state->{one} <p> Two: $state->{two} <p> Three: $state->{three} <p> }; } sub initialize { my $state = shift; $state = {} unless $state; $state->{one} = int(rand(100)); $state->{two} = int(rand(100)); $state->{three} = $state->{one} + $state->{two}; return $state; }
While the Fibonacci program relies on this table:mysql> describe dgerman_quiz_prex; +------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------+------+-----+---------+-------+ | session_id | varchar(8) | | PRI | | | | correct | int(11) | YES | | NULL | | | attempts | int(11) | YES | | NULL | | | one | int(11) | YES | | NULL | | | two | int(11) | YES | | NULL | | | age | int(11) | YES | | NULL | | | message | varchar(120) | YES | | NULL | | | modified | timestamp(14) | YES | | NULL | | +------------+---------------+------+-----+---------+-------+ 8 rows in set (0.00 sec)
mysql> describe dgerman_mar4; +------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------+------+-----+---------+-------+ | session_id | char(8) | | PRI | | | | one | int(11) | YES | | NULL | | | two | int(11) | YES | | NULL | | | three | int(11) | YES | | NULL | | | modified | timestamp(14) | YES | | NULL | | +------------+---------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)