---------------------------------------------------------
The Liberty Basic Newsletter - Issue #39 - JUN 99
"Knowledge is a gift we receive from others."
		- Michael T. Rankin
---------------------------------------------------------
In This Issue:
Using Arrays with For-Next Loops:
	A Sample Program


In Future Issues:

Programmer's Spotlight - on Carl Courtney
Binary Search - by Ian Davies
---------------------------------------------------------

Using Arrays with For-Next Loops:
	A Sample Program



Please download the sample source code and associated
files at:  http://alyce.webjump.com/fishsim.zip

This little program is a simple aquarium simulation.  The
methods used within the program can be applied to any type
of application, not just a graphics-oriented program.


---------------------------------------------------------
1.  LAY OUT
The layout of this program is done according to Brosco's 
teachings.  First of all, it makes use of white space to
make the source code more readable.  Branch labels appear
at the margins, but most other code is indented.  There
are blank lines between routines.

Secondly, branch labels and variables are named according
to their functions.  This cuts down on the need for
comments.  For instance, the number of Fish is held in a 
variable called numberFish.  There is no doubt about the
use of that variable!  In the olden days of programming,
everything was kept as small as possible because of
severe restrictions on usable memory.  We really don't
need to concern ourselves with this limitation any more,
so feel free to use descriptive names.

Third, the source IS commented so that others can 
understand it, and the author can return to it after some
time has passed and still understand it.  (We ALL forget!)
Try this experiment sometime:  take a heavily commented
BAS file and tokenize it.  Then compare the number of KB
in each.  You will see that the TKN is a smaller file.  
The comments are ignored in the tokenizing process, so you
needn't worry that comments will make your code too large.

Fourth, routines are kept small enough to be contained on
one screen for editing.  It is far too confusing to scroll
up and down and back and forth through a routine!  You 
will soon lose the sense of it!  It is possible, and even
preferable to make extensive use of GOSUBS.  And, of course
the subroutines themselves should be kept to a reasonable
length.  Remember that you can call a subroutine from
within a subroutine!  By putting often-used routines into
subroutines to be called with GOSUB, you are streamlining
your code and making it much easier to read AND debug.
Here is the opening section, from just after the program
window is opened, until the main input loop is reached:

    GOSUB [load]
    GOSUB [init]
    GOSUB [sim.setup]

And here is the main input loop:

[loop]
    print #1, "setfocus; when characterInput [quit]"
    print #1, "when mouseMove [quit]"  'stop program at keystroke or mouse move
    scan
    GOSUB [move]
    GOSUB [draw.screen]

    if Count<1500 then
        for i = 1 to pause: next i  'generate a delay on fast cpu's
    end if
    goto [loop]

THAT's ALL!  Notice that it is a small routine, uses white 
space at the margins and between parts of the routine, it
makes use of GOSUBs, which are named to suit their functions,
and it is commented.

---------------------------------------------------------
2.  FOR-NEXT LOOP: AN EASY ONE

Here is the subroutine that draws the screen.  The window
is filled by tiling a bitmap that is 200x200 in a nested
loop:

[init] 'initialize dll and draw water background
    for x=0 to 1200 step 200
      for y=0 to 1000 step 200
        print #1, "drawbmp water ";x;" ";y
      next y
    next x

    open "lbsprite.dll" for dll as #s
    'load background from screen:
    CallDll #s, "Init",h as short, r as short
    RETURN

The bitmap, called 'water' was loaded in the [load]
routine.  Rather than make several calls to draw the
bitmap across the width and height of the screen, the
command is put within a FOR-NEXT LOOP which increments
by 200 each time for the x and y placement, since 200
is the width and height of the bitmap.  If the bitmap
were 300 wide, then that loop would say STEP 300 instead.

---------------------------------------------------------
3.  EASY - FILLING AN ARRAY WITH A FOR-NEXT LOOP:

At the very top of the source code, the numberFish variable
is set and the fishes( array is dimensioned:

    numberFish=5  'pick 1-10 here.  Slower pc's should choose fewer fish
    DIM fishes(10,5)

Since the array can contain a maximum of 10 fish, according
to our command to dimension it, we must trap the possibility
of setting numberFish too high.  It is also a good idea to
make sure that the minimum value of numberFish is at least 1:

[sim.setup]
    if numberFish>10 then numberFish=10  'trap error - too many fish
    if numberFish<1 then numberFish=1    'trap error - no fish

The fishes( array is double-dimensioned.  That means that each
index in the first dimension is associated with (in our case)
5 elements in the second dimension.  For each fish, the element
fishes(i,1) will contain its x-location.  The element fishes(i,2)
will hold its current y-location.  Because we are keeping these
variables in an array, it only takes a few lines of code to set
the initial x, y location of all of our fish:

    'x,y location to start each fish:
    for i=1 to numberFish
        fishes(i,1)=int(rnd(1)*600)  'x location
        fishes(i,2)=int(rnd(1)*380)  'y location
    next i

This routine will start with fishes(1,1) and pick a random
x location that does not exceed 600, then it will pick a
random y location that does not exceed 380.  After finishing
the first fish, it moves on to fishes(2,1) and fishes(2,2), 
setting the x, y location for the second fish.  It continues
until it reaches the maximum value set by numberFish.


---------------------------------------------------------
4.  A DIFFERENT METHOD OF FILLING AN ARRAY WITH A
	FOR-NEXT LOOP:

In the [load] routine, we loaded the bitmaps of the five
fishes, and got their handles:

    loadbmp "f1", "fish1.bmp"
    hf1=hbmp("f1")
    loadbmp "f2", "fish2.bmp"
    hf2=hbmp("f2")
    loadbmp "f3", "fish3.bmp"
    hf3=hbmp("f3")
    loadbmp "f4", "fish4.bmp"
    hf4=hbmp("f4")
    loadbmp "f5", "fish5.bmp"
    hf5=hbmp("f5")

Since there are five different handles to assign, it might
seem that this is not a job for a FOR-NEXT LOOP, but it is!

    for i=1 to numberFish STEP 5
        if i<=numberFish then fishes(i,3)=hf1
        if i+1<=numberFish then fishes(i+1,3)=hf2
        if i+2<=numberFish then fishes(i+2,3)=hf3
        if i+3<=numberFish then fishes(i+3,3)=hf4
        if i+4<=numberFish then fishes(i+4,3)=hf5
    next i

This same few lines of code will assign a bitmap handle to
as many fish as there are in numberFish.  Since there are
five bitmaps in use, STEP 5 is set as the increment.  Then,
notice that the counter variable, i, is used within the 
loop.  The first index is i, the second is i+1, the third
is i+2 and so on.  You must also be sure that i+? is no
larger than the DIM of the fishes( array, with
a conditional statement like the following example:
 
if i+2<numberFish then fishes(i+2,3)=hf2

---------------------------------------------------------
5.  EVEN MORE CUTE TRICKS TO FILL ARRAYS:

As the fish swim about in their aquarium, they should
move up and down a bit, as well as across the screen.
(Think about it - fish don't swim in the same straight
line, back and forth!)  We can easily add variation to
the movement of our fish by assigning the increment of
change in Y direction to be the index of the fish.
Fish 1 will move 1 pixel in Y each frame, while fish 2
moves 2 pixels in Y each frame and fish 3 moves 3 pixels
in the Y direction for each frame of animation.  This 
works for us because we won't have too many fish.  An
aquarium with 50 fish would need another method, or fish
#50 would move in huge jerks of 50 pixels Y each time!

	fish(i,5) will be the change in y value:

    'set y-speed
    for i=1 to numberFish
        fishes(i,5)=i
    next i


Most of the movement of the fish will be in the x-direction.
This value will be contained in the array fishes(i,4).
They will certainly move more than one pixel at a time!
We'll choose 2 possible speeds for our fish:  10 and 14.
Half of the fish will move ten pixels in the x-direction
for each frame of animation, and the other half will move
14 pixels.  We'll make the first half of the fish the 
'slow' fish.  The value for half of the fish would be
numberFish/2.  Since we cannot use just half of one fish,
should numberFish be an odd number, we'll use LB's INT to
trap that error:

    for i=1 to int(numberFish/2)
        fishes(i,4)=10   'speed of first half of fish
    next i

Now, we'll set the x increment for the second half of
the fish.  To count the upper half, we add one to the
number we found for the last fish in the first half, or
(int(numberFish/2) +1):

    for i = (int(numberFish/2) +1) to numberFish
        fishes(i,4)=14  'speed of last half of fish
    next i

The code so far is fine (as far as it goes) in setting
up the simulation.  Let's picture it:  we start our
aquarium simulation and our fish begin swimming.  Wait
a minute!  The are all swimming to the right and downward!
That's not very realistic!  We'll need to change the
x-increment and the y-increment to a negative number in
half of our fish.  A handy way to express the opposite of
ANY number is to write it as: 0 - number.  In just that 
way, we can change the x-direction to moving left in
some of the fish with this expression:
fishes(i,4)=0-fishes(i,4)
Let's add as much variability as we can and do it by
STEP 2 in the x-direction:

    'change direction of half of fish:
    for i=1 to numberFish STEP 2
        fishes(i,4)=0-fishes(i,4)
    next i

Again, to add a more natural look to the aquarium, lets
change DIFFERENT fish so that they are traveling in a
negative y-direction.  The code is almost identical to
the previous routine, but instead of starting at index
i=1, we'll START with the second fish, i=2:

    for i=2 to numberFish STEP 2
        fishes(i,5)=0-fishes(i,5)
    next i

---------------------------------------------------------
6.  MOVING THOSE FISH WITH FOR-NEXT LOOPS:

Now we will see the advantage of holding our fish values
in arrays!  If we did not, we would need to perform the
following routine once for EACH fish, for EACH frame of
animation!  Remember that fishes(i,1) holds the x-position
and fishes(i,4) holds the amount of change in x for this
particular fish with each frame.  Easy!  All we need is 
the following routine within a FOR-NEXT LOOP to move all 
of our fish:

fishes(i,1)=fishes(i,1)+fishes(i,4)

NOPE!  Close, though.  We also need to make a check to 
see if the fish is about to go off of the screen on
the right or left side.  If the fish is about to exit,
we need to keep him on screen AND modify the value for
change in x for the next frame.  Remember, earlier we
changed the value of some elements by subtracting from
0.  That method will work here also.  A negative number
will become positive when subtracted from 0, just as a
positive number will become negative.  In other words,
subtraction from 0 serves to change the SIGN of the
number.  So, a fish who gets to the left side of the
screen has had a negative value in fishes(i,4) which
we will now change to a positive value, so he swims
towards the right.  We'll need a separate conditional
statment to trap the left and right sides of the
screen:

    for i=1 to numberFish
        fishes(i,1)=fishes(i,1)+fishes(i,4)
            if fishes(i,1)<0 then
                fishes(i,4)=0-fishes(i,4)   'reverse direction
                fishes(i,1)=0
            end if

            if fishes(i,1)>(DisplayWidth-100) then
                fishes(i,4)=0-fishes(i,4)    'reverse direction
                fishes(i,1)=(DisplayWidth-100)
            end if
    next i


And, OF COURSE, it works exactly the same way in the
y-direction:

    for i=1 to numberFish
        fishes(i,2)=fishes(i,2)+fishes(i,5)
            if fishes(i,2)<0 then
                fishes(i,5)=0-fishes(i,5)    'reverse direction
                fishes(i,2)=0
            end if

            if fishes(i,2)>(DisplayHeight-40) then
                fishes(i,5)=0-fishes(i,5)     'reverse direction
                fishes(i,2)=(DisplayHeight-40)
            end if
    next i


---------------------------------------------------------
7.  YET ANOTHER USE OF FOR-NEXT LOOPS IN THIS PROGRAM:

We have now determined WHERE each fish should be for the
next frame of animation, so all that is left is to actually
draw the fish.

To do the drawing, we'll set the variable xfish equal to
fishes(i,1), the variable yfish will equal fishes(i,2) and
the variable for the proper bitmap handle, hFish will be
set to fishes(i,3).  We can now make the call to draw the 
fish, but we need to know which direction he is facing, so
we know whether the call should be to DrawSprite, or to
DrawSpriteMirror.  Since fishes(i,4) contains the x-
increment, we'll check that.  If it is positive (more than
zero) then we'll need to call DrawSprite, but if it is
negative (less than zero) then he is heading in the other
direction and we will need to DrawSpriteMirror.  Here
is the entire routine:

[draw.screen]
    for i=1 to numberFish
        hFish=fishes(i,3)  'proper bmp for this fish
        xfish=fishes(i,1)  'current x location for this fish
        yfish=fishes(i,2)  'current y location for this fish
        if fishes(i,4)>0 then
            CallDll #s, "DrawSprite",h as short, hFish as short,_
		 xfish as short, yfish as short,r as short
          else
            CallDll #s, "DrawSpriteMirror",h as short, hFish as short,_
		 xfish as short, yfish as short,r as short
        end if
     next i


    CallDll #s, "UpdateScreen",h as short, r as short,
    RETURN


---------------------------------------------------------
8.  TOM'S TURN

Whenever Tom sees his mom writing an interesting bit of
code, he can't help but elbow her out of the way, so he
can modify it.  (Or, as he says, 'Do it the RIGHT way!'
The shark.bas program in the packet is his version, and
yes - you guessed it - he has added a shark to the tank,
with predictable consequences!

He has made further use of FOR-NEXT LOOPS in his routine
and you might want to check out his gradiant fill for
the water in the aquarium.

Tom also suggests that there are many other modifications
that could be made to these simulations.  If anyone does
write a variation, why not post it (just the code!) here
on the lbnews list?  Thanks.

---------------------------------------------------------
 Newsletter compiled and edited by: Brosco and Alyce.
 Comments, requests or corrections: Hit 'REPLY' now!
            mailto:brosco@orac.net.au
                       or
           mailto:awatson@mail.wctc.net
---------------------------------------------------------