home *** CD-ROM | disk | FTP | other *** search
- ------------------------------------------------------------------------------
- Note: This article extracted from the September '91 issue of Carrier Detect
- Journal. At this time, only part 1 of the series was available; Future
- installments may be read in Carrier Detect Journal.
- ------------------------------------------------------------------------------
-
- * Writing a BBS Door (Part 2)
- Tutorial by Scott M. Baker
-
- I am happy to say that response to the first door
- tutorial has been very encouraging. We've received several
- requests for further continuation of the series, so here
- is the second installment. For those joining us for the
- first time, this series is about how to write a "door"
- program. We're programming in Turbo Pascal and using my
- DoorDriver kit for support. I encourage any of you who
- have not yet read part I to review as it contains some
- important introductory material.
- Last time, I said we'd dig deeper into some
- interactive communication with the user. The best way to
- do this is with a sample program. Our last sample, HLODOOR
- was pretty plain, so let's write something that is a bit
- more exciting.
- The following is NUMDOOR.PAS: a simple little game
- designed to demonstrate some interactive communication
- with the user.
-
- { 1} program numdoor;
- { 2}
- { 3} uses doordriv;
- { 4}
- { 5} procedure DoTheTitle;
- { 6} begin;
- { 7} sclrscr;
- { 8} swriteln('Hello, '+user_first_name+
- { 9} ' '+user_last_name+
- {10} '. Welcome to NumDoor!');
- {11} swriteln('');
- {12} end;
- {13}
- {14} procedure playgame;
- {15} var
- {16} thenum: word;
- {17} playerguess: word;
- {18} guessnum: byte;
- {19} done: boolean;
- {20} tempstr: string;
- {21} begin;
- {22} swriteln('I''m thinking of a number.'+
- {23} ' Can you guess what it is?');
- {24} swriteln('');
- {25} guessnum:=0;
- {26} randomize;
- {27} thenum:=random(100)+1;
- {28} done:=false;
- {29} while not done do begin;
- {30} inc(guessnum);
- {31} swrite('Guess #');
- {32} str(guessnum,tempstr);
- {33} swrite(tempstr);
- {34} swrite(': ');
-
-
-
-
-
-
-
-
-
-
-
-
- {35} sread_num_word(playerguess);
- {36} if playerguess>thenum then swriteln('Lower!') else
- {37} if playerguess<thenum then swriteln('Higher!') else
- {38} if playerguess=thenum then begin;
- {39} swriteln('Correct!');
- {40} done:=true;
- {41} end;
- {42} if guessnum=10 then done:=true;
- {43} end; {while}
- {44} if thenum<>playerguess then begin;
- {45} swriteln('You Lost!');
- {46} str(thenum,tempstr);
- {47} swriteln('The number was '+tempstr+'.');
- {48} end;
- {49} end;
- {50}
- {51} procedure waitforkey;
- {52} var
- {53} ch: char;
- {54} begin;
- {55} swriteln('');
- {56} swriteln('Press any key to continue.');
- {57} sread_char(ch);
- {58} end;
- {59}
- {60} begin;
- {61} initdoordriver('DOORDRIV.CTL');
- {62} dothetitle;
- {63} playgame;
- {64} waitforkey
- {65} end.
-
- Some of you were asking for a real door.. Well, there
- it is. All 62 lines worth. Those of you using our new
- LOCREAD program may wish to load up a second window on the
- screen so you may view both the above source and the rest
- of the article at the same time. On with the discussion...
-
- First lets look at an overview of the structure of
- NUMDOOR. We've got three main procedures: DoTheTitle,
- PlayGame, and WaitForKey. These procedures are pretty self
- explanatory. DoTheTitle displays a little title
- information about NUMDOOR. PlayGame performs the actual
- task of playing the game, and WaitForKey waits for the
- user to press a key once the game is over.
-
- Let's go through the program section by section. At
- the very top, you'll notice lines one and three. Line 1
- (Program NumDoor;) is simply us formally telling TP the
- name of our program. Line 2 (Uses Doordriv;) is the
- all-important "uses" statement which tells TP that we will
- be using the DoorDriv TPU.
-
- Procedure DoTheTitle
-
-
-
-
-
-
-
-
-
-
-
-
-
- The first procedure, DoTheTitle displays a little
- introduction to the user so he knows where he is. Let's
- look inside this procedure and see how it works:
-
- LINE 7: SCLRSCR;
-
- This is a DoorDriver procedure which we have not
- introduced before. Sclrscr is DoorDriver's compliment to
- the Turbo Pascal clrscr procedure. The clrscr procedure is
- provided by TP to allow us to clear the screen. If you're
- familiar with basic, then this is equivalent to a CLS.
- Obviously, we will need to clear both the remote and the
- local screens, so that's why we have to use DoorDriver's
- Sclrscr.
-
- LINES 8-10: SWRITELN('Hello, '+user_first_name+ .....
-
- These lines display the introduction. As we learned in
- part one of this tutorial, SWRITELN is DoorDriver's
- compliment to Turbo Pascal's writeln procedure. You may
- notice that I have separated the parameters across three
- lines. This is perfectly legal - as long as the individual
- components include plus (+) signs in between them, we can
- split it up that way.
- Another important note about this line: We include the
- variables USER_FIRST_NAME and USER_LAST_NAME. These were
- discussed in part one. For those who may have missed it,
- DoorDriver places the user's first and last names into
- those two respective variables. Sticking them in the
- SWRITELN allows us to be a bit more personal to the user.
-
- LINE 11: SWRITELN('');
-
- You may be wondering, what is the point of writing
- _nothing_ to the screen? The point is, like TP's writeln,
- swriteln will output a CR/LF sequence. So even if we do
- not write any data, the Carriage Return still goes out.
- The effect is a blank line.
-
- Procedure PlayGame
-
- PlayGame is where all of the real work takes place.
- Let's take a minute to talk about what exactly the "game"
- is that we are playing.
- The game is a very common number guessing game. The
- computer generates a random number and the user gets ten
- shots to guess what it is. If the user guesses
- incorrectly, the computer will tell whether he needs to go
- "higher" or "lower". Now that we know what we want to do,
- lets see how we would go about doing it. In pseudocode,
- here's what we need to do:
-
- 1) Generate a random number
-
-
-
-
-
-
-
-
-
-
-
-
- 2) Ask the user for a guess
- 3) Compare the user's guess to our random number.
- 4) Say "lower", "higher", or "correct" based on the
- outcome of #3's comparison.
- 5) Loop back to 2 until either the user guesses the
- number correctly or uses up all ten tries.
- 6) If the user used up all ten tries, tell him he
- lost.
-
- That's our strategy. Now, let's go thought the actual
- code.
-
- LINES 16-20: Variable Declarations
-
- We need a multitude of variables to store some of our
- information in. THENUM is a word variable which will hold
- the random number which we generate. PLAYERGUESS is
- another word to hold the player's current guess. GUESSNUM
- is a counter to hold how many times the user has guessed.
- DONE is a boolean to tell us when we are done. And
- finally, TEMPSTR is a temporary string which we will
- discuss when we come to it.
-
- LINES 22-24: SWRITELN('I''m thinking of .....
-
- These lines comprise a little instruction that we give
- the user. They're just simple swriteln statements, similar
- to the ones we encountered in DoTheTitle.
-
- LINE 25: GUESSNUM:=0;
-
- Since Turbo Pascal does not initialize our variables,
- we will have to do it ourselves. Guessnum is our counter
- of how many guesses the user has made. Since he hasn't
- made any yet, we've got to set it to zero.
-
- LINE 26: RANDOMIZE;
-
- The Randomize procedure is provided by Turbo Pascal to
- randomize TP's random number generator. Without it, the
- game would pick the same random number each time it runs.
-
- LINE 27: THENUM:=RANDOM(100)+1
-
- Here is where we get our random number. The random
- function returns a number between zero and it's parameter
- minus one. (i.e. Random(100) will include 0..99, not 100)
- So we add 1 to it to get numbers between 1 and 100.
-
- LINE 28: DONE:=FALSE;
-
- Right now, we aren't done yet, (we haven't even hardly
- started!) so we'd better set our variable accordingly.
-
-
-
-
-
-
-
-
-
-
-
-
-
- LINE 29: WHILE NOT DONE DO BEGIN;
-
- Line 29 sets up our "loop" which will ask the user for
- up to ten guesses. We want to keep going as long as DONE
- is not true. The loop consists of lines 29-43 which ask
- the user for his guess and check it's validity.
-
- LINE 30: INC(GUESSNUM);
-
- We're on the first guess, so set guessnum accordingly.
-
- LINES 31-34: SWRITE('Guess #' .....
-
- These lines prompt the user for his guess. Although
- they may seem complicated, they are really nothing more
- than the simple SWRITE statements that we have seen
- before. We just need to do some "magic" to manipulate our
- data.
- Let me explain our problem: SWRITE/SWRITELN only
- accept string data. But, our variable GUESSNUM is a byte
- variable which holds numeric information. So how do we get
- this data into something we can use? The answer is that we
- use Turbo Pascal's STR procedure. STR is a very handy
- procedure which converts a numeric format variable to a
- string format variable. So, when we say
- STR(GUESSNUM,TEMPSTR), we are telling pascal to "take the
- number in guessnum, convert it to a string, and place it
- in tempstr".
- Once this has been done, TEMPSTR now contains our
- number which we can send out to swrite with no problem.
-
- LINE 35: SREAD_NUM_WORD(PLAYERGUESS);
-
- This line the major new concept that we are trying to
- introduce. SREAD_NUM_WORD is a DoorDriver procedure which
- will read a word variable from the user. It handles all
- the details of waiting for the user to press keys,
- converting the data to a word, etc and just gives us a
- nice word variable.
- This is where the "interaction" takes place. Until
- now, we have just been displaying information to the user.
- Now, we ask the user for some information back.
- Specifically, we ask him for his guess. The guess is
- stored in the variable PLAYERGUESS.
-
- LINES 36-41: If playerguess>thenum then ....
-
- This block comprises the code to test the player's
- guess and act upon the results. We display "higher" or
- "lower" if the number is higher or lower and if the user's
- guess is correct, we display "correct" and set DONE to
- true to end our loop.
- This code is all standard pascal stuff (with some
- swrites thrown) in so I won't go into too much detail
-
-
-
-
-
-
-
-
-
-
-
-
- here. We've got to try to stick to the doordriver-related
- things or our little tutorial could get very big very
- quickly.
-
- LINE 42: IF GUESSNUM=10 THEN DONE:=TRUE;
-
- If we're at the tenth guess, then it's time to end our
- loop.
-
- LINES 44-48: IF PLAYERGUSS<>THENUM THEN BEGIN; ....
-
- We could have exited the loop for one of two reasons:
- 1) The user guessed correctly and DONE was set to true or
- 2) The user ran out of turns. These lines will check and
- see if the user's guess was correct. If it was not, then
- we got to break the bad news to him - he lost.
- This code also includes our little trick of using STR
- to convert the data. In this case, we have THENUM and we
- need to convert it to a string so we can tell the user
- what the number was. It works identically to the situation
- we had in lines 31-34.
-
- Procedure WaitForKey
-
- After we have finished PlayGame, we need to have a
- little pause so the user gets to absorb the full impact of
- his game playing. We could use a simple DELAY(2000) for a
- 20 second delay, but we are out to demonstrate interactive
- communication, so let's wait for a keypress.
- I'm not going into this line-by-line as it is such a
- simple procedure. Rather, I'll describe what it does.
- First, we tell the user we want him to hit a key with a
- SWRITELN statement.
- Then, we use DoorDriver's SREAD_CHAR procedure to read
- a single character. SREAD_CHAR will wait for a key and
- then return it to us. We used the variable CH to hold this
- character.
-
- The Main Procedure
-
- The main procedure, comprising lines 60-65 executes
- all of our other procedure. Please note that similar to
- HLODOOR, we had to call INITDOORDRIVER() to get DoorDriver
- setup and ready for use.
- After that, we just called DoTheTitle, PlayGame, and
- WaitForKey in order. Then, we exit.
-
- Interactive Routines
-
- We have introduced two new very important routines:
- SREAD_NUM_WORD and SREAD_CHAR. DoorDriver includes a whole
- set of similar routines for doing similar things. Here's a
- listing of them:
-
-
-
-
-
-
-
-
-
-
-
-
-
- SREAD(s: string); Reads in a string
-
- SREAD_NUM(i: integer); Reads in an integer
-
- SREAD_NUM_WORD(w: word); Reads in a word
-
- SREAD_NUM_LONGINT(l: longint); Reads in a longint
-
- SREAD_CHAR(CH: CHAR); Reads in a char
-
- The first four of these routines will read in data
- until the user presses the return key. For example
- "1234"<return>. They allow the user to backspace back and
- forth to correct his mistakes. These are very similar to
- Turbo Pascal's READLN and Basic's INPUT statements.
- The fifth procedure (SREAD_CHAR) will wait for a
- character and return that character. It's simply for when
- you want one character and only one character. The user
- can't correct his mistakes with backspace or anything.
- This routine also does not echo to the screen.
- SREAD_CHAR performs almost identically to Turbo
- Pascal's READKEY function. In Turbo Pascal you would use
- ch:=READKEY; With DoorDriver, use SREAD_CHAR(CH).
-
- Conclusion
-
- This installment has turned out a lot longer than I
- had anticipated. However, we have gained some very
- important knowledge. We now know how to ask the user for
- data.
- If you like, play with DD's other input routines
- (SREAD,SREAD_NUM, etc) and see what you can do with them.
- They are very important to the operation of a door.
- You might also want to try altering the look and feel
- of NUMDOOR. You can expand the SWRITELN statements to
- provide a more impressive instruction and title section.
- Or if you are feeling really adventurous, you may want to
- look in the DoorDriver manual and peek into the
- SET_FOREGROUND procedure which will let you set the color
- of the text. That is one of the key things we will
- introduce next time.
- Please, if you have any questions or suggestions, you
- can either send them directly or to Michael Crosson,
- editor and published of Carrier Detect. I am right now
- still deciding in which direction to take this series -
- should we work on creating one large program? Or introduce
- features with a lot more small programs such as NUMDOOR
- and HLODOOR. You tell me!
-
-
-
-
-
-
-
-
-
-
-
-