Programming in (Q)BASIC

Note on this tutorial

I wrote this tutorial many years ago (2001-2002). Because of the large number of links pointing to it I've left it up. However, I no longer support it. Please do not contact me asking for help with QBASIC, ASM, or other programming issues. Also, please do not contact me about minor errors in the text: the text of this tutorial is mostly unedited, and only the presentation and markup have been significantly updated (to valid XHTML 1.0 strict). If there are major errors which significantly interfere with readability, though, please feel free to bring them to my attention - Billy Wenge-Murphy
This tutorial is (c) 2001-2007 Billy Wenge-Murphy. All rights reserved. It may not be copied, reproduced, or redistributed in any form without permission. If you wish to share it, please link to it instead of reposting it.

Perhaps you found your way here either because you're new to programming and would like to start of by learning BASIC, or on the other end you're an experienced programmer looking to hone your skills. While this tutorial primarily focuses on the former, I'll write separate sections for advanced techniques as well.

The thing I find most irritating about other tutorials is they usually assume previous knowledge of one language or another. As well, they often throw things at you and hardly explain what they mean, and why it's like that. I want to go against that trend. Therefore from here on in I'll write like you've never programmed before in your life, and try to cover important points in detail with sufficient explanation.

To start off, what is programming anyway?

1.1 - Introduction To Programming

A program is essentially something you write that's easy for you to understand because it's written in a form understandable to people. However, when you RUN or COMPILE it (make the computer do something with it) it's first changed into a form which can be run by the computer, and would be very hard for the average person to understand without a great deal of effort and training. How do you write a program. Basically, you write commands. These are special keywords telling the computer to do something. For example, one of the simplest commands in BASIC is the PRINT statement. It goes like this:

PRINT "Hello!"

When you type this in (you'll need a special program which can interpret BASIC, which I'll get to in a minute) and RUN it, you'll see a blank screen come up with the word Hello! in the corner. We can then conclude that what the print statement does is print out text on the screen. Then, why the "" around Hello! ? It will make sense later as you learn about variables, subprograms and other such more complex parts, but for now just accept that that is the syntax it should be in. You should have quote marks around the text to print. Don't assume though that all commands are a command followed by something in quote marks. That couldn't be further from the truth.

Now, I guess maybe you'll want to be able to actually write and run programs. The program we'll be making the programs with is called QBASIC. You might be able to dig it up on your windows CD, but if not, I recommend getting ahold of QB 4.5 somehow.

1.2 - A few simple commands

We'll start with a few simple commands. The first you already learned - PRINT. Here's a few more, which we'll go over:

COLOR
LOCATE
CLS

To start, let's go over color. Well, like it sounds, it has something to do with color (DUH!). It's important to note that most of the time a command with either be a descriptive word about what it does, or an acronym for a descriptive word.

COLOR does one thing. It changes the current color. What do we mean by current color? Well, when you use the print statement the text will be printed in whatever the "current color" is. This by default is grey. You use COLOR to change this. Unfortunately, COLOR is just a little bit complicated because instead of just saying:

COLOR Green

You have to use special numbers which are assigned to each color. The code number for green is 2. So let's see color in action by adding to our earlier example:

COLOR 2
PRINT "Hello!"

Our first program print Hello! in the default grey. Now that we put

COLOR 2

in front of it, it will print that same text in green. Notice that the number for the color is NOT inside quotes like the text for print was. Commands that take numbers generally don't need the number in quotes.

Here's a handy table which lists all the colors and their code numbers:

0 = black 4 = red 8 = grey 12 = light red
1 = blue 5 = magenta 9 = light blue 13 = light magenta
2 = green 6 = brown 10 = light green 14 = yellow
3 = cyan 7 = white 11 = light cyan 15 = bright white

It's time to make another important point. What should this program do?:

COLOR 6
PRINT "Hello!"
COLOR 1

Will it print the text in brown, or in blue? The answer is brown. Why? BASIC programs are in order, line by line. Even though

COLOR 1

changes the current color to blue, it will have no effect because of when it happens. This command comes after the print statement, so it doesn't affect it - by this time, the print statement has already done it's job. However, this program will print the text in both brown and blue:

COLOR 6
PRINT "Hello!"
COLOR 1
PRINT "Ahoy hoy"

It will print "Hello!" in brown, then on the next line down, "Ahoy hoy" in blue.

So, a print statement not only takes into account what the current color is, but also the current row number it should print on. Print automatically prints on the next line unless you tell it otherwise. You do this by using LOCATE.

LOCATE takes two things with it called parameters. The number that color needs to work, or the text that print needs are also called parameters. Basically, any information you give to the command to make it go is called a parameter. For locate, you give it two numbers. First the row number then the column number. The screen has about 24 rows and 80 columns. Each number can only be whole (because there's no in between) and must be >0. For example, to move the text down to the 5th row:

LOCATE 5,1

Again, no quotes here. Perhaps you want to move it to the middle of the screen:

LOCATE 12,40

Which is about the middle of the screen. Locate is pretty easy to understand. Just don't give it numbers too big, or less than zero, because you'll get error messages and your program won't work. Something even as minor as that is called a bug. Little things like that can mess up a whole program, so watch even for such minor details. It can be very irritating to find when your program is in the 100s or 1000s of lines.

That's simple enough. Here is a command even simpler: CLS. This is an acronym for CLear Screen. It does what it sounds: Clears the screen. The screen is not automatically cleared of text after you run the program, so you may notice junk text leftover if you run a program over and over. Usually you'll want to start a program with CLS, but as you go on you'll find less and less use for it.

1.3 - Interaction

Well, it's all fine and dandy to be able to give the user some information, but to really do anything interesting you'll need to get input from the user. To start, we'll get input by asking questions and so on, or prompting them to type something in. Later, we can make games by using the keyboard as a control. And if you're really ambitious, with a deep understanding of BASIC you can move on to using the mouse (this is a rather technical procedure if you're into not just doing, but understanding - which i advocate: it's for advanced programmers only). So, here's what we'll be looking at:

INPUT
IF...THEN...ELSE

Again, it does like it sounds. It gets some input. This one's a bit different though. The parameter is a variable.

Variables are a BIG part of programming. Unlike in the math sense, you use them to store things. There's different kinds of variables to store the different types of data. For example, there's numeric variables to store.... numbers, of course. Then there's string variables to store strings (one or more characters of text. the message in the earlier print statement is a string). There's actually more than one type of numeric variable, but don't worry about that as of yet. So, let's make a simple program to ask the user their name.

PRINT "What's your name?"
INPUT n$
PRINT n$ ; "? What a terrible name!"

So, what here does input n$ do? It tells the computer to prompt the user to type something in, then it stores whatever they type in in that variable. They'll probably unwittingly enter their name, only to be told by the computer a second later that it's a terrible name. But something is different about this print statement. It has a semi-colon. It's very simple - in a print statement, you can connect multiple things with a semicolon. You need it if you want to print out both n$ and ? What a terrible name!, on the same line. Notice that you can print out variables as well as plain messages. Because n$ is not in quotes, it prints out whatever's in that variable. If it was in quotes, it would literally print out n$ on the screen, rather than whatever was entered through INPUT.

Notice now that the variable is called n$. Why is it called this specifically. Well, you can name a variable whatever you want! It just has to only numbers and letters, and cannot start with a number. But doesn't the $ at the end break this rule? NO. That $ tells the computer that this variable will hold a string. If you drop the $, it signifies that it's holding numbers. It may seem that a string is no different than a number, but that's not true. Numbers and strings are treated differently, so properly label your variables!!

Names of variables can be pretty long. I could have chosen name$, username$, nameofthepersonusingthisprogram$, anything i want pretty much. But i prefer short variables. However, name$ is probably better because it makes your program easy to read, something very important for long programs.

Another very important part of programming is making decisions based on the input. A simple way to do this is the IF statement. This is throwing rather a lot at you at once, but I don't want to lose your interest.

With IF you basically give it something that could happen. There's a word that goes with it; THEN. Whatever comes after THEN is what it should do; But, it only does it if the IF thing happens. For example, let's looking at a little number guessing game:

num = 7
PRINT "I'm thinking of a number between 0 and 15. Try to guess it in one try!"
INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"

Wow, that if statement is long! Let's break it down. It says first:

IF guess = num

So, it's going to check to see if guess and num contain the same number.

THEN PRINT "Yeah! You got it right"

a THEN statement only happens if an IF statement is true. so if they put in 6, 0, 1, 6.83451, -2, and on the whole anything but 7, this wont happen. but there's still one more part:

ELSE PRINT "Sorry! That's wrong!"

If they get it wrong, the THEN doesn't happen. But, we want to give them a message anyway. That's where else comes in. Else happens if the IF turns out to be false - what it was looking for didn't happen.

1.4 - Eliminating redundant code: Loops

What if we wanted to give them more than 1 guess? Say, 6 guesses this time. Well, we could do it like this:

num = 7
PRINT "I'm thinking of a number between 0 and 15. Try to guess it in one try!"

INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"
INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"
INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"

INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"
INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"
INPUT guess
IF guess = num THEN PRINT "Yeah! You got it right" ELSE PRINT "Sorry! That's wrong!"

Well, that's very redundant. You typed (or maybe copy+pasted) the same code 6 times! That's terrible programming practice, and just flat out boring to do. So, let's look at something at takes care of things that need to be done many times: Loops. Here's a couple kinds of loops and loop-related commands we'll look at:

For...Next
Do...Loop
Exit for
Exit do

Okay, let's use the first one to make this program a few lines shorter. In a for loop, we give a variable and a value it should start at. Then, we make it loop, adding to this variable every time it runs through, until it gets to a certain point. An example loop might look like this:

FOR a = 1 TO 10
....
....
....
NEXT a

The dots in the middle are just my way of saying you'll put some stuff between there, and it'll be whatever you want, as you'll see in a second. So, this loop will take the variable A (remember it will store a number because it doesn't have a $ after it - you can't do number math with a string variable) and make it equal 1. Then it will do whatever stuff you want it to. It will keep doing things until it comes to the words Next A. This closes the loop. It goes back to the beginning, adds 1 to a, and does it again and again like this unless a is more than 10.

num = 7
PRINT "I'm thinking of a number between 0 and 15. Try to guess it in 3 tries"
FOR a = 1 TO 3
INPUT guess
IF guess = num THEN
	PRINT "You got it!"
EXIT FOR
ELSE
	PRINT "No, sorry"

END IF
NEXT a

So, we now know this loops 3 times. First A is 1, then 2, then 3. So, it asks for a guess 3 times. Notice I did something different with the IF...THEN...ELSE part. It's still the same statement, but it's spread across multiple lines to allow it to do more: It sees if guess = num. If it does, then it does 2 things. It prints a positive message, and it breaks out of the loop. Obviously we don't want to ask them over and over after they got it right like our first program did. So, we break out or exit the loop. Exit for means exit the for loop, whether a is 3 yet or not.

If they didn't guess right we go to the else statement and do what comes after it. We give them a negative message. Obviously we could have a gazillion lines after THEN if we wanted to, and the same with ELSE, because this format lets us do more than one thing per IF and more than one thing per ELSE. So, we have to tell the computer to end the if statement somewhere, just like the loop ends (and loops again) somewhere. That's what END IF does. It ends the IF statement.

When we stretch an IF...THEN on for multiple lines like this, and end it with END IF, it's called an IF-END IF block

I realize this has been a lot of information to digest at once. As you read my tutorial, make sure you understand it pretty well before you move on. Programming, like math or language, builds on itself, and the more you press on knowing less, the harder it gets. If you go to far without understanding very much, you'll eventually just break down and reteach yourself anyway.

Let's take a different approach to this program. Lets make it so that the user keeps guessing until they get it right. For this, we'll need a loop that doesn't just go for a set number of times. This is where the DO LOOP is handy. A do loop may look like this

DO
.....
.....
.....
LOOP UNTIL num = guess

This loop theoretically could go forever, because num has to = guess for the loop to end. If that never happens, the loop never ends (another easy place for bugs....). So, here's yet another version of the program, using a DO LOOP:

num = 7
PRINT "I'm thinking of a number between 0 and 15. Try to guess it in 3 tries"
DO
INPUT guess
IF guess <> num THEN PRINT ":Sorry! NO!"

LOOP UNTIL guess = num
PRINT "You finally found the number! Good job!"

So, what's happening here. Well, again the basic stuff. It asks for input every time the loop goes. Notice i made an if statement that was a little different though. I said if guess <> num. What's with that? Well, <> means "Greater than or less than". So, if they guess something that's greater the number, they get told it's wrong, and if they guess less than the number, they're told it's wrong. So, the only thing that wouldn't make it say no would be if it's equal. If they guess the right number then, they're not told it's wrong. And look at the part that says loop. It only loops is guess doesn't = num. So, it basically loops again, giving them another chance, if they're wrong. If they are right, the loop ends and it says they're right. This program is much easier and cleaner than the two previous, and runs slightly faster (although not noticeable, it does take milliseconds less to process because less stuff happens)

One last thing. Remember EXIT FOR to get out of a FOR LOOP? Well, there's a similar statement, EXIT DO, that you can use if you want to prematurely end a DO LOOP for one reason or another.

1.5 - Even more input

Commands/keywords for this section:

SCREEN()
INKEY$
AND

If you got all previously discussed, you've already mastered a small chunk of the language. So far, I've given you some very important commands in BASIC. But i tend to gear my tutorials to eventually culminate in game design, so let's look some very humble beginnings for a pac-man style game.

For simplicity, let's make a very tiny, basic maze. This is not a maze we'd really want, but it's okay to learn from. Let's just put it right on the screen with some print statements:


PRINT "0000000"
PRINT "       "
PRINT "0 000 0"
PRINT "0 0 0 0"
PRINT "0     0"
PRINT "0 000 0"

PRINT "   0   "
PRINT "0     0"
PRINT "0000000"

Wow! It's craptacular! Anyhow... that'll do for now. Now, in this maze, our character will be an asterisk - we'll do more aesthetically pleasing games once we get into graphics, files, and all that fun stuff. Again, for the sake of simplicity, you'll control him with the number pad.

So, let's think a bit on how we'll accomplish this. We'll draw a maze, with print, and draw the asterisk character with print. We'll need the help of locate to position him in the maze. The user will hit keys - which we'll show you how to do in a second - to move the guy around. Of course, if we LOCATE him, we're gonna be using coordinates.

So, let's plan that out: The first empty space in the maze is at 2,1. We'll start him there. If he moves up he'll go to 1,1 and if he moves down he'll go to 3,1. So, we'll subtract to move him up, add to move him down. The same logic applies to left and right. From 2,1 if he goes right he'll be at 2,2 and if he goes left he'll be at 2,0 (yes, that zero is not allowed with locate, but this is purely hypothetical). So, we'll add to go right and subtract to go left. Good, that's most of the work right there.

But, what about not running into walls? Well, I'll introduce you to a seldom used command called the SCREEN function. It can actually get info straight off of the screen, after it's been printed! Unfortunately, I also have to introduce you to a hideous monster called ASCII.

Let's start with the really confusing part to get it out of the way. What is ASCII?. It's an acronym for "American Standard Code for Information Interchange". Essentially, it goes like this: It gives a special code to 256 different characters, letters, numbers, and symbols. Believe me, it is helpful, but I hate to have to throw such things at you which are not easy to comprehend at first glance. You'll see as you program more that it is useful, and start to understand why it's around, but whether you do or not it's an important part of programming, and unfortunately must be covered. Here's the ASCII table as it appears in QBASIC's help menu

ASCII chart ASCII chart

The reason why i mentioned this is because the SCREEN function will spit out what it's supposed to, but instead of a simple character of text like you'd expect, it gives you an ASCII code. For example, say we've printed our maze and we do this:

PRINT SCREEN(1,1)

It will give you the number 48. Clearly, there's a 0 at (1,1), not a 48. Well, 48 is the ASCII code for 0. So, we'll only let our guy move onto something if there's not a 0. To do this, we'll look at where he's trying to move with SCREEN(). If it gives us a 48, he's not allowed to move there and he stays put.

Now for the other technicality: INKEY$ We don't want input statements constantly prompting the user, making them type something in, and hitting return. We want to be able to move around easily. INKEY$ is a special variable. Whenever you hit a key at any time (outside an input statement), even if seemingly nothing else is happening, QBASIC takes that key and puts it into INKEY$. So INKEY$ is very handy in a situation like a video game, because you can let the enter single keystrokes without any prompting. Take this loop for example:

DO
LOOP UNTIL INKEY$ = "1"
PRINT "You broke out of the loop!"

There's nothing in it! That doesn't matter, because if the user is hitting buttons while this empty loop runs, the key goes into INKEY$. When they hit anything but 1, nothing happens. But if they hit 1, the loop ends. However, I usually write that kind of loop like this:

DO
a$ = INKEY$
LOOP UNTIL a$ = "1"

PRINT "You broke out of the loop!"

Why do that if you can just look at INKEY itself? Isn't that extra pointless code? Well, INKEY$ is constantly changing and very touchy, so this loop works better, because you have something more solid to look at. INKEY$ changes so frequently that hitting the right key might not break the loop. I am just in the habit of doing A$ = INKEY$, then checking it. That is the style I'll use in this tutorial as well.

Let's start to write the code based on what we just discussed

CLS
y = 2
x = 1

COLOR 15
PRINT "0000000"
PRINT "       "

PRINT "0 000 0"
PRINT "0 0 0 0"
PRINT "0     0"
PRINT "0 000 0"
PRINT "   0   "
PRINT "0     0"

PRINT "0000000"

DO

 a$ = INKEY$
 checky = y: checkx = x
 LOCATE y, x: COLOR 0: PRINT "X"
 IF a$ = "8" AND y - 1 > 0 THEN checky = y - 1
 IF a$ = "4" AND x - 1 > 0 THEN checkx = x - 1
 IF a$ = "2" THEN checky = y + 1
 IF a$ = "6" THEN checkx = x + 1
 IF SCREEN(checky, checkx) <> 48 THEN
  y = checky
  x = checkx
 END IF
 IF X > 7 then x = 7
 LOCATE y, x: COLOR 15: PRINT "X"

 LOCATE 10, 10: PRINT x, y, checkx, checky
LOOP UNTIL a$ = "Q" OR a$ = "q"

A few new things here, but the rest isn't too complex. Firstly, there's AND. It's a special word you can use in IF statements, making them more specific. This line for example:

IF a$ = "8" AND y - 1 > 0 THEN checky = y - 1

Recall that the thing after THEN won't happen if the IF didn't. We use AND to give it more conditions. A$ has to be 8 AND y - 1 has to be more than zero. If those are both true, then we'll give the variable checky a value that's one less than y. This thinking applies to the next line also.

The next new thing here is colons. They let you put more than one command on a line. This is just a matter of style. This line:

LOCATE y, x: COLOR 0: PRINT "X"

Works the same as these lines:

LOCATE y, x
COLOR 0
PRINT "X"

There is absolutely no difference, i just felt like putting them on one line to make it look neater (to me anyway) Same with the indenting; i like to indent code that's between DO....LOOP, and indent code between IF...END IF. Although it's perfectly fine not to indent, you'll see most programmers do this indenting with ifs and loops, and other such blocks of code.

Now that that's out of the way, let's step through this program.

First we clear whatever may be on the screen from before. Then we set the variables that store where the 'character' is on the screen. We draw the maze (using COLOR 15 because i wanted a white maze). Now we enter the main loop. Good programs have a main loop (where necessary). Then, we put INKEY$ into another variable to make it easier to work with. Here it gets going:

checky = y: checkx = x

Since we're going to be checking to see if they try to run over a wall, i chose to use different variables that remember where they're 'trying to move'. Later the program looks at what character is on the screen there. If it's character 48 according to the ASCII table, which is a maze wall, then they don't actually move there.

Just like LOCATE, SCREEN ( ) can't have zeros in its parameters. So the ifs for moving up or moving left make sure that the program doesn't even bother checking if they would be trying to move off the screen [to (0, x) or (y, 0)]. Also, after all the checks are done and stuff like that there's this line:

IF X > 7 THEN x = 7

There's no maze past 7 on the x axis, so we don't let them move there!

We'll get back to finishing this game later as we learn more. It would be big and difficult using only what we know now. A pac-man like game has more things to it: pellets, power pellets, enemies, multiple levels. We'll need more knowledge to work with before we can accomplish these.

Mascot: Billy's Weird Cat Thing