Guess a Number - A simple CGI program in Scheme with LAML

Kurt Nørmark ©    normark@cs.auc.dk    Department of Computer Science, Aalborg University, Denmark    

Abstract. This is a demo CGI program written in Scheme, and using the LAML libraries for CGI programming and the LAML HTML mirror for Scheme.

The game is operational, and it can be played from here if you are connected to the Internet.

 

  The overall design the-game-sect
1  The Game
We first describe the game.
1.1  The Game
 

The Game   the-game
1.1  The Game
The game is very simple. You are supposed to guess a number between 0 and 100. The machine picks a secret number. Upon each guess, the machine will tell you if your guess is too low, too high, or correct. The machine part is running on an Appache WEB server on a Unix machine. 

 

 The Game The Program design-sect
2  The overall design
Although this program is simple and small we have used a structure which, in some respects at least, can be used for larger and more realistic CGI programs.
2.1  The overall design
 

The overall design   design
2.1  The overall design
We decide to split the program in a tiny CGI shell and the Scheme program as such. The CGI shell, which must be located in the .public_html/cgi-bin directory, is here:

#!/bin/sh
 
string=? ; exec /pack/mzscheme/bin/mzscheme -r $0 "$@"
;; This program implements a number guessing game, 
;; which is commonly used to illustrate simple WWW
;; server programming.
(load "/user/normark/scheme/tools/number-guess/number-guess.scm")
The name of the file must be number-guess.cgi, and it should be file protected to be executable (typically with chmod 755).

This starts MzScheme via a shell script, and the load line is executed. It would be perfectly possible to place the entire Scheme program here, but we prefer in general to organize our software in a directory outside the .public_html catalogue. Therefore I load the number guessing program from the tools/number-guess directory in my LAML development directory, which happens to be /normark/scheme.

As another important point, we decide to organize the number guessing system as a single program, which in the page-write part branches between a game init part (A link to a program source marker in page-write) and a game playing part (A link to a program source marker in page-write). We could as well have written two separate CGI programs, which probably would have been preferable in case the 'System' is larger. (This would typically call for common definitions organized in a shared scheme number guessing libary file). 

 

 The overall design  the-program-sect
3  The Program
In this section we describe the number guessing program details.
3.1  The preamble part
3.2  The init game part
3.3  The game part
 

The Program  The init game part preamble-part
3.1  The preamble part
We will here comment on the preamble part of the number guessing program. It follows the typical pattern of most Scheme CGI programs we have written.

We first see kn-laml-dir, which is a variable that points at my laml directory, in which this software resides. In reality it is not used, but in general it isuseful to have variable that points to the source file directory, here source-directory (defined via kn-laml-dir).

laml-dir is important, because it's value points at the root of the LAML system, which is used. Using the program at cs.auc.dk it is natural to use the shared LAML system in /pack/laml/. Alternatively, normark's /user/normark/scheme can be used (which is the LAML development system).

The variable number-guess-url-prefix and not least the derived function number-guess-url are used to address the number guessing program from a browser. The function returns an URL with actual URL parameters - following the question mark. The function make-url-parameters is from the cgi LAML library, and it makes a list of actual URL parameters. We will meet the function number-guess-url later on.

Next comes the loading part of the program. Here laml.scm is loaded from the designated laml-dir, and a number of other libraries are loaded. In this context, the most important are the cgi.scm libraray (A link to a program source marker in loading) and the encode-decode.scm library (A link to a program source marker in loading), which is used by cgi.scm.

In other-settings we set the variable cgi-testing to #f and we register the current time in cur-time. The time is not used in this program, but it general this number is useful for a variety of purposes (such as making file names 'unique').

In the section url-parameters we extract the URL parameters passed to the program. The variable language-preference controls whether danish or english is used in the game, with english as the default. The function text-choice uses the variable language-preference. The variable mode is important because it controls the part of the program to be started; Possible values are the symbols init or play, with init as the default. The function defaulted-get is a function from the LAML general library.

The CGI library function extract-url-parameters decodes the URL parameters. The variable url-pars is an association list (a list of cons pairs), such as

  ((language . "english") (mode . "init"))
This ends the game preamble part. 

 

The Program The preamble part The game part init-game
3.2  The init game part
The function
game-init returns a HTML body to be used in one of the branches of the page-write section in the program. This is the place to draw the secret number (A link to a program source marker in game-init).

Also notice the form element, generated by form-1 at (A link to a program source marker in game-init). This determines the program which will receive form input when submitted. Thus, when we submit a new guess this detail determines the receiving CGI program. Here, we reuse the same program for this purpose (possible due the outer branching discussed above), but notice that we switch to play mode. We pass the language-preference on as the language parameter.

After a welcome text we call guess-part (A link to a program source marker in game-init), which renders the form used for the user's guess.

Let us now look at guess-part, which returns part of the body. The function text-line renders an input field, in which the guess can be entered (A link to a program source marker in guess-part). The secret number is passed on using a hidden field (A link to a program source marker in guess-part). In a better version of the program we should protect this field from being read directly in the document source. The submit button is also made in this function (A link to a program source marker in guess-part). 

 

The Program The init game part  game-part
3.3  The game part
The game part, represented by
game-play, is the place where we get a hint about our guess, and we are allowed to make a new guess if we did not hit the number exactly.

We first have to extract the submitted form input. This is done by extract-form-input from the CGI library (A link to a program source marker in game-play), which returns an association list such as

  ((secret-number . "42") (players-guess . "22"))
We prepare a body with a new form element (as above) (A link to a program source marker in game-play). The conditional (A link to a program source marker in game-play) compares the secret number with the players guess, and an appropriate hint is presented. Notice how guess-part is activated if no exact hit is found (A link to a program source marker in game-play A link to a program source marker in game-play). In the lucky case where the player guesses the number an URL is given to restart the game (A link to a program source marker in game-play).