TDK_Man's Dark Basic Programming For Beginners
Part 1 - Variables
This is the first of an intended series of tutorials aimed at teaching the newcomer to programming the basics of the BASIC programming language. In part 1 you will find a very brief introduction to programming languages and an explanation of variables.
The examples will be in Dark Basic Classic, but the examples and theory should apply with little or no modification to
any dialect of BASIC - including DB Pro.
It will cover the elementary groundings and anyone with any previous programming experience will find little of interest in this tutorial.
Smaller sections of code which can be typed into DB will appear in bold to make the text easier to follow:
SET DISPLAY MODE 800,600,16
CLS
PRINT "Hello World"
Larger sections of code will be placed in the usual forum code boxes:
Part 1 - Variables
Where Do I Start?
OK, so you've downloaded the DB demo or bought it, loaded it up and don't know what to do next. You've no programming experience and can't make any sense out of the help files and/or manuals.
Well, you need to learn the ABC's and start simple, so that's what we will do...
Programs:
In a nutshell, computers manipulate data by transferring numbers around in memory.
For example, when a number is placed in a certain part of memory called the video memory, a dot will appear on your monitor screen. The colour of the dot depends on the value of the number.
Every image, text character and coloured dot you see on the computer screen is nothing more than a number in your computer's memory.
When you play a computer game, all you are seeing is the results of all these numbers being manipulated to create what you see on the screen. A computer program is simply a list of instructions the computer has to follow to do it.
To write a game, you need to create the machine code which tells the computer's CPU where to move the data from and where to put it.
However, as binary (all 0's and 1's) is not the easiest way to go about it, back when I first started programming, a language called 'Assembler' was developed. This turned the programming process into something more managable and easier to learn.
call_oz(GN_Nln)
push iy
pop hl
ld de, 2
ld b, 6
call_oz(GN_Gdn)
ld d,b
ld e,c
ld hl, 10
call_oz(GN_M16)
ld b,h
ld c,l
Even so, as you can see from the above snippet of Z80 assembler, the commands were still obscure and looking at it you had very little idea exactly what it did. Besides that, something like clearing the screen - which we now take for granted with CLS in DB - took many lines of code, because each individual dot on the monitor had to be manually set to black in a loop - and all you had at your disposal were simple instructions like loading values into registers.
This was known as a 'Low-Level Language' as you had to get down to talking directly to the hardware. Also, you had to learn the version of ASM for the CPU in your machine. This might be Z80, 6502, 68000 or one of many others - none of which for the main part were interchangeable.
The BIG advantage was that programming the hardware like this was FAST - blindingly fast! And, that remains true to this day - a program written in assembler will be a lot faster than the same program written in a higher-level language, but a thousand time bigger and more difficult to write. Instead, short assembler routines are written for specific purposes where speed is essential.
Over time, other programming languages appeared which removed the low-level commands like LD, PUSH and POP and replaced them with higher level commands like PRINT and REPEAT...UNTIL. When these programs were run, the high-level instructions were compiled into low-level machine code that the computer could use.
Examples of these languages were Pascal, Forth, C and Cobol - each having their own areas of expertise.
And then along came BASIC or Beginners All-purpose Symbolic Instruction Code which as the name suggests was aimed firmly at beginners.
Clearing the screen was reduced to CLS, outputting text to the screen used PRINT and so on. It was easy to learn but slow as it was interpreted (not compiled into machine code), though later on, compilers appeared which sped things up a bit. Most importantly it's 'nearly English' syntax meant you could read the majority of BASIC code and know more or less what it was doing straight away.
Variables:
All versions of BASIC are built using the same building blocks. A program which uses these building blocks can be run on practically any machine, though things start to alter when you get to the commands which make use of the hardware differences between machines - for example, versions of BASIC running on a PC and a Mac will both have unique commands.
One of the building blocks in any higher level language is variables. Without them you would have an impossible task writing anything but the smallest program.
So, what is a variable? Well, a variable is in effect a substitute for something which can change - either a numeric value or an alphanumeric string of characters. A numeric variable can be used in a formula or calculation in exactly the same way as a number can.
Take the simple example:
A=100
Here we are creating a variable called A and giving it the value 100. I found it easiest when learning to program by thinking of it as follows…
The computer creates a cardboard box in memory, sticks a label on the front of the box and writes 'A' on the label. It then puts 100 into the box.
From this moment on, whenever your program refers to 'A', the computer goes through all of it's boxes until it finds the one with 'A' on the label and gets the value out to use.
B=50
OK, another box only with B on the label and 50 stored inside it. Easy eh?
C=A+B
What does C equal? If you thought AB then you are thinking in algebra terms and it's not the same!
Like before, the computer gets the 100 out of box A and the 50 out of box B and adds them together, putting the resulting 150 into a new box it creates and labels 'C'.
You will notice that BASIC uses the syntax of 'the bit on the left side of the equals sign ends up containing the results of everything on the right side'. This is different to the way you do it in conventional maths, so be aware of this.
In fact it would be more precise to read 'A=100' as A
becomes equal to 100 rather than A
equals 100 as in computer terms 'A=100' may not be true. The variable 'A' can change, so it may NOT equal 100!
For example think about these two (admittedly pointless) lines in a DB program:
A=10
A=100
On the second line, when the program reaches it, A already equals 10 (as defined on the first line), so A=100 is a false statement as A actually doesn't equal 100 - it equals 10! If the first line also said A=100, then the second line would be true as A does indeed equal 100 at that point. You should now see the reason for reading it as 'A becomes equal to' rather than just 'A equals'.
This may sound very confusing at first, but later on it will make more sense when you will find out about BASIC's IF statement which is used to do logical comparisons using boolean logic - where the answer to a question is always either yes (1) or no (0). For example, in BASIC you can say:
IF A=100
…which will return a 0 (false) or a 1 (true) depending on whether or not A does equal 100 or not. Computers never say 'I don't know' or 'maybe' in these cases!
As the A=100 is the same as what we have just covered, it is important to have firmly in your mind the difference between the two. One sets the variable's contents to 100 and the other compares the contents of A with 100 to see if they are the same.
As an aside, in the programming language Pascal, these two tasks have a different syntax to avoid this confusion. Setting the variable A to equal 100 in Pascal is done with A:=100 with the colon meaning 'becomes'. As such it does actually read A becomes equal to 100. IF A=100 in Pascal is exactly the same as BASIC (without the colon).
Variable Names:
The only rules you should apply are:
1. Don't use reserved words as a variable names (words used as BASIC commands like Print, Do, Loop etc), though you can use variable names of which only a
part is a reserved word. For example, Sprite is a reserved word and not recommended as a variable name, but MySprite would be OK.
2. Always start a variable name with an a..z or A..Z character - never a number. A number can be placed on the end or in the middle of the variable name if you wish though. Even a variable name like ABC123DEF is acceptable!
3. Don't use spaces or any special symbols in variable names other than the _ (underscore) character. This can be used to separate words to make them more readable. Eg: Time Left is a no no. Time_Left is OK.
You can use any combination of characters and numbers in a variable name as long as you follow rule 2 above, so make use of the ability and use a name which makes sense. So, if you are storing a value which represents the players score then use a variable called 'Score'. A line which says:
Score=Score+100
…makes more sense than
X=X+100
..as the variable name tells you what you are adding 100 to! X could mean anything.
Also, unlike some programming languages, you don't have to declare variables prior to using them. The first time you refer to them in your program they exist, and if you don't specify that they contain anything, numeric variables automatically contain 0 (zero).
OK, that's numeric variables… or is it? Well, not quite.
In DB there are two types of number - Integers, or whole numbers like 10, 123 or 1000 and Reals (or floats - floating point fractional numbers), like 1.373, 328.45 or 1000.09.
Integer and real variables need different amounts of memory to store values, so you need to tell DB what type of value it is you are storing. You do this with the variable name.
Variables which need to store real numbers are identified by putting the # symbol on the end of the variable name. This effectively tells DB to make a bigger cardboard box to hold the decimal point and numbers after the decimal point.
So, the following examples are correct:
Age=21
Apples=8
Height#=137.45
ObjAngleX#=120.33
You also have to be careful not to accidentally mix the two types of variable as you can end up with hard to track errors. For example:
A#=100.23
B#=10.14
C=A#+B#
What is C equal to this time? If you said 110.37 you would be wrong. If you said 110 then you would be correct.
A# and B# are added together to get the correct result of 110.37, but the result is placed into C which is an integer variable, so the .37 bit is lost. Think of the cardboard box being integer size (too small) and it simply can't fit the decimal point and everything after it, so it just drops it.
This effect is known as variable casting in some programming languages. (The result is comparable to the DB function INT() in DB).
Sometimes you may want to do this, but when learning, the chances are that you do not, so beware!
Strings:
As well as numeric variables, you can also have string variables which are pretty much the same, but hold alphanumeric characters (a..z A..Z 0..9) rather than numbers. This can be a single character, a word or a complete sentence up to 255 characters long. And, being alphanumeric strings can also be numbers so beware as numbers in strings are still strings and cannot be treated as if they were number variables!
String variables are defined by putting a $ sign on the end of a variable name and their contents have to be enclosed in double quote symbols to clearly define where the string starts and ends.
For example:
A$="The cat sat on the mat."
Name$="Fred Bloggs"
Age$="21"
FaveHobby$="5-A-Side Football"
…are all legitimate string declarations. But, note that in the third example Age$ may equal 21, but adding the variable to itself would equal "2121" - NOT 42 as it's a
string variable - not a numeric variable.
Arrays:
Arrays are very useful. Arrays are easy if you are shown how they work in the right way. Arrays are a nightmare to new programmers if you are not!
Arrays are nothing more than groups of normal variables, each with an index number with which to access them. The main difference is that arrays have to be dimensioned before you use them as DB has to make sure that it builds enough cardboard boxes (to continue the analogy). This is done with the DIM command.
Arrays can be single or multi-dimensioned so let's take a look at single dimensioned arrays first…
An example:
Say you were writing a simple game where each person typed in their name and the program stored it, along with their best score. The variable Name$ could hold their name and the variable Score could hold their best score.
But, that's only good enough for just one single player. Use the same variables for player number two and player number one's name and score are lost! So, we use Name1$ and Name2$ for the names along with Score1 and Score2 for the scores.
I think you can see where we are going with this… If you had 100 people playing this game, we would need Name1$, Name2$, Name3$ all the way up to Name100$ - and the same for the variable Score.
Also, the line in your program which increments the score would have to be repeated 100 times - once for each player.
Arrays rid you of this hassle. Using:
DIM Name$(100)
DIM Score(100)
...will create two arrays, the first allowing you to store 100 strings of up to 255 characters (1 to 100, though you also have number 0) and the second, 100 numbers. This is a 1 dimensional array.
Memory is allocated in a continuous block (like a ticker-tape), and large enough to store the requested number of variables stated in the DIM statement. The Score array would look something like this:
Each of the 100 variables is accessed by using it's index number. This way you can have:
Name$(1)="John"
Name$(2)="Dave"
Name$(99)="Pete"
And so on.
Score(1)=2000
Score(2)=2500
Score(99)=2100
…would be the respective scores. For example, Score(12) would belong to player Name$(12) and so on. When you realise that the actual number can be replaced by a numeric variable it makes it possible to say things like Name$(CurrentPlayer) and Score(CurrentPlayer) in your programs.
So that's single dimensioned arrays. What about Multi-Dimensioned arrays?
Well, they are basically the same, but instead of the array being one single line of variables from 0 to 100, they are created in a 2 dimensional grid format. They are best thought of as being like the old-fashioned pigeon holes you find in schools (or a wall covered with lockers) where there are a number of boxes running across and down.
Dimensioning an array like this just needs you to use two values in the DIM statement - the number of boxes across and the number down. Bearing in mind that array indexes start at 0, to get a numeric array grid of 25 variables (5 across and 5 down) called Location, you would use:
DIM Location(4,4)
However, while learning, if you wanted an array of say 10 across and 5 down you would be better off using DIM ArrayName(10,5) and completely ignoring the 0 element until you get the hang of things. Doing this, for our 5x5 integer array we would therefore use:
DIM Location(5,5)
It doesn't matter which method you use - 0 based arrays or 1 based arrays - just use the one you understand and are happiest with.
Remember you don't
have to use the 0 element of an array - it's just a waste of memory if you don't. With small arrays, this isn't really a problem, though the larger the array, the more memory is wasted.
When created, you access the contents using Location(1,1) or Location(1,3) etc. The first element in brackets is the index
across the array (the 'X' value) and the second element is the index
down the array (the 'Y' value). In the above diagram, the box with the 200 in it would be set with Location(3,2)=200.
Once again, in your programs, you can replace the numbers with variables and use something like Location(XLoc,YLoc).
Finally to complicate things even further, you can take the dimensioning one step further by creating
3 dimensional arrays.
This would be akin to having a block of variables in a 3D Rubiks cube structure and storing a value in each of the small boxes that make one up. This would be done with:
Dim CubeArray(3,3,3)
In this example, the three values correspond to the X, Y and Z axis of the array and this will create a block of variables as shown in the image on the right. As you can see, the 'top slice' is just like the 2 dimensional array discussed in the previous section. However, as the DIM statement has a further Z value, then the array is stacked four deep - using the indices 0 to 3.
This gives you 4 variable grids, each one 4 across and 4 down and to set the variable highlighted in red to the value 10, you would use CubeArray(1,3,2)=10. In other words, 1 along the X axis, 3 along the the Y axis and 2 along the Z axis.
But, I doubt if you'll need to use an array like this for the forseeable future…
What You Can Do With Variables:
It's difficult to start giving programming examples this early in a series of tutorials as you will probably not be familiar with the commands being used, so I'll try to keep the examples as simple as possible.
In essence, you use variables to store things that can vary in your programs or when you want to store information that isn't available when you write the program.
For example:
Print "Please Enter Your Name: ";
Input Name$
CLS
Print "Hello ";Name$
This simple program will print the message 'Please Enter Your Name.' onto the screen. The next line uses BASIC's INPUT command. When your program reaches this line, it will stop for the user to type their name in. Whatever they type will be stored in the string variable Name$ when they press the Enter key.
On the next line, CLS will clear the screen and on the last line, the PRINT command will print 'Hello' followed by the contents of Name$, (whatever name they typed in).
Another example:
Print "Please Enter Temperature In Centigrade: ";
Input C
F# = 1.8*C+32
Print C;" degrees centigrade equals "; F#;" degrees Fahrenheit."
This example asks the user to enter a number for a temperature in Centigrade (Celsius) and stores the value in a variable called C.
The next line uses the variable C in a formula to convert the temperature to Fahrenheit and stores the result in the variable F#. Notice that this is a real number variable as the formula includes the value 1.8 which means that the result may be a real number too.
The last line prints out the result in a formatted sentence.
There you have it - two very simple programs which demonstrate the use of variables. However, these programs run just once and then end. You have to re-run them every time you want to use them again. What we want is for the programs to keep working until we tell them to stop.
That however is down to program layout and structure... which just happens to be one of the topics in the next tutorial!
Operators:
Variables aren't much use if you can't do anything with them, so a number of options are available to you for this task. Some of these options can be applied to numeric variables, some to strings and some to both.
Maths Operators:
Numeric variables wouldn't be very useful if you couldn't use them with basic maths in your programs so the basic operators add, subtract, multiply and divide are represented by +, -, * and / respectively.
Therefore, adding together two numeric variables is just as easy as adding two ordinary numbers. For example to add 30 and 50 normally we would put 30+50 and the answer would be 80. In a program, that would equate to:
A=30
B=50
C=A+B
Print C
...and when C is printed to the screen you see the number 80 printed.
More complicated formulas can also be built up with a combination of the four basic operators such as A=M*V/X+Z. However this brings into play a very important aspect of maths when programming -
Order Of Precedence. This is best explained with the following example so type it in and run it.
A=7
B=2
C=3
D=A+B*C
Print D
What is printed? It should be 27 right? 7+2 equals 9 then the 9 is multiplied by 3 to make 27. So why does it print 13?...
Aaaaaargh!!! Dark Basic is broken!!!
Actually, it's not... The reason is that Dark BASIC (like all programming languages) carries out maths in a specific order. This is known as the
Order Of Precedence.
Multiply and divide (* and /) calculations are done first, followed by addition and subtraction (+ and -). So, our little calculation above is carried out by multiplying B and C together
first to get 6 and
then adding A which makes a total of 13.
Now this may not be what you want - you may
want it to be done in the order that results in 27. You can force DB to do this by use of the '(' and ')' symbols (parentheses). Anything enclosed in parentheses is given a higher order of prececence and will be calculated before anything else. So:
D=(A+B)*C
...will force A to be added to B first before the result is multiplied by C. Result - 27!
Relational Operators:
These are used to compare data items (numeric and strings) and use the = (equals), < (less than), > (greater than), <= (less than or equals), >= (greater than or equals) and <> (does not equal) symbols.
Each one returns true (1) or false (0) and we touched on the subject earlier in the tutorial when we looked at IF A=100.
In a nutshell, we need in our programs a method to make decisions. In other words, do something only if another thing has already been done or act on a users input - that sort of thing. With relational operators and IF...THEN that is possible. So, let's have a quick rundown on IF...THEN first:
IF...THEN
Without IF...THEN statements, programs would be impossible to write as there would be no way to make decisions. The basic form is as follows:
IF condition
Do stuff here only if the condition is met
ENDIF
or...
IF condition
Do stuff here only if the condition is met
ELSE
Do this stuff only if the condition is NOT met
ENDIF
In both above examples, the condition is deemed to have been met if the condition is tested
True (returns a 1) and the relevant code is executed. Using IF...THEN you don't actually get to see the 0 or the 1, but that's what DB returns and acts on!
The first example is used if you want to carry out the enclosed code ONLY if a single condition is met - otherwise nothing is done. The condition might be as simple as checking to see if a variable equals a certain value or the user has clicked a mouse button.
The second example is used if you want to do one thing if a single condition is met and something else if it is not. If the condition was that a certain variable equalled say 10 then if it did equal 10 the block of code between IF and ELSE would be executed. If the variable contained ANY other value the code between the ELSE and the ENDIF is executed.
OK, that out of the way, on with the description of relational operators.
Note: It is taken for granted that the following examples are used with
variables as conditions in IF..THEN statements so instead, I'll show examples with
proper numbers along with what they would return.
Equals (=)
Checks to see if two items are equal. 1 is returned if they are, 0 if they are not. Eg:
10 = 10 - Returns True (1) as 10 does indeed equal 10.
10 = 11 - Returns False (0) as 10 does not equal 11.
Less Than ( < )
Checks to see if the first item is less than the second. 1 is returned if it is, 0 if it is not. Eg:
2 < 10 - Returns True (1) as 2 is less than 10.
7 < 5 - Returns False (0) as 7 is not less than 5.
9 < 9 - Returns False (0) as 9 is not less than 9.
Greater Than ( > )
Checks to see if the first item is greater than the second. 1 is returned if it is, 0 if it is not. Eg:
2 > 10 - Returns False (0) as 2 is not greater than 10.
7 > 5 - Returns True (1) as 7 is greater than 5.
9 > 9 - Returns False (0) as 9 is not greater than 9.
Less Than Or Equals (<=)
Checks to see if the first item is less than or equals the second. 1 is returned if it is, 0 if it is not. Eg:
2 <= 10 - Returns True (1) as 2 is less than or equals 10.
7 <= 5 - Returns False (0) as 7 is not less than or equals 5.
9 <= 9 - Returns True (1) as 9 is less than or equals 9.
Greater Than Or Equals (>=)
Checks to see if the first item is greater than or equals the second. 1 is returned if it is, 0 if it is not. Eg:
2 >= 10 - Returns False (0) as 2 is not greater than or equals 10.
7 >= 5 - Returns True (1) as 7 is greater than or equals 5.
9 >= 9 - Returns True (1) as 9 is greater than or equals 9.
Does Not Equal ( <> )
Checks to see if the first item is not equal to the second. 1 is returned if it is not, 0 if it is. Eg:
2 <> 10 - Returns True (1) as 2 does not equal 10.
9 <> 9 - Returns False (0) as 9 does equal 9.
So, to finish, a VERY basic little number game as an example of using what we have learnt in this tutorial. Don't worry if there are any commands that haven't been covered in the tutorial. I've commented the program and they will be covered eventually. If you like, look them up in the DB help files by pressing F1 when in the DB editor.
Randomize Timer(): Rem Initialise the random number generator
Start:
MyNumber=Rnd(99)+1: Rem Select a random number between 1 and 100
Do: Rem Main Program Loop
CLS: Rem Clear the screen
Print "I have thought of a number between 1 and 100. See how quickly you can guess it!"
Print
Input "What is your guess? ",Guess
Print
If Guess < MyNumber: Rem If chosen number is lower than computer's number
Print "Your guess was too low. Try again."
Sleep 2000
Endif
If Guess > MyNumber: Rem If chosen number is higher than computer's number
Print "Your guess was too high. Try again."
Sleep 2000
Endif
If Guess = MyNumber: Rem If chosen number is equal to computer's number
Print "Your guess was correct. Well done!!"
Print
Print "Do you want to play again (Y/N)?"
Repeat: Rem Repeat...Until loop repeats until Y or N key is pressed
I$=Upper$(Inkey$()): Rem Read the keyboard for keypresses
Until I$="Y" or I$="N"
If I$="Y": Rem If Y was pressed
Goto Start: Rem Jump to Start label at beginning of program
Else
CLS: Rem Clear the screen
Print "Goodbye...": Rem Print Goodbye message
End: Rem End the program
Endif
Endif
Loop
Note: The above program uses the Goto command to keep it as simple as possible and avoid things that have not been covered in the tutorials yet. I would never use this command anywhere else and urge you not to use it in your future programs either. In later tutorials you will see how to easily avoid using it.
Further Practice:
Feel free to alter the above program to see what it does. If you like, try changing it so that:
1. The program asks for the players name at the start and uses the name in the in-game comments. Eg: "Your guess was too high Peter. Try again."
2. When the user guesses correctly the program tells them how many guesses they took to do it.
3. When the player exits the game the program tells them how many games they have played along with their quickest and slowest games - guess-wise.
A working amended version of the program will be found in Part 2 of this series of tutorials so if you want to try to do it yourself, don't look until you have attempted it.
There is no right or wrong way to do these three tasks - some ways are just better than others. If you alter the program to do these three things and it works, then consider yourself having passed the test.
TDK_Man