A Bit of History

Two years after the original series was canceled in 1969, high school senior Mike Mayfield was busy keeping the Star Trek universe alive by feeding punched paper tape into a Sigma 7 in an effort to bring the crew of the Enterprise and the Klingon Empire to life on a 10 character-per-second teletype terminal. Soon after Mike ported his game to HP BASIC, it entered the public domain. From there, early computer enthusiasts enhanced and rewrote the game for every flavor of mini and microcomputer BASIC imaginable and beyond.

I remember encountering versions of the game back in the early 80s when I was a little kid trying to learn BASIC on my IBM PCjr. Back then, computer books and magazines distributed programs in printed form. Meaning, you had to type them in to play the games. It was a pain in the ass, but the process encouraged you to tinker. It motivated you to learn to code and to tweak or even improve the programs you were entering in.

Every BASIC game book that I picked up contained some version of the Star Trek game. I recall loading it up a few times, but each time I ended up staring at the screen in utter confusion. "How the heck is this Star Trek?" I remember thinking. I couldn’t figure out how to play it.

By the time I entered high school, I had graduated from BASIC and moved onto to bigger and better things like C and C++. But, on occasion, I often wondered about the Star Trek text game. What made it so popular? After learning about the history that I touched upon above, I decided to dig it up and take a second look.

After a bit of web surfing, I came across Mike Mayfield’s original port to HP BASIC. Here’s a snippet of the code:

Ah, good old line-numbered BASIC. It’s all coming back to me now. Those line numbers were there to provide targets for GOTO and GOSUB statements. But, line numbers made editing a tad difficult. It was convention to enter in line numbers that were multiples of 10. That way, as you developed the program, you could go back and insert up to 9 additional statements in between existing lines without reworking all the GOTO/GOSUB references. If you needed to insert more than 9 lines, I remember a special feature in the BASIC editor on my PCjr. It would append a zero to all line numbers and all line number references throughout the program. Meaning, you could now insert up to 99 lines. Couldn’t they just renumber the program in multiples of 10? Nah. The PCjr wasn’t powerful enough for that.

If you’re wondering about “Centerline Engineering,” it was an imaginary company that Mike Mayfield coined to give his BASIC projects a level of prominence to those reading the remarks section.

With code in hand, I really wanted to play the game. I’m sure that there are HP BASIC interpreters out there for modern machines, but what fun would that be. Before I played it, I wanted do my own port. This game was born in the hobbyist era. It was made to be reinterpreted and enhanced as it traded handed. I wanted to bring back part of those long-lost magical days of type-in programs.

My first impression of the code was "what’s with all the single letter variable names?" First I thought it was a limitation of HP BASIC, but then I noticed the occasional 2-letter names. I guess 2 is better than 1. Everything is also in caps. Take a look at this line:

2140 T=T+1

That line increments T. But, due to the caps, I feel like the code is screaming at me. ASIGN THE SUM OF T AND 1 BACK TO T DAMN IT! Also, I’m so used to writing t++ or t += x that I forgot about the expanded notation. In fact, entering 7th grade having mastered BASIC, I found myself really confused when my math teacher introduced us to solving simultaneous equations. For instance, find the value of X in this equation:

X = 2X - 6

That was the first time I was introduced to the concept of operator overloading. The equals-sign can mean variable assignment or numerical equivalence depending on the context.

These are not executable statements. They’re strings that can be referenced in PRINT commands. The unquoted symbols get substituted with values of variables. It’s conceptually similar to C-style printf() format placeholders. I didn’t realize that BASIC offered such a rich numerical formatting notation.

As I continued to examine the source, I found some statements that didn’t make sense. For instance, even though you don’t have to declare variables before you use them, you still need to specify the dimensions of arrays. I came across some arrays that were never allocated as such. Ultimately, I decided to seek out a better basis for my port.

After a bit of Googling, I found a cleaned up version that maintained the majority of Mike Mayfield’s code. Some of it was reworked, probably to enable it to run on modern versions of BASIC. For instance, those cool IMAGE statements were dropped and replaced with sets of simpler PRINT commands. The variable names appear virtually identical, but at least they are all accounted for in this version.

Porting the Game

Next, I had to decide what language to port it to. Staring at that BASIC code reminded me that C# brought goto back into the mainstream. Would it be possible to do an exact line-by-line port from BASIC to C#? Apparently so... and the result is some of the sickest code I’ve ever keyed into a computer. Want a comparison? Here’s a segment of BASIC code:

To simulate line numbers, each line starts with a label consisting of an underscore followed by a number. That works fine for GOTO, but what about GOSUB? Examine line 2992. Subroutines were replaced with methods. That almost worked. In BASIC, you’re not forced to RETURN from subroutines. You can leave them via GOTO. That was used only in the case that the player is destroyed to send them back to the beginning of the program to start over. I replaced that GOTO with a return statement that passes a flag back to the caller. The caller inspects the flag and jumps back to the program start if need be. I also discovered that at one point, there is a GOTO that jumps into a FOR loop. C# won’t let you jump to a label in a sub-block of code. I transformed the FOR loop into a GOTO loop to make C# happy.

All the variables in the BASIC program, including the arrays, are real number type. However, in BASIC, an array and a scalar can share the same name; the interpreter is able to sort it all out. But, C# is less kind. To solve the problem, I prefixed array names with underscores. Also, arrays in BASIC are indexed from 1 instead of 0. To compensate, I increased the length of all arrays by 1. Index 0 is never used.

When I started testing my port, I noticed some string formatting problems. Examine the following BASIC line:

2726 PRINT TAB(41);"(";

That means: Print 41 spaces followed by left-parenthesis. That was easy to translate, but the intension was to push the left-parenthesis onto the next line by letting it wrap around the console. I cleaned some of this stuff up. There are also some tables that get printed in the game. I reformatted them a bit to make them easier to read.

One other thing: notice that in this type of BASIC, # indicates not-equal-to. It took me a while to realize why they chose that symbol. # resembles ≠.

Entering the Star Trek Universe

Now, I was ready to play the game. As I mentioned above, I never understood the rules before. Luckily, when you run the program, it gives you the option of viewing instructions. I studied them carefully. But, the only way to really understand what to do is to play the game. Here’s a walkthrough:

The game makes itself known by printing out its title. Then, it asks you if you want to view instructions. Every prompt in the game demands a number. If you hit Enter, zero is assumed. In this case, I hit Enter to skip the instructions. Next, it asks for a seed number to initialize the randomizer. This is an artifact of BASIC. It doesn’t really have an effect in C#. In BASIC, just as in C#, the randomizer could have been initialized based off the system time. If that was not an option, they should have taken advantage of the instructions prompt. When the instructions prompt appears, it could have entered a loop that timed how long it took the user to enter a value. That duration could have been used to initialize the randomizer. Again, I simply pressed Enter to skip it.

Next, it prints out my mission. I have to destroy 17 Klingon (note the game misspells it here) ships in 30 units of time with 3 starbases. Then it runs the short range scanner. The short range scanner displays the current quadrant. The game takes place in an 8×8 quadrant grid. Each row and column is numbered 1 to 8. The text on the right indicates that I am in quadrant (5,2). Each quadrant is partitioned into an 8×8 sector grid. The Enterprise is located at sector (5,4). On the quadrant display, <*> is the Enterprise. The remaining *’s are stars. Each = mark on the top and bottom horizontal-line dividers indicates a column. If you count, you’ll find that the Enterprise is in column 5. If you count the rows, you’ll find it’s in row 4. Hence, within this quadrant, the Enterprise is in sector (5,4) as specified.

The goal is seek out quadrants containing Klingon ships and destroy them. Let’s begin by doing a long range sensor scan (option 2):

This table summarizes 9 quadrants. The center quadrant is your current quadrant. The digits indicate the number of Klingon ships, the number of starbases and the number of stars. In our quadrant, there are no Klingon ships and no starbases, but there are 5 stars. Stars act as annoying obstacles as I’ll demonstrate later on. South of us, there is a quadrant containing 1 Klingon ship. Let’s head there. But, first we need to raise shields (option 5):

COMMAND 5
ENERGY AVAILABLE = 3000
NUMBER OF UNITS TO SHIELDS 500

It asks me how much energy I want to devote to the shields. I entered 500. If I run out of energy, I lose the game. Starbases replenish energy. They also restock photon torpedoes and repair damage. To see how much energy I have left, I’ll run a short range scan again (option 1):

Angle goes from 1.0 (inclusive) to 9.0 (exclusive). Note that the y-axis points downwards. So, although it appears to be a counterclockwise angle system, it’s actually clockwise. You also need to consider the aspect ratio. Each column is 3 characters wide, but each row is only 1 character high. This means that it’s not a circular coordinate system. Rather, it’s a swashed oval.

Distance is measured in warp factor units. Such a unit is equal to the length/height of a quadrant. To move to an adjacent sector, you need to move a distance of 1/8 = 0.125. I’m going to move south (angle 7.0) a distance of 1 warp factor. Navigation is option 0:

Navigation automatically runs a short range scan. Note that I moved from quadrant (5,2) to quadrant (5,3). Also, notice that is says that my warp engines are damaged. Parts of the Enterprise fail spontaneously. As you navigate around, they slowly get repaired. Let’s get a damage report (option 6):

Photon torpedoes are fired using the same direction and distance coordinate system as is used for navigation. The computer gave me the coordinates. Then it asks if I want to use the navigation calculator. The navigation calculator asks you to enter the coordinates of 2 quadrants and it will output direction and distance between them. I’ll press Enter to indicate I am not interested in doing this. Now, let’s fire the torpedo (option 4):

The game outputs the track of the torpedo. In this case, it hit the target. If the computer gets damaged, you have to estimate the direction of the Klingon ship yourself. It may take a few tries. The torpedo track will help you refine the direction. Also, sometimes a torpedo randomly diverts a bit from the specified direction.

I managed to get over there, but now my long range scanner is damaged. Note that each time you cross a quadrant boundary, the stardate advances. I have to destroy all the Klingons in the time restriction of my mission.

The >!< symbol indicates a starbase. If I navigate next to it, the Enterprise will automatically dock at which time I’ll get everything repaired. But, if I try to navigate there, the Klingon ship will fire at me. I can’t send out a photon torpedo because of the stars. The stars will obstruct the track. Let me check on those repairs:

I fired twice, which severely lowered my energy level. Phaser strength is a measure of the distance between the Enterprise the target. It probably would have been better to navigate north for a clear path for a photon torpedo. Luckily, I can dock with the starbase to replenish my energy:

The starbase takes away all my shield energy before giving me back 3000. If the game didn’t do this, the player could get infinite shield strength by repeatedly docking and transferring energy to the shields.

Also note that I docked by crashing into the starbase. While you are within a quadrant, you can’t pass through stars, ships and starbases. However, after leaving the current quadrant, those are no longer obstacles. In fact, the positions of stars, starbases and Klingon ships within a quadrant is not determined at the start of the game. Rather, the positions are invented at the time you enter a quadrant. It creates the illusion that stars, starbases and Klingon ships can move around within a quadrant. Note that they can never move out of a quadrant.

The values you see in a long range scan are the only values tracked by the game. It doesn’t store the exact sectors of each entity within a quadrant until you enter it. On a related note, the computer can show you a table of all scanned quadrants (option 7, option 0):

THE LAST KLIGON BATTLE CRUISER IN THE GALAXY HAS BEEN DESTROYED
THE FEDERATION HAS BEEN SAVED !!!
YOUR EFFICIENCY RATING = ...

And then it just starts over again with a new mission. The efficiency rating is a function of the time remaining. In Mike Mayfield’s original version, the time remaining was actually in minutes. As mentioned, in this version, it’s in turns.

Super Star Trek

In 1976, Creative Computing published a modified version of Mike Mayfield’s program titled Super Star Trek. It’s virtually identical to the original game. However, the menus accept 3 letter mnemonics instead of numbers. The computer offers a few more options. And, just for fun, each quadrant has a name. With those ideas in mind, I decided to code my own version of the game. I began by digging up some ancient ASCII art...

There are many subtle nuances in the original game. How often do different parts of the Enterprise malfunction? How and when do photon torpedoes randomly deviate from their specified targets? And so on. It doesn’t really matter. As I said above, this is the kind of game that deserves to be reinvented everytime it trades hands. The exact parameters of the Star Trek universe are up to the coder. For example, in my version, different parts of the Enterprise malfunction depending on how often you use them. If you rely on the computer for targeting Klingon ships too much, the computer will start to fail.

Rewriting the game brought up an interesting aspect of the BASIC version. Targeting is done using polar coordinates, but you won’t find any trigonometric functions in the BASIC code. I assume the functions were unavailable. Instead, the angle is converted into a direction vector using different ratios that approximate the trigonometric functions. That means even if you worked out perfect targeting using trigonometry, when you entered in the angle, the actual trajectory will be slightly off. Nonetheless, it’s a pretty clever math trick. As for me, I took advantage of Math.Sin() and Math.Cos().

Comments and Discussions

At least, that's what it was called on the Dec-20 we had access to in high school back in 1974.

Somewhere around the house I have the listing to another Star Trek game that was on that Dec-20, 10Trek, that was a hoot and a half. I've been trying to find it to code it in and get a working version.

You have to download and install the FREE Microsoft Visual Studio Express. This will allow you to open and run the the C# source code supplied here by Michael Birken.

It does seem to have a number of bugs in it, so it needs a bit more work perhaps. For example, the number of star bases reported by the Computer Status Report (e.g. 3) differs from the Computer Cumulative Galactic Record (e.g. 18). It will crash if you go beyond the border of the galaxy. Just before completion I was scuppered, since I ran out of energy, even though I had plenty left. See the following example:

Mike Mayfield's original HP Time-Sharing BASIC code is spaghetti code, using GOTO statements. It jumps into the middle of FOR loops and the like, something that is illegal in structured programming. This makes it impossible to create a direct equivalent translation into programming languages that do not support jumps to labels, including ANSI BASIC written without line numbers.

When Mayfield's HP BASIC code is processed through the btotb.exe BASIC-to-True BASIC converter program offered by True BASIC, Inc., it produces code that will not compile or run, even after the PRINT USING and IMAGE statements are manually converted. Compilation halts with numerous "Illegal line number" errors due to illegal jumps into loops.

While it is possible to write a program that to the user appears like Mayfield's original, including typos, grammar and spacing errors, if one uses a structured programming approach it will look very different internally.

My first impression of the code was "what’s with all the single letter variable names?" First I thought it was a limitation of HP BASIC,

Back in those good ole days, most computers only had 4 kilobytes of RAM. BASIC variables consumed 1 byte for each character in the reference. So, to save precious RAM addresses, single letter variables were the rule. Likewise, the PRINT statement was often shortened to a question mark, because that saved a byte. (I recall that PRINT only took two bytes because each of the BASIC statements began with unique two characters, so only two bytes were stored in the program; PRINT was effectively "PR", but "?" saved a precious byte. I'm a little vague on this point though as I was pretty young and informally educated.)

I loved my TRS-80 MODEL I. I have loved programming ever since I picked up my first programming instruction manual at age 14, in 1978. I often show people a picture of the TRS-80 and announce it as my first love, and when I do that, I am not lying.

Mike Mayfield originally wrote his Star Trek simulation in BASIC on an SDS Sigma 7 system at University of California, Irvine, using a "borrowed" user account. That version has been lost to time. In late 1971 he ported the program to HP Time-Sharing BASIC on an HP 2000C system. These machines typically had at least 16kB of program memory, and possibly more via swapping to the hard drive, so having small core memory was not the reason for the one- and two-character variables. That was a limitation of HP Time-Sharing BASIC, which at the time was a fairly direct offshoot from Dartmouth BASIC with respect to programming syntax. Numeric variables, excluding arrays, could be named A, A0-A9, B, B0-B9, ... Z, Z0-Z9, giving 286 possibilities. Arrays could be named A ... Z, giving 26 possibilities. Strings could be named A$, A0$, A1$, B$, B0$, B1$, ... Z$, Z0$, Z1$, giving 78 possibilities.

HP Time-Sharing BASIC did not allow shortening statements to one- or two-character mnemonics. Such ugly features appeared much later on badly hacked-up versions of BASIC that appeared on microcomputers.

You seem confused about the purpose of having the player enter the randomizer seed. This wasn't out of laziness or lack of understranding of the available options, rather it was a feature that allowed the player to raplay a game. You and your buddy both enter the same randomizer value and can play the same map to see who has a better strategy/tactics.

Oh that is a great idea. And actually I am very addicted to this game it is great! I am hopefully, as a background project, port it to C++ and allow you to boot your computer with this Star Treck game as the OS.

The real reason for entering the randomizer seed is that the HP 2000C system on which Mike Mayfield wrote his port from the SDS Sigma 7 system didn't have a RANDOMIZE statement. Without that statement the program's random number generator would produce precisely the same sequence of pseudo-random numbers each time it ran. The RND() function in HP Time-Sharing BASIC accepted a single numeric parameter ("seed") that served the purpose of the RANDOMIZE statement in later versions of BASIC on personal computers, but if the same seed was used each time, the random number sequence would always be the same. This is fine for program testing, but not so good for game play. Game and simulation programmers got around the problem by having the player enter a random number from the keyboard, or by reading the time value from the system clock with the TIM() function and using that as a somewhat random seed.

Even though HP Time-Sharing BASIC on the HP 2000C had the capability of automatically seeding the random number generator using this method, Mike Mayfield never took advantage of it in the version that was offered via the HP BASIC Program Library. Every instance of the RND() function in the STTR1 program used a constant as a parameter, so the program always started out in identically the same state. Being a relatively novice programmer at the time, Mayfield was probably unaware of this.

I can't believe this stroll down the memory lane. I had completely forgotten everything about that game but it all came flooding back. I now remember I spent a fair bit of time playing that game. Thanks.

I think about this game every so often. This and "Adventure" just about got me kicked out of high school. Truly amazing how impactful a little bit of code can be on a generation or two of young tech types. I don't think that it is an exageration to say that my life would have probably gone in a different direction if I hadn't been so enchanted by a few interactive programs like this.

Thanks so much for your article Michael and thank you to Mr. Mayfield for starting this particular ball rolling so long ago.

Nice article! Just a bit of background on the TREKPT.txt
BASIC source used for the conversion...

STTR1 and its many derivitives has been one of my favorite
programs ever since I started playing with computers in
the mid-80's, used to play a conversion of Super Star Trek
on my old Atari 8-bitters. In 2006 I converted the original
STTR1 to run under TSB-E (running under a HP2100 minicomputer
simulation), basically breaking it up into segments and
re-coding the IMAGE formatting statements. The conversion
worked well but was kind of inconvenient having to boot TSB-E
to play trek so in 2007 I converted STTR1 to run under the
original paper-tape HP-BASIC (also runs under a 31KW version
of MSU BASIC) so I could put it into a standalone ABS binary
to run under the SimH HP2100 simulator. That way I could
just click an icon on my desktop and there it was.

Converting STTR1 to run under papertape BASIC was not easy,
mainly because papertape BASIC has no strings except for
print output. All strings had to be converted to use
numerical equivalents, and in the process somehow the
specification of X,Y coordinates got reversed (had forgot
that the original used Y,X but X,Y works fine for me).
I was new at papertape BASIC and thought it only supported
single-character variable names, so converted all variables
to single letters and used arrays to represent some. Later
I learned that papertape BASIC supported [letter][number]
names and could have not done that... oh well.

I borrowed the IMAGE format conversions from the TSB-E
version, but also added a number print subroutine because
papertape BASIC always padded numbers to a certain field
size making number prints look messy. The original did
not have the -=--=--=- top and bottom borders, added that
to make coordinates easier to determine. The prompt for the
seed number at the beginning was added to randomize, otherwise
it played the same game every time (under papertape BASIC each
number generates a different starting configuration).
Also added a display of "warp units" in the computer
navigation function for direct entry into the move command.

A stand-alone ABS file for TREKPT (along with paper-tape
conversions of other old HP games) is at:
http://newton.freehostia.com/hp/absgames.zip
Requires the SimH HP2100 simulator.

Hey i have been given some Project Work from my school to design a software just like Microsoft Word with visual basic 6.0 or visual c++ and i really need a helping hand, coz i have sat for hours thinking of how to do it. Please help me if with some codes you think might help me. Thanks very much.

When I was 12, this game was one of the first programs I wrote on my calculator. Back then I slept with that calculator and I would more likely forget to carry my wallet than my trusted TI-82. In later stages I even wrote animated porn on it

I had to rewrite it a lot because each math exam the teacher came round to reset all calculators (so we wouldn't cheat). It was annoying because the TI-82 isn't made for typing all those things.

Really thanks for the article. It brings back a lot of memories of how code used to be and how similar you can still code it today.

I saw the post for the contest and throught about creating an entry but I decided to find a new job instead.

My father worked for Xerox back in the 70's and 80's as an EE. He even has copies of some of the patents from his work on the 850 (and succeding) word processors. In fact, until a year ago, he still had an 850 in his office. I remember playing this game (and Zork) on a teletype terminal using thermal paper and a 300 baud acoustic coupled modem. I went through reems of paper playing both games.

I also remember another game they had at his office during the mid/late 70's. I got to go to work with him occasionally on Saturday and he set me up on this to keep me out of his hair. It was a real-time graphical version of Star Trek where you would fly around as either Federation, Klingon, or Romulan and search out the other guys and kill them. From what I remember, the game had a pretty good physics model (in two dimensions). The machines had full mac-like GUI and mouse (in the 70's) and were networked together (probably an early version of their ARCnet?). I'm sure they got this stuff from their PARC facility.

since I played that game. I wasted quite a bit of time as a young engineer playing a Fortran version on PDP-11 and VAX machines (seems like I ported it to the Vax). It requires using a little imagination.

I just about fell over when I saw the line-number labels! What a wonderfully warped way to do it