R.T.Russell Home Page

Chapter 15 - Grouping Data in Structures




Arrays are a great way to organize data. In your programs you will come across numerous uses for them. Eventually, you may happen upon a situation like the following. Suppose you are writing a killer game. The player has several variables associated with him: x-coordinate, y-coordinate, number of lives and name. You could easily define several variables like this:
PlayerX%=5
PlayerY%=12
PlayerLives%=3
PlayerName$="GR8"
Or you could use an array for the first three variables and make a mental note that index 1 refers to x position, 2 to y position and 3 to lives. PlayerName is a problem and would have to remain an individual string.

BBC BASIC offers the ability to create your own 'super' variable which will group all these individual variables together in one place and hence make them easier to keep track of. This device is called a structure as you probably guessed from the title of this section. To declare a structure, you use DIM, like an array but with curly brackets (braces) instead of the normal round ones so BASIC knows that we're talking about a structure. Within the braces go the names of the variables that we wish to include in that group. Usual naming rules apply. Let's see an example:

DIM Player{X%,Y%,Lives%,Name$}
We can access and use any of the variables and do all the normal things with them. The structure only acts as a grouping mechanism. Access is done by using the name of structure (Player in our case) followed by a dot and the name of the variable we want. To change the number of lives when a player gets hit, we would do this:
Player.Lives%=Player.Lives%-1
IF Player.Lives%<=0 THEN PRINT "GAME OVER"

The official jargon here is:
StructureName.MemberName
So now you can declare nice little units to hold all your variables in logical groups. But there's more. You knew I was going to say that, didn't you? The members of a structure are not limited to single variables. You can have an array as a member of a structure. Suppose your player could have up to 10 items of equipment: underwater flame thrower, anti-gravity boots etc. You need a way to represent whether he's picked up each of these items. Let's have an array called Item%. This is how we would declare the structure now:
DIM Player{X%,Y%,Lives%,Name$, Item%(10)}
Access is just as before:
IF Player.Item%(5)=TRUE THEN
  PRINT "You have the 1000 league boots"
ENDIF
Similarly, you can have another structure as a member of the structure. For example, it is common practice to make a structure to hold the X and Y coordinates. You do it like this:
DIM Player{Posn{X%,Y%},Lives%, \
\          Name$, Item%(10)}
Posn (for position) is referred to as a substructure and accesses to its components are like this:
Player.Posn.X% = Player.Posn.X% + 5
Substructures can contain other substructures, arrays and variables in any combination. The idea here, of course, is to divide the data up into logical, easy to manipulate groups, not to show how clever you are by nesting 10 levels of data inside 10 levels of data.

Arrays of Structures

When our player has reached the end of the game, victorious and covered in gore, we would like to add a high score table so he can brag to his friends. The table will consist of the top 10 scores. By now, it should be apparent how this is done:

DIM Table{Name$,Score%}
Great, but that only takes care of the top position, we want a table. This is how we declare an array of structures:
DIM Table{(10) Name$,Score%}
The first item in the variable list is the number of elements in round brackets (parentheses). This will give us an array called Table with 11 structures 0 to 10. To print out the contents of the high score table, we access the array like this:
FOR I% = 1 TO 10
  PRINT I%,Table{(I%)}.Name$;
  PRINT Table{(I%)}.Score%
NEXT I%
You need to wrap the array index in braces to tell BASIC you're working with a structure. As with normal arrays, multi-dimensional arrays are allowed and the same rule about numbering from element zero applies.

Prototype Structures

Back in our hypothetical game we have a structure to hold the aliens: current position, health points etc. At the end of the level there is the tough-as-old-boots-end-of-level boss that you have to defeat before winning through to the next level. This chap has the same attributes as an ordinary alien, but it doesn't really make sense to include him with the rank and file. We need to create another structure for him which has the same attributes as his underlings, but is kept separate so we can deal with him as a unique case. BBC BASIC allows us to use an already defined structure as the template or prototype for another one.

REM Prototype structures
DIM Alien{XPosn%, YPosn%, Health%}
 
REM Setup our alien
Alien.XPosn%=50
Alien.YPosn%=627
Alien.Health%=100
 
DIM BigBadBoss{}=Alien{}
REM Let's play ...
BigBadBoss will now have the members:
BigBadBoss.XPosn%
BigBadBoss.YPosn%
BigBadBoss.Health%
Don't get confused here. At the point when the structure is declared, all the members of BigBadBoss will be set to zero, it is only the names of the structure members that are copied over, not their actual values.

Using this technique, it is also possible to declare an array of the specified structure.

REM Arrays of prototype structures
DIM Alien{XPosn%, YPosn%, Health%}
 
REM Declare a full level of aliens
DIM LotsOfAliens{(20)}=Alien{}
LotsOfAliens{(0)}.XPosn%=50
LotsOfAliens{(0)}.YPosn%=627
LotsOfAliens{(0)}.Health%=100
 
REM ...
Line 5 gives us 21 (0 to 20) of the little blighters ripe for decimation.

In one of the previous sections, we had a player structure which had a position structure nested within it. This technique can be applied to prototypes as well. As an example, we can define the position of our alien using XPosn% and YPosn%, but we could make this a structure too. That way each time we had something that needed a position, the prototype would give it to us ready-made. This is useful, because it means we are always able to access the position in the same manner, wherever it is found. This is how we would do that:

REM Nested prototype structures
DIM Position{X%,Y%}
DIM Alien{Posn{}=Position{}, Health%}
DIM Player{Posn{}=Position{}, \
\          Lives%, Name$, Item%(10)}
      
REM Initialize our alien
Alien.Posn.X%=50
Alien.Posn.Y%=627
Alien.Health%=100
      
REM Initialize our player
Player.Posn.X%=50
Player.Posn.Y%=627
Player.Lives%=100
      
REM ...
Any changes made to the Position structure after the initial coding would instantly be reflected in the changes to the structures that use Position as a prototype. This is good and bad. If the game was to be expanded into three dimensions, we would redeclare like this:
DIM Position{X%,Y%,Z%}
and presto, both Alien and Player now have another dimension to play in. (You still have to write the code to handle that yourself. BBC BASIC isn't THAT clever.) The point to be wary of is going the other way, if you remove an element, you must also remove every reference to it in every structure that contains it. Think about the layout of your data before implementing it, this way you save hours of frustration and rework.

Obviously, these techniques come into their own when using larger structures, but don't ever lose sight of the fact that they are merely ways of collecting similar data together so it's all accessible from the same place. Once you get the hang of structures, you'll wonder how you ever managed without them.

Tip:  Structure names and abbreviated keywords
BBC BASIC allows the use of abbreviated names for most keywords and commands. These can be found under the entries for each word in the help files. As an example PRINT can be shortened to 'P.' - see the problem? If you declare a structure called P, when you try and access its members, BASIC will expand a line like 'P.Int1%=2' into 'PRINTInt1%=2' which is definitely not what you wanted. Single letter names don't fall into our book of good programming practices anyway.

The easiest way around this problem is to use meaningful names that have mixed case. It is possible to turn the abbreviated names on and off: from the menu choose Options | Customize then untick the box in the Program Editor group. The problem with this is that the option is on by default, so if you give your code to anyone else, they would have a problem and, because they are not as clever as you, wouldn't know what had happened.

If you read the help files, it's possible to do wonders with structures, but this introduction will suffice for many a while to come.

Exercises

1) If you wanted to store a pupil's grades for five subjects along with their first name and surname, can you suggest a structure that would do this?
2) Write a program that declares such a structure and prompts for the information. Calculate the average grade and print the results.
3) If you had 20 pupils in a class, how would you make an array of the above structure?

Left CONTENTS

CHAPTER 16 Right


Best viewed with Any Browser Valid HTML 4.0!
© Peter Nairn 2006