     *********** Star Trek in Just BASIC v0.1 ************

This file has two sections
1) Programming notes
2) Final comments


     ****************  Programming Notes  ****************

First off, a confession.  Although this game is the most played, 
copied, modified, shared, recoded, enhanced, blah blah blah ... 
program in the history of type-in-and-play games, I barely played 
it when it was wildly popular.  I don't know why, because I 
enjoyed the TV show a ton.  So i'm coming into this not really 
knowing the code, and vaguely remembering what the game was like.
For this, it didn't matter because anything i'd known about the 
progran had been long forgetten.  

My standard way of beginning a project of this type is to make 
a "0" copy of the file - "startrek.bas" becomes "startrek0.bas" 
and is NEVER editted.  The "0" file is refer to quite often.
Then a non-"0" copy is made, loaded into the editor and away 
we go line by line.

** Document Variables **
Document the easy stuff first.  When I see something like,
780  PRINT "YOU MUST DESTROY"K9;" KLINGONS IN"T9;" STARDATES WITH"B9;" STARBASES"

I start a blank line just below it and write, 
' K9 = total # of Klingons in galaxy
' T9 = # of stardates to complete mission
' B9 = # of starbases in galaxy

Go through the entire listing and document what you can.  When 
you come across a new variable, do a search.  An editor with a 
good search is very helpful. (I use Don Ho's Notepad++)
Look at each line where the variable appears.  If it is set to  
to a number the first time and always is on the right side of 
the equal side after that, then it is a constant.  Note that in 
your description.  Always note when a variable is user input.
If you feel like to know what something is but aren't sure, ask 
yourself by putting a question in the file.  When I first saw,

270  DIM C$[6],D$[72],E$[24],A$[3],Q$[72],R$[72],S$[48]
280  DIM Z$[72]

I wasn't sure what to make of the DIMs.  A search of the code 
for "A$[", "C$[", and "Z$[" showed they were never used.  So the 
note to myself said:
' NOTE:  Not sure why these strings are in a DIM statement.  
'    They appear to be simple garden-variety strings, not arrays.
'    Probably a feature unique to HP BASIC

It took a while to realize that HP BASIC requires all strings to 
be DIMmed to their maximum length.  Just BASIC does not have 
this limitation so we can delete these two lines.

Move all comments that identify variables to one common place.  
I keep the list near the top of the source code.  You're may be 
thinking this is waaaay too obvious but have you ever tried to 
keep 30 variables and their purposes in your head at the same 
time?  Document them.  Usually, the very act of writing things 
down will do a great job of helping to remember.

** Add comments to the source code **
When you figure out what a section of code is doing, add a few 
comments.  Once I knew K9 was the Klingon total and B9 was the 
Starbase total, figuring out the following code wasn't hard.
490  B9=K9=0
500  FOR I=1 TO 8
510  FOR J=1 TO 8
520  R1=RND(1)
530  IF R1>.98 THEN 580
540  IF R1>.95 THEN 610
550  IF R1>.8 THEN 640
560  K3=0
570  GOTO 660
580  K3=3
590  K9=K9+3
600  GOTO 660
610  K3=2
620  K9=K9+2
630  GOTO 660
640  K3=1
650  K9=K9+1
660  R1=RND(1)
670  IF R1>.96 THEN 700
680  B3=0
690  GOTO 720
700  B3=1
710  B9=B9+1
720  S3=INT(RND(1)*8+1)
730  G[I,J]=K3*100+B3*10+S3
740  Z[I,J]=0
750  NEXT J
760  NEXT I

The in-game instructions explained line 730, so I was able to 
document the G[] array plus K3,B3 and S3 -- the # of klingons, 
bases, and stars in each quadrant.

A quick search for the line numbers in this section of code 
showed that nothing else jumps inside these loops, and this code 
does not jump out of them.  This was noted as,
' *** These loops setup our entire 8 x 8 galaxy array: G[]
' *** Plus the total # of Klingons and Starbases: K9, B9
' *** Nothing jumps into (or out of) these two FOR/NEXT loops.

The last comment gives us the "green light" to go ahead and edit 
these lines without worrying about messing up the program flow.

This code tells us a lot.
1270  PRINT "COMMAND:";
1280  INPUT A
1290  GOTO A+1 OF 1410,1260,2330,2530,2800,3460,3560,4630
1300  PRINT
1310  PRINT "   0 = SET COURSE"
1320  PRINT "   1 = SHORT RANGE SENSOR SCAN"
1330  PRINT "   2 = LONG RANGE SENSOR SCAN"
1340  PRINT "   3 = FIRE PHASERS"
1350  PRINT "   4 = FIRE PHOTON TORPEDOES"
1360  PRINT "   5 = SHIELD CONTROL"
1370  PRINT "   6 = DAMAGE CONTROL REPORT"
1380  PRINT "   7 = CALL ON LIBRARY COMPUTER"

Write down everything we can gather from it.
' A  =  User input.  Main menu command number.  0=Move, 1=Short Range Scan, etc.
' 1410 *** Command=0  Set course code begins here
' 1260 *** Command=1  Short Range Sensor Scan code begins here
' 2330 *** Command=2  Long Range Sensor Scan code begins here
' 2530 *** Command=3  Fire Phasers code begins here
' 2800 *** Command=4  Fire Torpedo code begins here
' 3460 *** Command=5  Shield Control code begins here
' 3560 *** Command=6  Damage Control Report code begins here
' 4630 *** Command=7  Use Library Computer code begins here

Move each of these lines to its proper place in the program with 
a blank line before each to highlight the entry point.

Lines 810 to 1250 are "well-behaved" too.  By that I mean there 
are no jumps into (or out of) that section of code.  Line 810 is 
our entry point.  It is called once.  This section loads each 
new quadrant as we travel around the galaxy.
' ** Lines 810 to 1250 -- Load new quadrant -- well-behaved.

As with the block of code that setup the galaxy, the comment
"well-behaved" gives us the green-light to edit this block of 
code safely.


** Modifying the Source Code **
With our variable list and comments in place, we are ready to 
begin editing.  The major focus of the project is to remove as 
many GOTOs as possible using structured language features such 
as multi-line IFs, WHILE/WEND loops, SELECT CASE, etc.

All of the IF/THEN statements in MM's original program were 
like this,
IF <condition> THEN <linenum>
-- so there's plenty of work ahead.  :-/

Let's begin with the 490 to 760 block.  (Code posted above)
Just BASIC's IF statement is flexible.  We can put code after 
the THEN.  In fact, we can put as much code there as we want by 
making it a multi-line IF.  Here is line 530.
530  IF R1>.98 THEN 580

Let's remove the jump by simply moving the code we are jumping to 
after to the tail of line 530 - like this,
530  IF R1>.98 THEN K3=3 : K9=K9+3 : GOTO 660

Let's do the same with 540 and 550.  
540  IF R1>.95 THEN K3=2 : K9=K9+2 : GOTO 660
550  IF R1>.8  THEN K3=1 : K9=K9+1 : GOTO 660

Notice we added a GOTO 660 at the end of line 550 since the 
program would have been there after line 650.

We can do the same with lines 670 to 710 but take a look,
670      IF R1>.96 THEN 700
680      B3=0
690      GOTO 720
700      B3=1
710      B9=B9+1

If our test (R1>.96) is true we do lines 700 & 710 and 
if false we do line 690 then jump to 720.  In either 
case we end up at line 720, so this is a perfect spot for 
an IF/THEN/ELSE.
670      IF R1>.96 THEN B3=1 : B9=B9+1 ELSE B3=0

Going back to lines 520 to 660, which now looks like,
520  R1=RND(1)
530  IF R1>.98 THEN K3=3 : K9=K9+3 : GOTO 660
540  IF R1>.95 THEN K3=2 : K9=K9+2 : GOTO 660
550  IF R1>.8  THEN K3=1 : K9=K9+1 : GOTO 660
560  K3=0
570  GOTO 660
660  R1=RND(1)

We can remove two GOTO 660s by simply moving line 560 above 
the IFs but do you see how we can remove ALL four GOTOs?
Take a moment before reading on. . . . . 
. . . 
. . .
. . . 

If you answered: SELECT CASE, give yourself a point!
I opted for a different solution which takes advantage of a 
couple things the code is doing.  Notice how we are comparing 
our random # (R1) against smaller values as we go... and that 
K9 is always increased by the # we are putting in K3.
Here is my code,
520  R1=RND(1)
525  K3=0
530  IF R1>.98 THEN K3 = K3 + 1
540  IF R1>.95 THEN K3 = K3 + 1
550  IF R1>.8  THEN K3 = K3 + 1
560  K9 = K9 + K3
660  R1=RND(1)
K3 is set to 0, then, as we go thru the IFs, K3 grows.  Then we 
add K3 to K9.

This section started out with 28 lines and 8 jumps.  Here it is 
now -- only 16 lines and NO jumps.
' *** These loops setup our entire 8 x 8 galaxy array: G[]
' *** Plus the total # of Klingons and Starbases: K9, B9
' *** Nothing jumps into or out of these two FOR/NEXT loops.
490  B9=0 : K9=0
500  FOR I=1 TO 8
510    FOR J=1 TO 8
520      R1=RND(1)
525      K3=0
530      IF R1>.98 THEN K3 = K3 + 1
540      IF R1>.95 THEN K3 = K3 + 1
550      IF R1>.8  THEN K3 = K3 + 1
560      K9 = K9 + K3
660      R1=RND(1)
670      IF R1>.96 THEN B3=1 : B9=B9+1 ELSE B3=0
720      S3=INT(RND(1)*8+1)
730      G[I,J]=K3*100+B3*10+S3
740      Z[I,J]=0
750    NEXT J
760  NEXT I

Next, let's take a look at our code to setup a quadrant we have 
just flown into.  
Original Code:
' Lines 810 to 1250 -- load new quadrant
810  K3=B3=S3=0
820  IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 920
830  X=G[Q1,Q2]*.01
840  K3=INT(X)
850  B3=INT((X-K3)*10)
860  S3=G[Q1,Q2]-INT(G[Q1,Q2]*.1)*10
870  IF K3=0 THEN 910
880  IF S>200 THEN 910
890  PRINT "COMBAT AREA      CONDITION RED"
900  PRINT "   SHIELDS DANGEROUSLY LOW"
910  MAT K=ZER
920  FOR I=1 TO 3
930  K[I,3]=0
940  NEXT I
950  Q$=Z$
960  R$=Z$
970  S$=Z$[1,48]
. . .
. . .
1250 NEXT I

The only tricky part is near the top... that long IF statement
which says, "if our ship's location (Q1,Q2) is out of bounds, 
skip down to line 920".  

This time we are going to change the test from,
IF true THEN GOTO 920
 -- to --
IF true THEN "do everything between here and line 920"
So instead of checking for out of bounds #s (<1, >8) we check 
for valid #s (>=1, <=8) and to change the "OR"s to "AND"s 
since any value out of range should cause the test to fail.
820  IF Q1>=1 AND Q1<=8 AND Q2>=1 AND Q2<=8 THEN 
...    code between 820 and 910
915  END IF

Lines 830 to 860 extract K3, B3 and S3 (our klingons, bases and 
stars in this quadrant) from our galaxy array.
830  X=G[Q1,Q2]*.01
840  K3=INT(X)
850  B3=INT((X-K3)*10)
860  S3=G[Q1,Q2]-INT(G[Q1,Q2]*.1)*10

These were made a bit simpler,
830  X=G[Q1,Q2]
840  K3=INT(X/100)
850  B3=INT((X MOD 100)/10)
860  S3=X MOD 10

Lines 870 to 900 went from,
870  IF K3=0 THEN 910
880  IF S>200 THEN 910
890  PRINT "COMBAT AREA      CONDITION RED"
900  PRINT "   SHIELDS DANGEROUSLY LOW"
 -- to --
870  If K3>0 Then
880    Print "Combat Area      Condition RED"
890    If S<200 Then Print "   Shields Dangerously Low"
900  End If

These changes remove both jumps and allow the "Condition RED" 
message to be printed even if our shields strength is ok.  It
seemed proper since the Klingon was going to fire on us whether 
or not we fired on him first.

The MAT command at line 910 was replaced by two FOR/NEXT loops 
to zero-out the double-dimensioned K() array.  A REDIM would have 
worked just as well.  Lines 920 to 940 clear the 3rd element of 
K().  Since we just cleared the full array in 910, we can move 
910 below the closing END IF and delete lines 920 to 940.

950  Q$=Z$
960  R$=Z$
970  S$=Z$[1,48]
Q$, R$ and S$ were all replaced by one string: Q$  The rest of 
this section, lines 980 to 1250 put the Enterprise, klingons, 
starbases and stars into the quadrant.

' Lines 1260 to 1400 -- Get command from user.  Jump.
Which brings us to the main command menu and multi-branch code.
A SELECT CASE was used for the multi-branch.  The only real 
change was from using GOTOs to GOSUBs for the commands.
This portion of code was the heart of my main program.  It 
looped until a flag was set to signal the end-of-game had 
been reached.

' Lines 1410 to 2320 -- Navigation code
The single largest routine in the entire program... and not 
well-behaved.  If our navigation send us to another quadrant
it jumped up to that code.  If we ran out of time or energy 
if jumped to the end-of-game section.

A little more checking of the input for course and warp speed is 
done.  The max warp when engines are damaged is up from 0.2 to 
0.25 so you can move two sectors at a time.

A couple new flags were added, newquad and badnav, to better 
handle some troublesome jumps when we flew into another 
quadrant or into another object.  Also added some logic to 
prevent the Enterprise from flying out of the galaxy.

'Lines 4120 to 4620 -- Short Range Sensor Scan
A check was added at the top of this sub to see if a starbase is 
in this quadrant.  If so, we look in the sectors around the ship 
and, if found, set the "docked" flag to true.  
HP BASIC's USING/IMAGE formatting features were used heavily in 
the original Short Range Sensor Scan so this section got a major 
overhaul.  

' Lines 2330 to 2520 -- Long Range Sensor Scan
The Long Range Sensor Scan sub was recoded to get rid of the 
N$[3] array, and to display dashes for quadrants outside galaxy 
boundaries.

' Lines 2530 to 2790 -- Fire Phasers sub
This section was fairly typical of the rest of the program.  It 
had 29 lines and 13 jumps.  After recoding it was 30 lines and 
NO jumps.  :-)

' Lines 2800 to 3450 -- Fire Torpedo sub
At 67 lines this was one of the larger sections.  Was able to 
use a SELECT CASE and get rid of a good number of jumps.

' Lines 3460 to 3550 -- Shield Control
' Lines 3560 to 3660 -- Damage Control
' Lines 3690 To 3780 -- Klingon Destroyed
' Lines 3790 To 3910 -- Klingons attack Enterprise
These short subs were straight forward and easy.

' Lines 4630 to 5320 -- Library Computer
Option 0 (Galactic Record) used HP BASIC's unique formatting 
features but otherwise was easy to Just BASIC.
Option 1 (Status report) was simple print statements and needed 
only minor tweeks.
Option 2 (Photon Torpedo Data) was a bit of a challenge though.
This code basically does two things: (1) It tells us the 
direction and distance to each klingon in our quadrant and (2) 
asks if you want to use the calculator, if you do, it asks for 
2 sets of row, column points.  Then does the math and prints the 
result.  
The code to do both jobs was written into a single loop so I 
moved the calculating code into its own GOSUB then split the 
loop into two loops.  This made it much easier to read the code 
and figure out what was happening.  That's important when 
we need/want to make changes at a later time.

I used SELECT CASE statement in the calculator code to greatly 
improve its clarity too.  The math got a bit of a re-write also.



         **********  Final Comments  **********

Q) What's different between the old and new versions?

A) Structure mostly.  The original HP BASIC program has about 19600
   bytes and 640 lines with 184 jumps to 104 different line numbers.
   The Just BASIC version is about the same size (if you don't count
   REMs and blank lines) but 21 labels (mostly for GOSUBs) and only
   a handful of GOTOs.

   HP BASIC had some odd features for handling formatted output and
   for dealing with strings.  No string was over 72 characters.  
   That forced Mike to use three strings to handle the 192-byte 
   quadrant map.  Just BASIC's larger strings made the job a lot 
   simpler.  :-)

   HP BASIC allows GOSUBs but they were used for only simple code.  
   This version uses them for all the major commands, changing 
   quadrants, Klingon attacks, etc.

   Some sections saw major rewrites
    * Short Range Sensor Scan
    * Fire Photon Torpedo
    * Navigation
    * calculator for direction and distance between two points
    * the string insertion & comparison GOSUBs
    * the Library Computer Calculator function
    
   The HP program had about 20 lines of comments.  This one has a
   lot more. . . around 70.  For a bit of nostalgia I used the 
   old-school REM rather than the apostrophe.

   Message text was converted from all uppercases to mixed case.

   The source code was indented to show code dependance.
   
   This project was enjoyable.  While the code is still familiar, 
   it might be good to convert the variables from their one- and 
   two-character length names into descriptive labels.  Perhaps 
   change the GOSUBs into Real Just BASIC Subs too.  Who knows, 
   might even turn it into Super Star Trek.  The HP version of 
   Mike Mayfield's Star Trek turns 35 years old this month.  Let's 
   hope the Just BASIC version lives as long ... and prospers. :-)

Enjoy!

