cgi-dev

Repository that serves as my CGI "scratchpad" to try things out.
git clone git://git.samirparikh.com/cgi-dev
Log | Files | Refs | README

commit 268858842ed87b5773afc294ad9fcc157a042016
parent 9b72c9eb5e788b325e84ac9dfb3e5b90026a758f
Author: Samir Parikh <noreply@samirparikh.com>
Date:   Fri, 25 Feb 2022 15:14:01 +0000

get cookie to work

Diffstat:
Aguess_number2.cgi | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 199 insertions(+), 0 deletions(-)

diff --git a/guess_number2.cgi b/guess_number2.cgi @@ -0,0 +1,199 @@ +#!/usr/bin/perl + +use warnings; +use strict; +use CGI; +use CGI::Cookie (); + +use constant TRIES => 6; +use constant COOKIE_NAME => 'guess_number_2'; +my $game = CGI->new; + +# state maintenance subroutines +sub get_state { + my %state = $game->cookie( COOKIE_NAME ); + return undef unless %state; + return \%state; +} + +sub initialize { + my $state = shift; + $state = {} unless $state; + $state->{NUMBER} = int( rand( 99 ) ) + 1; + $state->{GAMENO} += 1; + $state->{GUESSES_LEFT} = TRIES; + $state->{WON} += 0; + $state->{GUESSED} = ''; + return $state; +} + +sub save_state { + my $state = shift; + return CGI::Cookie->new ( + -name => COOKIE_NAME, + -value => $state, + -expires => '+1M', + ); +} + +# game play logic +sub process_guess { + my ( $guess, $state ) = @_; + + # process list of previous guesses + my %guessed = map { $_ => 1 } split /,/, $state->{GUESSED}; + + # do nothing if user did not enter a guess + return ('', 'continue') unless $guess; + + # ensure guess is a valid number between 1 and 100 + return ("Not a valid guess.", 'error') + unless $guess =~ m/^[1-9][0-9]?$|^100$/; + + # check if user already entered this guess previously + return ("You already guessed that number.", 'error') + if $guessed{ $guess }; + + # we have a valid guess. update list of guesses + $guessed{ $guess } = 1; + $state->{GUESSED} = join ',', sort keys %guessed; + + $state->{GUESSES_LEFT}--; + + # the order of the checks is important here. At this point, it's + # possible that the player has used their last guess. Therefore, + # we first check whether the guess is correct + + # guess is correct! + if ( $guess == $state->{NUMBER} ) { + $state->{WON}++; + return ("Congratulations! You guessed that the correct number + was $state->{NUMBER}!", 'won'); + } + + # if the guess is not correct AND we are out of guesses... + return ("Sorry, you ran out of turns. The number was $state->{NUMBER}.", + 'lost') unless ($state->{GUESSES_LEFT} && $guess != $state->{NUMBER}); + + # otherwise... + # guess too low + return ("Your guess is too low.", 'continue') + if ( $guess < $state->{NUMBER} ); + + # ...or + # guess is too high + return ("Your guess is too high.", 'continue') + if ( $guess > $state->{NUMBER} ); + +} + +# html generation subroutines +sub print_header { + my $state = shift; + print $game->header( + -type => "text/html", + -charset => 'utf-8', + -cookie => save_state( $state ), + ); + print $game->start_html( + -title => "Guess a Secret Number!", + -onLoad => 'if (document.gf) document.gf.guess.focus()' + ); + print $game->h1( 'Guess a Secret Number Interactive Game' ); +} + +sub print_status { + my ( $message, $state ) = @_; + + # draw table + print + $game->table( { -border=>"0", -width=>"50%" }, + $game->Tr( + $game->td( $game->b("Game #: "), $state->{GAMENO} ), + $game->td( $game->b("Wins: "), $state->{WON} ) + ), + $game->Tr( + $game->td( $game->b("Guesses Left: "), $state->{GUESSES_LEFT} ), + $game->td( $game->b("Numbers Guessed: "), $state->{GUESSED} ) + ) + ); + print $game->h2( $game->font( {-color => 'red'}, $message )) + if $message; +} + +sub show_restart_form { + my $state = shift; + print $game->start_form(); + print $game->p( + #-style => 'padding-right: 25px', + 'Do you want to play again?', + ); + print $game->submit ( + -name => 'restart', + -value => 'Play again', + #-style => 'padding-left: 25px; padding-right: 25px', + ); + print $game->checkbox ( + -name => 'clear', + -label => 'Clear history', + ); + print $game->end_form(); +} + +sub show_guess_form { + my $state = shift; + print $game->start_form( -name => 'gf' ); + print "Your guess: "; + print $game->textfield ( + -inputmode => 'numeric', # force number pad on mobile + -pattern => '[0-9]*', # force number pad on mobile + -name => 'guess', + -value => '', + -override => 1 + ); + print $game->submit ( + -name => '_guess', + -value => 'Guess' + ); + print $game->end_form(); +} + +sub print_footer { + print $game->hr; + print $game->p( + 'inspired by Hangman game from ', + $game->a( + { -href => "https://www.oreilly.com/library/view/writing-apache-modules/156592567X/"}, + $game->i( 'Writing Apache Modules with Perl and C') + ), + ' by Lincoln Stein and Doug MacEachern.' + ); + print $game->end_html(); +} + +# begin main program +# retrieve current state +my $state = get_state() unless $game->param( 'clear' ); + +# initialize state if we are starting from the beginning (!$state) +# or if we are playing another game ($game->param( 'restart' )). +if ( !$state || $game->param( 'restart' ) ) { + $state = initialize( $state ); +} + +# process current guess, if any +my ( $message, $status ) = + process_guess( $game->param( 'guess' ) || '', $state ); + +# generate the HTML page +print_header( $state ); +print_status( $message, $state ); + +# prompt user +if ( $status =~ /^(won|lost)$/ ) { + show_restart_form( $state ); +} else { + show_guess_form( $state ); +} + +print_footer();