14)
Program 13 - random number game
Program 13 | Random number game | Source code - prog13.c |
At last a game ! well sort of. It's not
going to be a best seller though, sorry. This program is
a lot bigger in size than previous programs, but the
majority of the functionality has been covered in
previous programs. The new parts are the use of constants
and random numbers. Constants are not
difficult to grasp, but random numbers are a bit tricky
to understand at first. Random numbers though are important in computer gaming to generate different scenario's for a game each time it is used, keeping the user interest. They can also be used to good effect in probability algorithms,. The problem is though, that computers are precise machines, there is nothing fuzzy or random about them, and to a computer there is no such thing as a random number, but there is a way of generating seemingly random numbers, as will be explained. The explanation doesn't go into the gory details of how it all works, but gives enough information to use random numbers in programs. The program itself is a simple number guessing game. The program will pick a different random number between 0 and 100 each time it is run by the user. It is then the users job to guess that number. If the user guess is wrong it will say too high or too low accordingly and give them another go. When the user finally gets the right number, the program will congratulate the user and tell them how many guesses they had getting there. This is the most complex page so far, so it may need to be read slowly. |
Program code- new parts shown in red |
|
Description of the program code | ||||||||||||||||||||||||
The first
difference in this program is the use of two header files
that have never been used before stdlib.h
and time.h. These need to be included
for the random number functions. As with previous header
files, they will be explained later, but it's a case of
remembering which header files are needed for which
statements. When header files are explained there will be
a list of all the C functions and the corresponding
required header file needed to use them. The line #define MAXRANDNUM 32767 is defining a constant called MAXRANDNUM. What this means is that everytime the compiler finds MAXRANDNUM in the program below it will replace it with the value 32767. If you look a bit further down the code there is a line which reads ran=(ran/MAXRANDNUM)*100; this line will be treated by the compiler as reading ran=(ran/32767)*100; What you are probably thinking now is, why not just type the latter code in and not bother with defining a constant. There are a number of reasons why, but unfortunately this example is not the best to explain them all, but hopefully after the rest of the program is explained, you will see why. The other things you may be wondering are, why has it been given a name in capital letters ( MAXRANDNUM ) and why is it called a constant ? Constants do not have to have names with capital letters, you can use lower case letters if you like, but it is regarded as good programming practice to define constants with capital letters so that they can be identified as constants easily in programs and not variables. Also a constant is so called, because it is set to a "constant" value, in other words it cannot be changed by the program itself. You cannot have the line MAXRANDNUM = 12345; anywhere in the program, the compiler won't allow it. The only way a constant value can be changed is by changing the source code and re-compiling it. To explain further look at the following two programs that display information about a circle with radius r. Just in case it's been a while learning maths, the value of PI is roughly 3.14, the area of a circle can be calculated with the formula PI * r * r. The circumerence of a circle has the formula PI * ( r + r).
Firstly the second program is more readable. Secondly and more importantly. Imagine that tommorrow someone mathematical wiz discovers that we've been wrong all these years and the value of PI isn't 3.14 as previously thought, but 6.92. Okay, it's not going to happen, I know, but just imagine it did ! With program one, you would have to search through the code for all references to 3.14 and change each line accordingly ( only 2 line changes in this small example ). With the second program it's a lot easier, as only the #define PI 3.14 line would need changing. It's not such a factor with this example, but imagine a program with over 100,000 lines of code and where PI is used 100's of times. Another, more realistic, reason you may need to modify the code is, after a while the program didn't give you an accurate enough result. You could change the #define PI line to 3.1427, which is a lot easier. Okay enough of constants, hopefully you're convinced, but if not, you don't have to use them, now onto random numbers ( sorry more maths ) Firstly you do not need to fully understand this part on random numbers, you can take the portion of code from this program and modify it for your own programs if you do not understand it. Saying that though it would be better if it was understood. The line srand(Time()); is required to set something called a random seed. Without this line, it wouldn't be a very good game at all, unless you like guessing the number 51 that is. All that is needed to be understood about this line is that without it, the program will generate the same number to guess each time the program is run ( probably 51 ), which isn't what is needed for an interesting game. If you are ever writing a program that uses random numbers always include this line at the start of the program to ensure that it gives the effect of randomness. The next line ran=rand(); makes use of the rand function. What it does is store a random number between 0 and 32767 ( inclusive ) in the ran variable. It's not a conventional number ( 32767 ) that's for sure ! but there is a reason why it does this, but it would involve a long and complicated description on two's complement binary to explain why this strange number. It's another one of those things that has to be taken as red for now. Maybe sometime later, two's complement binary will be covered. It's not absolutely necessary to understand it though. So now, there's a number stored in the ran variable which is between 0 and 32767. The game is supposed to generate a number between 0 and 100 to guess though, so some manipulation of this number is needed, even though we don't know exactly what the number is. Whatever number was generated, between 0 and 32767, you can be sure that if you divide that number by 32767 then you will get a number between 0 and 1. To explain more clearly, imagine that the random number generated was a whole number between 0 and 10, instead of between 0 and 32767. If you divide whatever it is by 10, then you get a number between 0 and 1, look at the following table for proof :
The first column shows all the possible numbers that could be generated. The second column shows the result of dividing those numbers by 10. Therefore, after dividing by the largest possible number, you end up with a fractional value which is between 0 and 1. A value between 0 and 1 is a lot easier to work with than a value between 0 and 32767. If you then multiply the value ( between 0 and 1 ) by 100 you end up with a number of between 0 and 100, which is what the program needs ! If it needed a number between 0 and 500 then it would be a case of multiplying by 500 instead of 100. The line ran=(ran/MAXRANDNUM)*100; does all of this in a single line. The only problem now though is that it is not a whole number, it contiains a fractional portion as well. It's a bit unfair on the user to expect them to guess, say, 56.2918261 :). The final new line num=(int)ran; chops off the fractional part, leaving just the whole number. It is effectively saying convert the ran variable from a floating point number to an integer number and store the result in the num variable. |
Summary |
Phew ! again ! If
you have read this page and it's flown about a mile over
your head, don't get too down hearted. It is a giant leap
from what has been done so far. Try re-reading it a few
times slowly, if after that it's still not clear, don't
worry, move on to the next page, it gets a lot easier
than this page. The next page is a lot simpler, and covers functions in C, which provide a way of splitting large programs down into small manageable chunks. |
Tasks |
There are no tasks for this page. It contains information on complex issues and understanding it is a task in itself. |
(c) J.C.Spooner 2001