============================================================================== TEK'S DEFINITIVE QBASIC/QUICKBASIC GUIDE BY TEK ------------------------------------------------------------------------------ Author: Jason Jones (Tek, neozones@quickbasic.com) Created: 06.15.1999 Last edit: 06.20.1999 Last Revision: 07.15.1999 Filename: teksdqbg.txt Version: 1.0.0 Currently, my site is located at http://neozones.quickbasic.com, and I can be reached by email at neozones@quickbasic.com. My ICQ number is 825301 if you wanted to add me. Okay, now with that over with, let's dive into QBasic. I always wanted to write a whole book or set of chapters for QBasic, but never got around to it. After so much exposure in the QBasic community, I am really going to put something back in with the best tutorials and stuff that I can write. Without further ado, here is my "book", starting out at the absolute beginner programming level. ============================================================================== TABLE OF CONTENTS ============================================================================== QBASIC Introduction Overview Making a program TEK'S MAGNA CARTA: CHAPTERS Chapter 1 - Parts of programming Chapter 2 - Introduction to variables Chapter 3 - Printing data to the screen Chapter 4 - Input from the user into the program Chapter 5 - Cummulative review, comments, END Chapter 6 - Basic IF-THEN-ELSE statements Chapter 7 - SELECT CASE (similar to IF) Chapter 8 - FOR loops Chapter 9 - DO loops, WHILE loops Chapter 10 - More on IF-THEN-ELSE Chapter 11 - CONST, TYPE, intro to DIM Chapter 12 - DIM, single dimension arrays Chapter 13 - Doing basic math Chapter 14 - Simple sounds: BEEP, SOUND, PLAY Chapter 15 - More to do with strings Chapter 16 - More on math: ABS, COS, SIN, etc Chapter 17 - Do it yourself: input from the keyboard Chapter 18 - Keyboard continued: arrow keys Chapter 19 - Intro to files: APPEND, OUTPUT, PRINT Chapter 20 - Reading files: INPUT, LINE INPUT, EOF Chapter 21 - Binary files: GET, PUT, BINARY Chapter 22 - More great stuff with strings Chapter 23 - Intro to graphics The following chapters are not written yet, however, they will be added once they are written. =) Chapter 24 - Primitives: LINE, CIRCLE, PSET, PAINT, DRAW Chapter 25 - More on graphics: GET, PUT Chapter 26 - BSAVE, BLOAD: intro to VARSEG/VARPTR Chapter 27 - More on strings, ASCII set Chapter 28 - More on arrays Chapter 29 - Subroutines overview Chapter 30 - Subs Chapter 31 - Functions Chapter 32 - Variable scope Chapter 33 - Back to graphics: WAIT for vertical retrace Chapter 34 - Working with the palette Chapter 35 - Text mode: VIEW PRINT, CLS, LOCATE Chapter 36 - More text mode mechanics, and WINDOW Chapter 37 - Simple timing and delays: TIMER, SLEEP Chapter 38 - Time and date Chapter 39 - QuickBASIC only stuff, metacommands Chapter 40 - Misc commands/sounds: STOP APPENDIX Tricks of the trade FAQ, Q & A Variables defined Coordinates Common algorithms Programming humor Glossary/buzzwords Books Websites/email Greets Release notes, history ============================================================================== QBASIC ============================================================================== --- Introduction ------------------------------------------------------------- QBasic is a "simple" language that's been around for many years. The most popular implementations of BASIC dialects for DOS (as far as I know) would be QBasic 1.1 and QuickBASIC 4.5. However, there are many other dialects of BASIC. (By the term "dialects" I am referring to different versions and types of BASIC. These include PowerBASIC, (has almost identical QB syntax, plus some extras), FirstBASIC (a stripped down version of PowerBASIC), VBDOS (Visual Basic for DOS, created by Microsoft), Visual Basic (Windows versions 2, 3, 4, 5, 6) also by Microsoft, XBasic, ASIC, Moonrock, Chipmunk (Mac), TrueBASIC (Mac, I think..), BASM286, and more. You can download QBasic 1.1 for free from my site at: http://neozones.quickbasic.com/basfiles/misc/qbasic11.zip The other popular version of QBasic is QuickBASIC 4.5, which is not free like it's cousin version 1.1. If you ask for it from me, I will NOT send it to you. --- Overview ----------------------------------------------------------------- QBasic is great for whipping up programs on the fly. It has a great IDE (the interface you use to create programs), great syntax checking (tells you what's wrong, more or less), and is very flexible. Of course, the more complex that you make program, the more complex your code gets, and the resources available to QBasic might not be as plentiful as they once were. That's one of the major downsides to QBasic: memory and speed. Unless you make your own routines in ASM or QBasic to tap into the rest of the system's memory, you are limited to 640k of data and code space. Also, largely due to the fact that QBasic is so flexible, you sacifrice speed of the program in general. That's why a program in QBasic and it's equivalent compiled under C are likely to have such differing speeds. --- Making a program --------------------------------------------------------- To make a program in QBasic, first open up QBasic. Most of us can type in "qbasic" or "qb" at the prompt in order to load the program. Some of us might do something different. As long as you load the program, it's all fine. Upon loading qbasic.exe or qb.exe or whatever version you have, you'll see an editing screen and some menus. The screen is blank and ready for us to type things in. With the file menu, we can make a new program, open one, save one, quit, and do a few other things. In QBasic, as with just about every other computer language on the planet, you type things in to make things happen. By working with parts of the system, variables, code, and code that performs actions, you make a program. Let's examine a classic "hello world" program. CLS PRINT "hello world!" END Type those three lines into QBasic, then save your program as hello.bas. If we want to run the program and see what happens, you can press F5 or goto the Run menu and click on Start. What should have happened is this: the screen cleared (to a blank black text screen), the message "hello world!" (with no quotes) was printed, and then the program ended. If you look at the program, you can see how the lines correspond to what happened: CLS cleared the screen (CLearScreen) PRINT printed out the text in the quotes END ended the program (sidenote: END was not needed because the program was out of things to do and would have ended normally, however, we explicitly told it to end the program which is a good programming habit) If you save the program as hello.bas, you can come back to it later and open it up and resume work on it. ============================================================================== TEK'S MAGNA CARTA: CHAPTERS ============================================================================== --- Chapter 1 ---------------------------------------------------------------- Well, with all the introduction out of the way, let's get into coding and make an awesome 3d shootemup like Quake! Oh wait, not quite. Heh. First you must understand the language. The main aspects of coding are variables, program flow, and the system. VARIABLES are names that you use to store values. Such as if you were playing a game like Quake, you might have a name for the character, which needs to be stored in a variable. You would also store numbers such as your health, armor, and time elapsed in the game. QBasic has several specific variable types to choose from. The most common are integers and strings. (For more info on variables, see the Variables section in the appendix). PROGRAM FLOW determines what the order of execution of statements in your program is. For instance, in a simple database program where the program asks the user if he/she has any fruit, you would take different courses based on whether the response was yes or no. If the answer was yes, you might go on to ask what type of fruit it was and how many there were. If it was no, then you don't need to ask what it is or how many there are. Example: CLS INPUT "Do you have any fruit (y/n): ", Prompt$ IF Prompt$ = "y" THEN INPUT "How many do you have: ", HowMany% ELSE PRINT "You have no fruit!" END IF END If you don't totally understand the code, don't worry. You will. =) THE SYSTEM is everything dealing with files (data resources) the screen mode (graphics, text, or whatever), and associated things that aren't code nor variables. --- Chapter 2 ---------------------------------------------------------------- Introduction to variables: assigning values. Let's say that we want to keep in mind a certain value over the course of the program. This value might be your "lucky number" for instance. Example: MyLuckyNumber% = 26 QBasic will create or change the value of the variable MyLuckyNumber% to the value 26. The % sign identifies the variable as an INTEGER. Essentially this means that the variable can hold a NUMBER value from about -32,000 to +32,000. If we want to store a value such as someone's name, we have to use a string variable. Such as: MyName$ = "Jason" Notice that the term "Jason" is in quotes. QBasic MUST have these quotes so it knows you are putting text into a string variable. --- Chapter 3 ---------------------------------------------------------------- Now that we are into programming, we'll work with one of the most basic aspects of a program: printing stuff for the user. By the word printing, I am referring to showing text/data on the screen. To print a message we'll use the PRINT word (whoa, so complex). =) We can use this flexible command to show text, variables, and format text according to a template (covered later). To print out direct text, put what you want to "say" in quotes (""). PRINT "hello there! welcome to my program!" Remember our variables from earlier? Let's print them out! MyLuckyNumber% = 26 PRINT MyLuckyNumber% This code snippet will print 26 on the screen. Or if we wanted to print out a string, we could use this: MyName$ = "Jason" PRINT MyName$ What if we wanted to use a combination of the two? You might do this: MyName$ = "Jason" PRINT "Hello! My name is "; MyName$ That example will show "Hello! My name is Jason". Moving on. --- Chapter 4 ---------------------------------------------------------------- Letting the user put values into the program can be done with INPUT. The following example will ask the user for a lucky number, store it in the variable YourLuckyNumber%, and then show that number. INPUT "Please enter your lucky number: ", YourLuckyNumber% PRINT "You said that your lucky number was"; YourLuckyNumber% The INPUT command, as you can seee, will take input from a user and store it in the variable. The variable after the prompt asking for the user to enter a lucky number is where the user's keyboard input will be put. --- Chapter 5 ---------------------------------------------------------------- Now that we'eve progressed this far, let's backtrack a little and introduce CLS and END real fast, as well as comments for the program. CLS clears the screen. Later on you will see a couple other uses for CLS. END tells the program to quit. Remarks can be made with an apostrophe or the REM statement. For instance, if you wanted to leave yourself a note on some code so you might understand it later, or just to comment the program for other people to read, then can do this: PRINT "Welcome to the game!" ' welcome the user Everything after the ' is ignored by QBasic. ' is slightly more flexible than REM, but you can use REM on the beginning of a line to comment it. It does the exact same thing as '. REM Welcome the user PRINT "Welcome to the game!" Here's a cummulative example of everything so far: ' this program gets a number from the user and then shows it ' on the screen CLS INPUT "Enter a lucky number: ", LuckyNumber% PRINT "You said your lucky number was"; LuckyNumber% END --- Chapter 6 ---------------------------------------------------------------- Basic program flow with IF statements is a fundamental part of programming. This chapter will introduce you to IF statements and go over how they work. First off, earlier in the book we were doing a comparison of a response to a variable to determin the flow of a program. But let's make it simpler. What if we want to ask the user for input and if the user enters the number 5, then it will do something "more". INPUT "Enter a number: ", Number% IF Number% = 5 THEN PRINT "You entered the special number 5!" As you can see, we prompt for a number. Then we do an IF statement which literally reads "If the number is equal to 5, then do the following command." What if we wanted to do more than one thing due to the user input? We can put all actions we want to perform between the IF statement and the END IF. Like this: INPUT "Enter a number: ", Number% IF Number% = 5 THEN PRINT "You entered 5!" PRINT "Here is another line!" END IF Cool eh? =) What if we want to do certain commands if the number wasn't equal to 5? In other words, we'll have a default response: INPUT "Enter a number: ", Number% IF Number% = 5 THEN PRINT "You entered 5!" PRINT "Here is another line!" ELSE PRINT "You didn't enter 5!" END IF So if the user enters 5 we have a certain set of commands, or if they enter something else, we have a "default" response. What about testing multiple conditions? No problem! INPUT "Enter a number: ", Number% IF Number% = 5 THEN PRINT "You entered 5!" PRINT "Here is another line!" ELSEIF Number% = 4 PRINT "You entered 4!" ELSE PRINT "You didn't enter a 5 or a 4!" END IF --- Chapter 7 ---------------------------------------------------------------- There are a few more things we can still do with IF (multiple conditions), but we'll move on to SELECT CASE for now. Essentially, SELECT CASE is like a bunch of IF-THEN-ELSE statements, but it's setup a little differently. Observer the preceding code converted to SELECT CASE. INPUT "Enter a number: ", Number% SELECT CASE Number% CASE 5 PRINT "You entered 5!" PRINT "Here is another line!" CASE 4 PRINT "You entered 4!" CASE ELSE PRINT "You didn't enter a 5 or a 4!" END SELECT (We'll do some more SELECT CASE stuff later, along with the other IF stuff such as less than/not equal/greater than). --- Chapter 8 ---------------------------------------------------------------- Moving right along aren't we? Now we'll start loops. Loops are very good ways to do things. For instance, we want a number guessing game to run until the user guesses the number right. We could do this with straight IFs, but it could potentially be never-ending! Let's say we want to "loop" and give the user 10 chances at getting the number right. FOR i% = 1 TO 10 INPUT "Enter your guess: ", Guess% IF Guess% = 5 THEN PRINT "You got it!" END END IF NEXT i% PRINT "You didn't get it!" This code loops 10 times (1 to 10), doing the same statements each time. i% is a variable. If the user gets the number right (5) then we'll tell them so, and end the program. Otherwise, the program procedes to 10 guesses and if they don't get it, the program leaves the FOR loop and the last PRINT statement is executed, telling the user that they didn't get it. Similarly, if we wanted to go thru the loop 10 times we could do any of these: FOR i% = 2 TO 11 NEXT i% FOR i% = 10 TO 100 STEP 10 NEXT i% FOR i% = 10 TO 1 STEP -1 NEXT i% The value after STEP tells FOR what to increment after each loop. Obviously, the default value is 1. Note that the variable (i%) can be anything you want, I merely used a common counter variable. In nested loops, it is common to use i%, j%, k% and so on, or whatever descriptive variables you want to use. Note also that the NEXT command can be blank or with a variable on it. I have observed and communicated however, that if you put the variable on, there is a slight speed gain (a good thing). Last of all for the FOR statements, what if we wanted to exit the FOR prematurely? We can use the EXIT FOR command. Look at this: FOR i% = 1 TO 10 IF i% = 5 THEN EXIT FOR NEXT i% When i% = 5, the code will jump out of the loop. This is illustrated by the following snippet: FOR i% = 1 TO 5 PRINT "i% ="; i% IF i% = 5 THEN EXIT FOR NEXT i% --- Chapter 9 ---------------------------------------------------------------- FOR..NEXT loops are great for finite processes (especially for arrays which we'll get to later..), but there are also some other types of loops available to QBasic, namely DO..LOOP, and WHILE..WEND. I seem to recall reading some documents for Visual Basic and the author really said that WHILE..WEND was totally pointless in contrast to DO..LOOP. Although I still find uses for it, and it may be a bit different, you can be sure of a couple things: If it works for you, then by all means, go for it. It's probably still in the BASIC language to keep backwards compatibility. But back on track, to sum up how these loops differ from FOR loops is that they don't necessarily stop after a finite number of iterations. You get to control the termination conditions (if any) yourself, like a builtin IF statement, as well as controlling the counter yourself. Let's take a quick look at an example: i% = 0 DO i% = i% + 1 PRINT "i% ="; i% LOOP UNTIL i% = 10 If you can tell, what we did was start out i% at 0 (would have defaulted to 0, but it's good practice to at least initialize the variable so that if it were somewhere else in the program, it wouldn't possibly start out on some "residue" value). We entered the DO loop with DO, and for each iteration we add 1 to i%, print it out and the loop condition is to "go UNTIL the variable i% is equal to the number 10". Note that the statement to check for the condition is at the end of the loop, so that the code in the loop will occur at least once, as opposed to if we did it this way, which also works: i% = 0 DO UNTIL i% = 10 i% = i% + 1 PRINT "i% ="; i% LOOP The DO loops don't NEED any break conditions. Using the EXIT DO command to exit the loop, we can do this: i% = 0 DO i% = i% + 1 PRINT "i% ="; i% IF i% = 10 THEN EXIT DO LOOP As for the WHILE loop, it's like a DO loop with the condition at the top, as well as not being a UNTIL condition. We sorta have to use a double negative here, so we'll tell it to loop WHILE i% is not equal to 10. For instance: i% = 0 WHILE i% <> 10 i% = i% + 1 PRINT "i% ="; i% WEND Easy stuff eh? Cool. --- Chapter 10 --------------------------------------------------------------- Time to revisit the IF statement. This extra knowledge also comes in handy for loops as well. So far all we really looked at was IF a variable equals (=) something. But there are so many more ways to do it! For example, what if we wanted to see if a variable is unequal to a certain number? Number% = 3 IF Number% <> 5 THEN PRINT "Number is unequal to 5" END IF What if the number is less than something? Age% = 10 IF Age% < 20 THEN PRINT "You are a youngin'!" END IF Or greater than something: Age% = 42 IF Age% > 20 THEN PRINT "You are old! (just kidding)" END IF Or less than/equal: Age% = 15 IF Age% <= 21 THEN PRINT "You cannot legally purchase beer in the US!" END IF What about combinations of things, all in one IF statement? QBasic gives us OR and AND for simple comparisons. In other words, we can see perhaps if a number is less than 20 and greater than 10. Number% = 15 IF Number% < 20 AND Number% > 10 THEN PRINT "The number is between 10 and 20" ELSE PRINT "The number is less than 10 or bigger than 20" END IF Alternately, we can check for the opposite: Number% = 15 IF Number% < 10 OR Number% > 20 THEN PRINT "The number is less than 10 or bigger than 20" ELSE PRINT "The number is between 10 and 20" END IF Note that all these coparisons and such can also be used for the condition on loops (not FOR conidtions, as they don't have them). --- Chapter 11 --------------------------------------------------------------- More fun with variables. =) Oh boy, party time. Let's explore CONST and TYPE, with an introduction to using DIM. CONST is a constant in the program, a variable that can't have it's value changed. A very classic example of using CONST is to store PI. If you use PI in your program for doing calculations or something to that nature, you might put the value or approximate value into a constant variable for quick access and changing. TYPE is a memory structure that the program can use to store information in a hierarchal way. Each element can have certain aspects to it, combinations of variables can be used. To use CONST, just declare a normal variable to assign a value to: CONST PI = 3.141 It is general programming practice to capitalize the name of the constant variable. Probably the most used CONST would be for TRUE and FALSE. To track "yes or no attributes" for your program, you could do this: CONST TRUE = -1, FALSE = 0 INPUT "Enter your age: ", Age% IF Age% > 65 THEN SeniorCitizen% = TRUE END IF As mentioned, these constants are very useful for tracking conditions in the program that you want to track yourself. Now for TYPE. Let's say we had an object that we were describing, such as a person. Rather than make lots of variables like this: PersonFirstName$ PersonAge% PersonWeight% PersonHeight% PersonFavoriteColor$ We can group them into a TYPE: TYPE PersonType FirstName AS STRING * 16 Age AS INTEGER Weight AS INTEGER Height AS INTEGER FavoriteColour AS STRING * 16 END TYPE DIM Person AS PersonType To fresh your memory, you'll notice that we declared the variable type ourselves, because you don't use signs (%, $, etc) on the TYPE variables. STRING * 16 means that we want to allocate space for a maximum length of 16. It should be big enough for a first name. The DIM statement says that we want to make a set of variables like the set PersonType, in the name of Person. You see, PersonType was merely a memory outline, or a template, of what to create. To set the variables, we'll do this: Person.FirstName = "George" Person.Age = 24 Person.Weight = 160 Person.Height = 6 Person.FavoriteColour = "Orange" Simple, right? Good. If you're feeling a little confused, just play around with it on your own. Similarly, to print out these variables, we might do this: PRINT "First name is: "; Person.FirstName And so on. --- Chapter 12 ---------------------------------------------------------------- One of the most important aspects of programming, or at least, large programs or complex programs, is that most of them use arrays to perform tasks. What if we wanted to create a list of 9 peoples' names? You *could* do this: Person1$ = "Albert" Person2$ = "Benjamin" Person3$ = "Carl" Person4$ = "Dave" Person5$ = "Earl" Person6$ = "Francis" Person7$ = "Gary" Person8$ = "Harry" Person9$ = "Ian" But that seems a little tiresome, and not very efficient. And if we wanted to print them all out, we'd have to PRINT Person1$, etc. There has to be a better way to do this! And indeed, there is. What if we make an array? Basically, we'll give all the variables the same name, except we'll use numbers to refer to individual items. Check this out: DIM Person$(1 TO 9) Person$(1) = "Albert" ... Person%(9) = "Ian" Now, if we wanted to print all of these out, what could we do to make that easy? You guessed it, good 'ole FOR loop! FOR i% = 1 TO 9 PRINT Person$(i%) NEXT i% This will go thru and print all nine names, in only three lines of code, hoorah! Now, combining what we previously learned with this new knowledge, we'll expand a little on the TYPEs. We'll make them even more useful now. TYPE PlayerType x AS INTEGER y AS INTEGER END TYPE DIM Player(1 TO 2) AS PlayerType Player(1).x = 10 Player(1).y = 20 Player(2).x = 30 Player(2).y = 40 This is especially useful for games where you have perhaps a couple players and the same events happen to them, you can make an array to cut down on the necessary code needed. I find that this is also very useful in games for other things: bullets/missiles, enemy ships, level setup, dialog list, and any time where you might have more than one of something. --- Chapter 13 --------------------------------------------------------------- So you want your program to do something useful, huh? Well, chances are that you are going to want to use some math routines. Most of the math that you do in your program will be used with variables, so keep in mind that WHEREVER there is a number used in a program, it can be replaced with a variable instead (more on this in a second). You already understand assigning values: Num% = 20 We store the value 20 into the variable called Num%. We can now use the variable Num% to represent 20, if we wanted to do this: AnotherNum% = Num% * 2 The value stored in AnotherNum% would be 40, because Num% = 20, and we multiply (*) it by 2 to get 40. Here's a breakdown of the basic math used: Operation Sign Addition + Subtration - Multiplication * Division / To the X power ^ X QBasic will evaluate math on order of operations: Parentheses (innermost first) Exponents Multiplication/division (left to right) Addition/subtraction (left to right) Here are some samples of values that would be returned: 2 + 3 = 5 2 - 10 = -8 2 - -8 = 10 2 * 4 = 8 6 / 3 = 2 2 ^ 8 = 256 2 * (2 - 4) = -4 3 ^ (10 - 7) = 27 3 + (4 - 2) * 10 / ((3 ^ 3) / 9 + 2) = 10 --- Chapter 14 --------------------------------------------------------------- QBasic offers a limited arsenal of sound capabilities. For the good stuff like .WAV, .MID, .VOC, .S3M and all that stuff, you'll find yourself either using a library someone else wrote, or if you want to do it yourself, it will take time, information, and skills. It might not even be written in straight QBasic code if you choose to take the latter route. What QBasic does offer, though, is some "annoying" PC speaker sounds. Some computers now have internal speakers which aren't present anymore these days, or as the case on one of my new computers goes, the sounds are actually routed to the speakers. First off, we have BEEP. To use BEEP, just type BEEP: BEEP The internal PC speaker will make a beep noise (different on many computers). There is also a SOUND command, which takes the parameters for frequency and duration. Most people I know seem to hate this type of sound. So we'll keep this short and sweet. The duration parameter is the number of clock-ticks to play for, and there are 18.2 in a second so we'll make it an even number of 91 (5 seconds). SOUND 400, 91 The frequency must be a number between about 37 and about 32,000. Most speakers I've worked with you cannot hear above a certain frequency (really high-pitched), but it can drive dogs crazy if you get it just right. Last, but not least, is the PLAY command. Nowadays, people don't seem to use these sounds anymore, so I'll also keep this section brief as well. You can find all the documentation you want in the QBasic help- file, so knock yourself out. Use play with a string parameter, with letters to denote notes (A-G), a + or - suffix for sharps or flats, and less than/greater than symbols to move up octaves. Here's an example that will play a scale: PLAY "ABCDEFGFEDCBA" --- Chapter 15 --------------------------------------------------------------- Back to strings. Strings as you learned earlier, are "strings" of letters. Text data. Here are examples of strings: Address$ = "78 Chestnut Grove" City$ = "Sydney" FirstName$ = "George" LuckyNumber$ = "26" Notice that the data is all enclosed within double quotes (""). Also notice that the last one, LuckyNumber$, is a number, however, it's actually a string that happens to contain numbers. You cannot do math operations on a string, so the following code would be NOT work: LuckyNumber$ = "26" OtherNumber% = 2 PRINT LuckyNumber$ * OtherNumber% Okay, let's work a bit with strings. What if you have a string and only want the first 5 letters? Well, use the LEFT$ to return a specified amount of characters from the left side of a specified string, such as this: LongString$ = "There is a lot of text here." PRINT LEFT$(LongString$, 5) That snippet will print out "There" (without the quotes). You could also have stored those 5 characters into another string variable, or the original variable itself (thereby changing the string to just the first 5 characters of itself). You can also replace the 5 in that example with an integer. You probably also might want the right side of the characters for whatever reason. You can use RIGHT$ exactly like LEFT$. LongString$ = "There is a lot of text here." PRINT LEFT$(LongString$, 5) This example will show "here." (without the quotes). What if you want some characters from some IN the string? We have the handy dandy MID$ command available to us. If we wanted to get the word "is" from that string, we'd start on character seven, and read 2 characters, like in the following example: LongString$ = "There is a lot of text here." PRINT MID$$(LongString$, 7, 2) Moving on, there is a great routine called INSTR which tells you if one string is in another string. What if we had a string representing all the cards in a deck, and had a value from the user (a string) and wanted to see if it was in the deck? Check this out: INPUT "Enter your card (2-10, A, J, Q, K): ", Card$ IF INSTR("2345678910AJQK", Card$) THEN PRINT "It's there!" INSTR returned a true value if the search string was present in the initial string. Notice that we had no "checking" on the IF statement this is because it was a "true" statement. Look here: IF 1 THEN PRINT "1 is true" IF 0 THEN PRINT "0 is true" If you run that snippet, you will see "1 is true" but you won't see 0 is true, because it isn't. Similarly, if you said this: IF 2 THEN PRINT "2 is true" It would show "2 is true", because 2 is true. That is to say, it is non-zero, meaning that it isn't false. Lastly for this section on strings, will the be LCASE$ and UCASE$ functions. These are really helpful for checking against responses from the user. Imagine that you asked a person to type the word "yes" in a prompt. Since string checking is case sensitive, they might enter any combination of letters of uppercase and lowercase, thereby making it tiresome to check like this: INPUT "Type in yes to go on: ", Prompt$ IF Prompt$ = "yes" THEN (do code) IF Prompt$ = "Yes" THEN (do code) IF Prompt$ = "YES" THEN (do code) IF Prompt$ = "yEs" THEN (do code) IF Prompt$ = "yeS" THEN (do code) IF Prompt$ = "YEs" THEN (do code) IF Prompt$ = "YeS" THEN (do code) And so forth. What if we did a check only against one type of the input? We can see what a string looks like in all lowercase letters. Observe: FirstName$ = "Dave" PRINT FirstName$ PRINT LCASE$(FirstName$) The name shows itself normally, and then in all lowercase. This can make our lives much simpler, let's rewrite that previous example: INPUT "Type in yes to go on: ", Prompt$ IF LCASE$(Prompt$) = "yes" THEN (do code) Similarly, we could also choose from UCASE$ as well, for uppercases: FirstName$ = "Dave" PRINT FirstName$ PRINT UCASE$(FirstName$) This snippet will show "Dave" and then "DAVE". --- Chapter 16 --------------------------------------------------------------- QBasic can do many math operations beyond operations. It has several keywords dedicated to returning values. For the absolute value of a number, there is ABS. If you don't know, the absolute value of a number is it's distance from 0, so therefore the absolute value of 10 = 10, and -10 = 10. INPUT "Enter your negative age: ", Age% PRINT "You are"; ABS(Age%); "years old!" Then we have SGN, or the sign of a number. If a number is negative, it's sign is -1, if it's 0 the sign is 0, and if the number is positive, then the sign is 1: PRINT SGN(-1204) PRINT SGN(-2) PRINT SGN(0) PRINT SGN(10) PRINT SGN(3242) That snippet will print out the following sequence: -1, -1, 0, 1, 1. Also, we have COS, SIN, TAN, and ATN. COS returns the cosine of an angle in radians, SIN returns the sine, TAN returns the tangent, and ATN returns the arctangent. If you are a math buff, then all this stuff might be useful, but for the purposes of this chapter, now that you know it, let's move on. --- Chapter 17 --------------------------------------------------------------- Do it yourself: input from the keyboard. More often than not I have someone emailing me asking me how to get user input, without having to use INPUT (the downside of INPUT, for these reasons, being that it must have all data followed by the user pressing to enter the data and go on). QBasic supplies us with a fairly handly little routine, INKEY$. INKEY$ returns keys from the keyboard buffer, as they are being pushed. INKEY$ is most useful in a loop to continously track input, as well as a SELECT CASE for deciding what to do, based off of that input. An example should clear this up in a program snippet where you press "q" or "Q" to exit. DO SELECT CASE INKEY$ CASE "Q", "q" END CASE "A", "a" PRINT "You pressed A!" END SELECT LOOP This is probably all you need to know for now, but here are some sidenotes: typically the INKEY$ loop may have a long set of actions for a key, or whatever. there may be some delays which could cause you to lose the data of the keyboard buffer. For this reason, I usually put the INKEY$ value into a variable called kbd$, but it can be named anything, really. Then I SELECT CASE on the kbd$, and go from there. Remembering how the LCASE$ command worked, we could have just checked against one value on the SELECT CASE CASEs, like this: DO kbd$ = INKEY$ SELECT CASE LCASE$(kbd$) CASE "q" END CASE "a" PRINT "You pressed A or a!" END SELECT LOOP See the next chapter for a little more info regarding using INKEY$. --- Chapter 18 --------------------------------------------------------------- This small chapter will go over INKEY$ concerning one of the larger questions I see asked, that of "how do I use the arrow keys?" Well, the arrow keys can't be tracked quite like the other keys. You see, an arrow keypress gives INKEY$ 2 bytes, not 1, like other letters would. So we prefix it with a CHR$(0) and track as usual. To find the code for the arrow key, you can go into the QBasic helpfile and find the keyboard scancodes section. Then get the scancode for the arrow key or other key, that you want. Let's say we are looking for the upwards directional arrow key, the scancode is 72. This would suffice in itself, but we can use that scancode to find the ASCII code for 72, and that would be H (not lowercase h, it is uppercase). Now we can tell if the up arrow has been pressed. Another commonly sought key is the escape key, which happens to be just plain old CHR$(27). PRINT "Press escape to end..." DO kbd$ = INKEY$ SELECT CASE LCASE$(kbd$) CASE CHR$(0) + "H" PRINT "You pressed the up arrow!" CASE CHR$(27) END END SELECT LOOP --- Chapter 19 --------------------------------------------------------------- By now you probably want to store stuff (information, data, whatever) into separate files. This way you can save data and load it back in at a later time. QBasic file handling is quite good if I do say so myself. Available in your arsenal are many commands that deal with opening, reading, writing, and closing files, as well as seeking positions, and different types of files. First we'll be talking about opening up files in simple text modes. To open a file for output (to write information into it), we'll have to use the OUTPUT method or the APPEND method. The OUTPUT method will overwrite an existing file if it exists. APPEND will start adding stuff to the end of an existing file, or create a file if it doesn't exist. When we do open that file, we need to assign it a number that we'll be using to refer to it. Since this is a simple demonstration, we'll just assign it file handle #1. To open: OPEN "test.txt" FOR APPEND AS #1 This will create test.txt if it doesn't exist, and if it does exist it'll open it and put the current write position at the end of the file. From here on we have a couple of ways to put data in the file. First off we can have nice neat little "form fields" using the WRITE command, or as I prefer, using the PRINT command. Note that this is a different variation of the PRINT command, where we'll specify a file number to "print" the text to. PRINT #1, "This file now contains some text!" If we are done with the file, then we will close it: CLOSE #1 This is simple stuff, so far. Let's try making a simple "logbook" program. We'll use the TIME$ and DATE$ functions to return the current time and date to put in each entry: OPEN "logbook.txt" FOR APPEND AS #1 PRINT #1, TIME$, DATE$ LINE INPUT "Enter your thoughts for the day:", Thoughts$ PRINT #1, Thoughts$ PRINT #1 CLOSE There are a couple things here that you might now be familiar with. I used the LINE INPUT command instead of INPUT because LINE INPUT will accept all the text entered, including commas (which would normally confuse the INPUT command). Next we write the "thoughts" to the end of the file logbook.txt, and then print a blank line, and close the file. Note that CLOSE didn't have any parameters on it; using CLOSE without any file specifications will close all open files (in QBasic). See the next chapter for a quick logbook file-reading example. --- Chapter 20 --------------------------------------------------------------- What if we want the program to retrieve all the lines in the file, show them to the user (you), while letting the user press enter to see each new entry. Not a problem. However, we will be implementing a new command that will tell us when we have reached the end of the file. You see, if you have a file open and try to take input past the end, you get an error. As we all know, errors are bad. Here is the example: OPEN "logbook.txt" FOR INPUT AS #1 DO LINE INPUT #1, TimeDate$ LINE INPUT #1, Thoughts$ INPUT #1, Dummy$ PRINT TimeDate$ PRINT Thoughts$ PRINT INPUT "Press enter to go on.", Dummy$ LOOP WHILE NOT(EOF(1)) CLOSE The loop condition to stop looping basically reads "continue looping while we have NOT reached the end-of-file #1". Everything else should be fairly straightforward --- Chatper 21 --------------------------------------------------------------- The next step in working with files is to learn about the other main type of files: binary. Binary files store information on a more raw level, and might seem somewhat cryptic at times, but they definitely have advantages for many tasks. If you were to store a number in a normal text file, you would store what the number looks like.. in other words, if the number is -2452 then that's what the file would see. However, this means that numbers can range from 1 to 6 digits. But we all know that an integer takes up 2 bytes, no matter how big it is (about -32,000 to +32,000). If we were to store the byte representation of a number, then it'd make a file a lot more linear and with a better compression. We can also store strings, however, you won't get any "compression" there. In fact, you'll need to know more about the string (as in storing an integer with it), if it isn't fixed length. Let's take a look at how we can store the numbers 1 thru 10 in a binary file. OPEN "test.dat" FOR BINARY AS #1 FOR i% = 1 TO 10 PUT #1, , i% NEXT i% CLOSE #1 If you don't see quite what is going on, don't worry. First we are opening the file for binary mode. The other great thing about binary files is that you can read and write to them in the same mode. Not only that, you can set the position that you want to write at. Next we made a FOR loop to go from 1 to 10, and we are using the PUT method to store the variable in the file. Note that we left the space between #1, and i% blank. The parameter that goes there is the byte position to write to. However, by leaving it blank QBasic will put it in the current position and then bump up the position however many bytes is necessary (2 bytes because it was an integer). The following code does the exact same thing as the preceding code: OPEN "test.dat" FOR BINARY AS #1 BytePos% = 1 FOR i% = 1 TO 10 PUT #1, BytePos%, i% BytePos% = BytePos% + 2 NEXT i% CLOSE #1 Similarly, we could have used a simple fuzzy-logic algorithm to determine where to write: OPEN "test.dat" FOR BINARY AS #1 FOR i% = 1 TO 10 PUT #1, i% * 2 - 1, i% NEXT i% CLOSE #1 What if we wanted to get this information back out of the file? Try this: OPEN "test.dat" FOR BINARY AS #1 FOR i% = 1 TO 10 GET #1, , FileValue% PRINT "Value"; i%; "is"; FileValue% NEXT i% CLOSE #1 We'll cover binary files more in detail later, but this should give you the basic information necessary to work and experiment with the files. --- Chapter 22 --------------------------------------------------------------- More great stuff with strings is coming up. Right now we'll focus on pulling a number out of a string, and making a string out of the contents of a number. QBasic provides us with some nifty little commands to get this done: STR$ and VAL. Lastly, we'll also find the length of a string with the LEN function. Let's say we have the user enter a number and it was in a string variable. Well, we might want to perform some calculations with this variable, but as we both know, we can't do calculations on a string, only numbers. By using VAL on a string, it'll return whatever number that it finds, to us. INPUT "Enter a number: ", Number$ NumInt% = VAL(Number$) PRINT "Your number times 2 is:"; NumInt% * 2 Simple. Now on to making a string from a number. This should be self- explanatory, so I'll show how it's done: INPUT "Enter a number: ", Number% NumStr$ = STR$(Number%) PRINT "The number is"; NumStr$ However, there may be spaces on either side of the number (this is because all the numbers have a prefixing space on them to leave room for a - sign). There is an easy way to take them off if you want. We'll use the LTRIM$ and RTRIM$ commands which trim all the spaces off the left or right side of a string variable, respectively. INPUT "Enter a number: ", Number% NumStr$ = LTRIM$(RTRIM$(STR$(Number%))) PRINT "The number is"; NumStr$ From the example above, you can see that the user enters a number which is treated as an integer, then we make a string variable out of it by storing in NumStr$ LTRIM$(RTRIM$(STR$(Number%))). Basically what this means is: "Store in NumStr$ the following expression: the left trimmed value of the right trimmed value of the string value of the number Number%". What if you want to see how many letters are in FirstName$? Use LEN to return the number of letters as an integer: INPUT "Enter your name: ", FirstName$ PRINT "The length of that name is:"; LEN(FirstName$) Keep this knowledge in your back pocket, it comes in handy all the time for many routines. All this may seem confusing, but hey, this is programming after all. --- Chapter 23 --------------------------------------------------------------- Intro to graphics. QBasic has a well-rounded arsenal of simple commands to draw on the screen. Among these, the ability to go into about 10 screen modes, draw primitives, and handle sprites. There are a few main screenmodes that people use: 0 is textmode, which is "default" 7 is a 16 color mode that has built-in page-flipping 9 is 16 color mode with page-flipping, hi-res 12 is a hi-res mode with 16 colors 13 is 320x200 256 color mode. This is by far the best mode available directly to QBasic for games (in my opinion) mainly because by default you have access to 256 colors, and in comparison to other screen modes, it is the least flickery (except when page-flipping in 7). For the purposes of these graphics chapters, we'll be focusing primarily on SCREEN 13, or 13h. To enter the graphics mode, we must use the SCREEN statement followed by which mode to enter. The following code will take us into 13h: SCREEN 13 If we are done with our program and want to go back into text mode, we can use this: SCREEN 0 If you are planning to do more stuff in screen 0, then you will likely need to change the text width (skewed from 13h), by doing the following code: WIDTH 80, 25 This command tells QBasic to setup the text of the screen to be 80 columns by 25 rows. In most screen modes you can change the size of the text with this command. Be sure to check out the QBasic helpfile for information on the screenmodes. --- Chapter 24 --------------------------------------------------------------- Drawing primitives. QBasic has a nice arsenal of command, with a few bells and whistles, with which you can draw to the screen. Among these are the LINE statement for lines, boxes, and filled boxes, PSET for single pixels, CIRCLE for circles, ellipses, and arcs, PAINT to paint areas with a limited and optional pattern, and DRAW, similar to old Logo programs. Note: before using ANY graphics commands, you must be in a graphics mode. For all of these examples, first switch to SCREEN 13 before you do any drawing. For help on coordinates, see the coordinates appendix. To draw a line, we must supply the x and y coordinates of start and end points of the line (or box), and tell the routine whether we want to draw a line (default), box, or filled box. We also supply what color we want the line/box to be. The basic syntax of a LINE is this: LINE (x1, y1)-(x2, y2), Color If we wanted to make a box, it'd be this: LINE (x1, y1)-(x2, y2), Color, B And for a filled box, it'd be this: LINE (x1, y1)-(x2, y2), Color, BF If you haven't assumed it already, (x1, y1) represents the x and y coordinates of the top-left point of the line/box. Respectively, the ordered pair (x2, y2) represents the coordinates of the lower-right point of the line/box. Let's say we wanted to make a simple little program to draw 256 lines on the screen, in 256 colors. Easy. Let's use a FOR loop, because it will work out good that way: SCREEN 13 FOR i% = 0 TO 255 LINE (i%, 0)-(i%, 199), i% NEXT i% This code, as you can see, will draw 256 lines in 256 colors, on the screen, in order. The LINE command also has an optional style attribute. I suggest that for anymore information on any of the graphics commands, that you check out the QBasic helpfile to the last word on whatever it is you want to use. Next, we have PSET. Sequentially, I would have talked about PSET first, but I didn't feel like it. ============================================================================== APPENDIX ============================================================================== --- Tricks of the trade ------------------------------------------------------ This section will show some common examples or tidbits of code that I have seen used extensively, or just code I think is interesting. A. Center text on screen A. Many people wish to center text on the text screen, so they space it over manually with the PRINT routine. This can get tiresome. Why not make a sub to space it over for you, on the row that you want? SUB CenterText (Row%, Text$) LOCATE Row%, 40 - LEN(Text$) / 2 PRINT Text$ END SUB --- FAQ, Q & A --------------------------------------------------------------- Q: Where can I download QuickBASIC 4.5? A: Short answer: it's still copyrighted and illegal to download. However, as with any software, it can be found on the internet with enough looking. So, if you *really* want it, go look for it. However, don't ask me for it. Your email will go straight to my trash can. --- Variables defined -------------------------------------------------------- Variables store information for quick access. Variables in QBasic, as with many other languages, are different depending on what you want them to contain. Among the numeric variables are the common integer, the long integer, and single and double precision variables. To store string (letters) information, we use the string. All variables store their information as a sequence of bits. How many bits that a certain type of variable uses will determine how large of a number it can hold. A bit is the most rudimentary piece of data: it is yes/no, true/ false, 0/1, on/off. Eight bits make up one byte. If an integer is 2 bytes, then that means it has 16 bits. Therefore, you'd think that the maximum value of the variable would be: 2 ^ 16 = 65,536 However, all of the variables in QBasic are signed. What this means is that they can be positive or negative. In order to tell if a number is negative or positive, we use it's last bit (the leftmost bit, if you will), to mark negative or positive. By doing this, we have to sacrifice some of the upward range, so the integer actually has a range of: -32,768 to 32,767 Similarly, there are data types in QBasic called a long integer. The long integer (denoted by the & sign) is 4 bytes. And therefore can hold a range of values of 2 ^ (4 * 8) = 4,294,967,296. But if you'll recall, we share this space among negative and positive so that we have a real range of: -2,147,483,648 to 2,147,483,647 One might think that we should just always use the long integer. Wrong. Long ints have more data, and therefore take more time to calculate with. Moreover, they take up twice as much memory to store! That's about all you need to think about variables for now, so I'll end this section with this brief and succint paragraph. =) --- Coordinates -------------------------------------------------------------- Most of QBasic's graphics commands use coordinates to tell about an area of where to draw to. Every point on the screen has an x location and a y location. The x location is how many pixels from the left that a pixel appears. The y location is how many pixels from the top (of the screen) that a pixel appears. In plain English, a pixel is smallest representable thing on a display: a single dot. If we are in 13h, then the screen resolution is 320x200 pixels. The coordinates of the first pixel are (0, 0), and the coordinates of the last pixel are (319, 199). In an ordered pair of coordinates, the x position always comes first: (x, y) This information should be sufficient to familiarize you with the basic workings of the screen. --- Common algorithms -------------------------------------------------------- Distance algorithm between 2 points of (x1, y2)-(x2, y2): Distance = SQRT((x2-x1) ^ 2 + (y2 - y1) ^ 2) --- Programming humor -------------------------------------------------------- The only thing funny about this section is that I haven't taken the time to put something in it. =) --- Glossary/buzzwords ------------------------------------------------------- ASM Assembly, such as assembly language, the lowest and most primitive (therefore powerful) computer language C Popular computer language, generally "stronger" than QBasic QB Shorthand for QBasic or QuickBASIC BASIC Beginner's All-purpose Symbolic Instruction Code PDS Professional Development System VBDOS Visual Basic for DOS (Visual Basic 1.0) DOS Disk Operating System (DOS is typically interchangeable with MS-DOS) --- Books -------------------------------------------------------------------- There are some books that will help you in QBasic programming (if you don't like my own little "book", that is). I won't go into a lot of detail, but the following books I've noted are the most popular among QBasicers: The Revolutionary Guide to QBasic, Wrox Press Contains many insightful examples into programming, and seems to cover more aspects of making a program than most other books. QBasic by Example, Que The title says it all: covers most commands in QBasic showing examples on how to use them. --- Websites/email ----------------------------------------------------------- The following sites are full of files, links, help, tutorials, and more content that will aid you on your programming of QBasic and of programming in general: Jason Jones (Tek/Tekky), neozones@quickbasic.com, http://neozones.quickbasic.com/ Jordan Day (Hal_8900), dayzed@ponyexpress.net, http://alternatelogic.quickbasic.com/ --- Greets ------------------------------------------------------------------- Greets go out to the following people (in no particular order): Class Necrolyte HAL_8900 ChUcK E-Rage Pasco 19day Angelo Mottola Michael Hoopman EvilGeek Marcade Nekrophidius Pete Rems zkman Wafn Syn9 SonicBlue .. and whoever else I forgot to mention! --- Release notes, history --------------------------------------------------- 06.15.1999 Began writing this document 06.16.1999 Five more chapters 06.17.1999 Laid out rest of chapters so far, appendices, and wrote some more chapters 06.20.1999 Wrote three more chapters and working on appendix section 07.16.1999 Uploaded version thus far to NeoZones -*-