So there it is - the challenge. As indicated, this program will leverage our understanding of two dimensional arrays. We discussed those toward the close of the last installment of this series. By way of review, lets just examine these again briefly. At the heart of most games, puzzles and simulations is the array. We have been using single dimension arrays since the second installment. We easily recognize these as they appear as variables that have a single subscript following the variable name:
In the example above we have the array "Toys" and we are specifying the 15th element. There are presumably at least 14 other elements in this array, maybe more. We know that each of the elements are unique and hold their own unique values, yet all or the elements are related (they are sequential in memory) and have the same properties. Specifically they belong to the "Toys" array and are numeric.
We have seen that we use a DIM statement to DIMension an array prior to use. This will cause Liberty Basic to set aside a contiguous block of memory for the array to be stored in. Failure to DIMension an array before use will cause an error. If the "Toys" array were actually 20 element in size, we would DIMension it with the following statement:
The array "Toys" is called a single dimension array. It represents a series of data elements laid out in a sequential row. We would imagine this row being horizontal, like the row of mailboxes which we have been using as our analogy (see installments 2 and 3 for more about single dimension arrays). When we last discussed arrays we added another dimension to our array. It is like having a row of mail cubes (like post office boxes) that runs across and up, such as in the example below:
In the programming world two dimensional arrays do not start at one and go to 32 as in the picture. Instead the numbering travels in two directions along two axis. You can imagine it as navigators use a map. There is an axis in a vertical direction (up and down) and one in the horizontal direction (left and right). Such as in the image below:
In this case the elements are numbered (in columns) from point of origin going left to right from 1 to just short of infinity (if you care to go that far). Rows of data are also numbered from 1 going up. (Technically speaking Liberty Basic uses both Zero Based Arrays and One Based Arrays. For now we will not worry about that.) Here is a graphic showing the column and row numbering of a two dimensional array.
As you can see in the graphic the vertical axis has been named 'X' and the horizontal axis has been named 'Y'. These are arbitrary names which are common in programming. The value of any single element in the two dimensional array is accessed by referring to it using the 'X' and 'Y' values in combination. Consider the following:
In this image we are referencing the element at X=4 and Y=3. We have assumed this array is called Starmap (in preparation for the development of our game). This array was DIMensioned in Liberty Basic using the following statement:
All two dimensional arrays must be declared. This creates the memory space for the storage of the array. Above we are accessing a specific element in the array. We could assign its value to another variable, change its value or utilize it in any number of ways, just as we would any regular run-of-the-mill variable. To assign its value to the variable "A" using Liberty Basic we would write the following statement:
A = Starmap(4,3)
We could also use variable as our subscript values as in the following example:
X = 4 Y = 3 A = Starmap(X,Y)
So how do we get from here to our starmap? Well the starmap is simply a string array that is eight elements in the 'X' direction and 12 elements in the 'Y' direction. We have thrown a little wrinkle into the display of the array by showing element (1,1) in the upper left corner rather than in the lower right corner, but lets not worry about that yet. Let us concentrate on creating and populating the array first.
Before we begin our program, lets document what we are doing:
'StarMap - by Brad Moore 'public domain, 2003 'for Liberty Basic 3.x
Now we will dimension the array and reserve memory for it at the same time.
Now we can use a simple nested FOR-NEXT loop (these are discussed in installment 4 of the series) to set every element of the array to a period character ".".
for x = 1 to 8 for y = 1 to 12 starmap$(x,y) = "." next y next x
Now we have 96 elements of an array that are populated with a period. We need to change a few of these to a different character. We can do this by simply setting the specific element to the desired character. We know that the character in element 1,1 should be an at sign "@", this is our spaceship. We can set this using the following statement:
starmap$(1,1) = "@"
Likewise, we can construct the gate which is a simple box of asterisks on the oppisite side of the starfield from the spaceship. The following statements will do this:
starmap$(7,11) = "*" starmap$(7,12) = "*" starmap$(8,11) = "*" starmap$(8,12) = ""
Notice that we also set element 8,12 to an empty string. This is actual portal that we will move our spaceship to. Before we get into the mechanics of the game though, lets see how to print this out with coordinate locations across the top and side.
You will notice that we have been talking about arrays starting with 1,1 in the lower left corner, but our starmap is printed out with the 1,1 element in the upper left corner. We have flipped the array. The actual orientation is really arbitrary. It does not make a lot if difference which way you portray your array provided you remain consistent with in your program.
In order to get the coordinates across the top I have chosen to use a FOR-NEXT loop. It is incremented from 1 to 12. I have used some fancy string manipulation to insure that the spacing of the coordinate values stays consistent. Here is the code:
print " "; for x = 1 to 12 a$ = right$("00" + str$(x),2) + " " print a$; next x
The first PRINT statement spaces the output so that things will line up vertically when we print out the array values and the 'X' coordinates. There is a FOR-NEXT loop I discussed and then the fancy string manipulation. This is how it works:
Converts the numeric value of 'x' (our loop counter for the FOR-NEXT loop) to a string. Lets say 'x' is really "7" now.
"00" + str$(x)
This actually equates to:
"00" + "7"
Which is equal to "007" (kind of like James Bond!). We want a two character string only, but this will produce a three character and sometimes a four character string depending on the value of 'x'.
right$("00" + str$(x),2)
Actually equates to:
Which chops off the two right most characters and discards any additional characters. That means that the statement above actually equates to:
Finally we add a simple space to all of that, on the right - I will show you:
right$("00" + str$(x),2) + " "
"07" + " "
Which of course is:
So why have we done this? Well we want to space our output of the array out so that each element is padded on either side by two spaces. Something like:
space, value, space, space, value, space, space, value, etc...
As you can see, on either side of the value there is one unshared space. Adding the two unshared spaces and the single value we come up with three characters. So each of the coordinate display values must be exactly three spaces long to line up correctly with the array that will be displayed below it. Some values are a single character in length (numbers 1 to 9) and then a few are two characters long. For consistency I have decided all numbers will be two characters long and the single digit values will be padded with a zero. That is what we have done above. Padded the single character values with a zero, then added the extra space to get our three characters.
Our display should now look something like:
01 02 03 04 05 06 07 08 09 10 11 12
Now we need to print the vertical coordinate values AND the contents of the array at the same time. We can not do these in separate steps, as we only get one pass at any given line of text. (Liberty Basic 3.02 introduced a new command called LOCATE that acts like the LOCATE command in QBasic and can overcome this problem, but we will not be visiting it at this time.) Luckily it is very easy to do this. We will use a nested loop, and simply print the loop counter value for the outer level loop BEFORE executing the inner level. Here is the code:
for x = 1 to 8 print x;" "; for y = 1 to 12 print " ";starmap$(x,y);" "; next y print next x
Note that we have padded each element of the starmap$ array as we printed it with both a leading space and a trailing space. Notice also the use of the semi-colons in the print statement. They are all important. Remember that these cause the next thing printed to be printed to the same line immediately following the last thing printed. We print a space, the value of the array element and then a space and then the last semi-colon gets us ready to print the next space, element, space. The other item that is important is the simple PRINT statement that follows the "next y" statement. This breaks the chain of text following text on the same line because it does not have a semi-colon following it.
Now one more print statement for spacing and we are done:
Here is the complete program, included here for your convenience:
'StarMap - by Brad Moore 'public domain, 2003 'for Liberty Basic 3.x dim starmap$(8,12) for x = 1 to 8 for y = 1 to 12 starmap$(x,y) = "." next y next x starmap$(1,1) = "@" starmap$(7,11) = "*" starmap$(7,12) = "*" starmap$(8,11) = "*" starmap$(8,12) = "" print " "; for x = 1 to 12 a$ = right$("00" + str$(x),2) + " " print a$; next x print for x = 1 to 8 print x;" "; for y = 1 to 12 print " ";starmap$(x,y);" "; next y print next x print