|
Second Summer 2004 |
The problem was this.
So I started by writing this program:
<? 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>
Then Jesse improved on it (disregard the lack of indentation):
<? 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>
And he provided a client-side 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>
So I wrote a CGI with hidden fields version of it:
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;
And we converted most of that to CGI/DBI in class on Thu:
#!/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;
}
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_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;
}
And the final version required the creation of a new table:
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)