BASH Script – Guess My Number
Some of the most fun I had with the Commodore Vic-20 and Commodore 64, was entering programs from their user’s manual or magazines and learning how to program in BASIC. Something that I think today’s generation starting to use computers these day are missing out on. The computer has become just another house hold appliance. Where you use a microwave to cook your food. You use a word processor to do your homework, a photo managing software, or video editing software to upload to YouTube to show everyone how cool you are. If you know how to navigate around the Macintosh finder, or Windows desktop you’re a computer expert. However if you were tasked with writing a very simple program (besides ‘hello world’, would you be able to do it?
For those of us that use some flavor of the *NIX operating systems, such as Mac OSX, or any of the Linux distributions, we are lucky, because we have a plethora of programing “scripting” languages at our finger tips!
I wanted to demonstrate this capability, by taking one of the very first programs I ever wrote on the Commodore 64. The program lets you pick the difficulty by letting you define the highest number it will “guess”, then randomly generates a number from 1 to that number. You must then guess the number the computer chose and try to do it in the least amount of guesses. It was a very straight forward program, though I did run into a few issues when converting it to a bash script.
The first problem is that I do not have allot of experience programming without line numbers. Even when I converted a couple of programs from my BBS, I was able to simulate line numbers in AREXX by making each line in the script a number such as L1: L2:. Arexx will execute from top to bottom, unless you execute a GOTO, or GOSUB statement. In BASH unless you make a nesting infinite loop, it will execute top to bottom no matter what! There is no equivalent to the GOTO statement. You can define a function and perform the equivalent of a GOSUB, but when the subroutine finishes. It returns to execute exactly where you left off. To me this is quite a limitation, and in my opinion causes bloat.
Here is the listing of the original Commodore 64 program, as it appeared in the User’s Guide.
I do not have allot of experience with BASH scripting, so there was quite a bit of Google searching and rethinking the operation of the program. One of the biggest stumbling blocks came from the fact that without a go to statement, I had to use an extra variable and create the until loop. Which added several needless lines to the program. (The line numbers here make it easier to read, and later describe the script. Do NOT enter the line numbers!)
1 #! /bin/bash
2 # BASH Shell version of the Random Number Guessing Game
3 # Originally published in the Commodore 64 Users Guide.
4 # Converted to BASH Shell by Brent P Hendricks
5 # This script in intended to be used with an article
6 # published on Brent’s World (An American Expat In Korea)
7 # Please check out the article @ www.catracing.org/hendrb/
8 # This script is public domain, however the article text is
9 # Copyright 2014 by Brent P. Hendricks, if you use to use
10 # the article text in part or in full, please contact
11 # me on my blog. Linking to my article is permitted!
12
13 clear #- Clears the screen
14
15 echo “Randon Number Guessing Game v1.0”
16 echo
17 echo “Originally published in the Commodore 64 Users Guide in 1982, page 51”
18 echo “Converted to a BASH Shell script by Brent P Hendricks Dec 2014”
19 echo “This script was published in an article demostrating the differences between Commodore Basic and BASH shell Scripting.”
20 echo “If you have a chance, please read the article at Brent’s World www.catracing.org/hendrb.”
21 echo “This script has been released in the public domain, however the article text is Copyright 2014 by Brent P. Hendricks.”
22 echo “Copying the article text, either in part of in full may only be done with writen permission from the author.”
23 echo “Feel free to link to the article at https://www.catracing.org/hendrb/bash-script-guess-number/”
24 echo
25 echo
26
27 #defines functions
28 guess ()
29 {
30 echo
31 if [ $GUESS -lt 2 ]
32 then
33 echo
34 echo -n “Enter your first guess : ”
35 read AN
36 else
37 echo
38 echo -n “Enter another guess : ”
39 read AN
40 fi
41 }
42
43 #define variables
44 GUESS=1 #Defines variable try (Used to count the number of attempts)
45 WIN=0 #Defines variable WIN (This is used to determine if the game is over and can exit.).
46 echo
47 echo -n “Enter Upper Limit for your guess: ”
48 read LIMIT #’Reads’ Keyboard input and puts the result in variabel LIMIT
49 # Generates Random Number From variable LIMIT
50
51 NUMBER=$((RANDOM % $LIMIT))
52 echo “I’ve Got The Number.”
53 guess #Calls function quess
54
55 #This can be used for troubleshooting, If the script does not appear to be running correctly.
56 # You can uncomment these lines to display the results of each game variable.
57
58 # echo $NUMBER
59 # echo $AN
60 # echo $WIN
61
62 until [ $WIN -eq 1 ]
63 do
64 if [ $AN -eq $NUMBER ]
65 then
66 WIN=1
67 fi
68
69 if [ $AN -lt $NUMBER ]
70 then
71 echo “Sorry, my number is HIGHER.Try again!”
72 ((GUESS=$GUESS+1))
73 guess
74 fi
75
76 if [ $AN -gt $NUMBER ]
77 then
78 echo “Sorry, my number is LOWER. Try again!”
79 ((GUESS=$GUESS+1))
80 guess
81 fi
82 done
83 echo
84 echo “Great! You Got My Number! It Took You $GUESS Tries.”
85 echo
86 echo -n “Would you like to try another? ”
87 read an
88
89 if [ an = y ]
90 then
91 exec $.\number-guess.sh #Replaces currently running program with new number-
92 guess progrom, BASH does not support GOTO
93 else
94 echo
95 echo “Please Check Out Brent’s World @ www.catracing.org/hendrb”
96 fi
97 exit
To write a BASH script, you can use any text editor that you feel comfortable using, in *NIX, I tend to prefer nano, but vi will work as well.
After entering the script into your favorite editor, you need to make the script executable. to do this type chmod 776 <filename> at the command line.Once the script has execute permissions. type .\<filename> . The .\ tells the system to execute the file in the current directory, instead of looking in the SEARCH PATH set in the $PATH environment variable.
The first line of your script must contain the statement #!/bin/bash. This tells the system that you are executing a script
Between Lines 2 – 11 are the programs comments, similar to the BASIC REMark statement. Any statement following the # command will be ignored by the bash shell. This is also useful while trouble shooting scripts or .conf files, as instead of removing a line. You can simple “POUND IT OUT”, and the shell will ignore it.
Line 13 simply clears the screen.
15-24 Is simply a sequence of ECHO statements that display the program banner. Echo displays text or variables to the std(OUT) (Screen). Echo has several options that we used in this script, including its NULL state which simply prints a cr/lf to std(OUT). As you see here with echo being by itself. Echo with no options will output any text in quotes will automatically add a cr/lf to the end of its text. Sometimes this is undesirable for formatting reason, or if the echo command is being used to create prompt for input followed by a read <variable> statement. You can suppress the addition of the cr/lf by adding the –n option. As seen in line 38.
26 – 31 is defining a function called ‘guess’, since BASH does not support a GOTO feature, creating the subroutine that gets called by the DO UNTIL LOOP was an easy solution. In this subroutine you see our first use of the test function [.
Line 30 could also be written in long hand, like this.
If test -$GUESS –lt 2 ]
Then
<do this>
Else
<do that>
fi
The test function allows us to perform tests to determine if a specific condition exists. In this case if the number of GUESS’s is 1, This could also have been write as if [ $GUESS –eq 1).
-eq = Equal to
-lt = Less Then
-gt = Greater Then
The fi in 40 closes out the loop statement, and the } in line 41 tells the interpreter that this is the end of GUESS function.
Line 43 – 45 simply puts default values in 2 variables, GUESS (Which is a counter of how many attempts you have made to guess the number), and WIN = which is simply a condition variable used later in the program so exit the DO UNTIL loop. Variables in *Nix are case sensitive. It is common practice to use capital letters, so they are not confused with commands. As noted here, we have a function defined as guess, as well as a variable named GUESS.
Line 48-53 Prompts the users for the upper limit of the number the computer will generate. The computer will pick a number from 1 – limit. As noted above, the –n option is used after the echo command to suppress echo from automatically adding a cr/lf after the prompt. Line 49 reads std(IN), in this case the keyboard for input, and places the input in the variable LIMIT
Line 53 generates a random number from 1 – $LIMIT and places this number in the variable $NUMBER
Line 56 calls the guess function
Lines 58 – 60 where placed by me, as an example of debugging, I wanted to be able to see between each guess that the variables where doing what they are supposed to do
A note about variables. When placing values into a variable you only specify the variable name, with one exception (more about that in a sec.) whereas when reading a variable you must proceed it by a $.
\Lens 63 – 83. Is what I consider to be bloat caused by the fact BASH does not have a GOTO feature. So I had to assign another variable WIN, and this 3 part UNTIL-DO loop. I suppose you could make the program one whole nested loop inside an infinite loop, but we can save that attempt for a future article.
Line 92, If the user answers they want to play again. Exec $ exits the script and re-runs it. Another brutal solution driven by the lack of a GOTO command.
I hope you try typing in this BASH script, It certainly brought back allot of memory, mostly of the amount of frustration that writing even a simple program can cause. If you would like me to write more articles for the technical portion of my blog please let me know. Also any comments or suggestions on the programming syntax or format.. Please let me know.
Errata has been corrected, in the remark statements at the beginning of the script, I stated that I got the idea for the number guessing program from the Commodore 64 users manual published in 1992. This is incorrect and should read 1982.