Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

42 Astoundingly Useful Scripts and Automations for the Macintosh

Work faster and more reliably. Add actions to the services menu and the menu bar, create drag-and-drop apps to make your Macintosh play music, roll dice, and talk. Create ASCII art from photos. There’s a script for that in 42 Astounding Scripts for the Macintosh.

Reversi in SuperBASIC on the Color Computer

Jerry Stratton, July 8, 2020

Reversi is a fun game to write on an early computer. I suspect one of the reasons it was so popular in early BASIC books is because it’s also an easy game to write on early computers. It’s very easy to get a version that basically works, even if it doesn’t work well.

I took the logic for this game from Tim Hartnell’s Giant Book of Computer Games. It was a fun game, but it didn’t handle everything it really ought to have. That was Hartnell’s style: provide a basic structure, and let the reader learn by adding to it. Among the things that needed to be added were:

  • Require a move by the human player if one is available.
  • Recognize more quickly that the game is over when the game is over1.
  • Disallow a move by the human player that doesn’t flip any pieces.
  • Recognize that the game is over if one player has no pieces. Sadly, I have lost all of my pieces while playing this not particularly smart game. My excuse is that I was often playing the game while distracted by programming the game.

And of course there were a lot of other changes I wanted to make so that the game would play better on the Color Computer.

Reversi checking moves

Checking to see if the player has any valid moves, and highlighting them as they’re found.

I decided it would be even easier to learn by adding to it, if I first rewrote it completely in superBASIC to make the logic easier to understand. As written, the game uses all of the block types currently possible in superBASIC: loops, switches, and both if/endif and if/else/endif. It’s a very good example of how to use superBASIC to write an old-school BASIC program.

While my next game project is going to use the Color Computer’s graphics screen, I decided to keep this one retro. The board is constructed using text, just as in Hartnell’s version, with ‘O’ for the human player and ‘X’ for the computer. This makes it easier to manipulate the board; for example, highlighting a move is as simple as adding 32 to the ASCII code for the character. The characters themselves are stored as numbers, making that sort of conversion even easier.

The computer’s tactics are pretty basic. It uses a few decent metrics to decide on what a good move is. These are in the findMove subroutine:

[toggle code]

  • //adjust the desirability of the current potential move
  • switch
    • //if the number of flips is the number of human pieces, take it
    • case (%currentQuality% = %humanScore%)
      • %currentQuality% *= 100
    • //edges are more desirable
    • case (%row%=2 or %row%=9 or %column%=2 or %column%=9)
      • %currentQuality% *= 2
    • //next to the edges are less desirable
    • case (%row%=3 or %row%=8 or %column%=3 OR %column%=8)
      • %currentQuality% /= 2
    • //next to corners are less desirable yet
    • case ((%row%=2 or %row%=9) and (%column%=3 or %column%=8) or (%row%=3 or %row%=8) and (%column%=2 or %column%=9))
      • %currentQuality% /= 2
  • endswitch

Three of those are Hartnell’s. I’ve added one, that if the number of flips is equal to the number of human pieces remaining, take that move, as it is a winning move. I added that after seeing the computer take pity on me by not taking the move that would have wiped out all of my pieces.

New metrics can be added by adding new CASEs to the desirability SWITCH in findMove.

The basic logic is very basic. The program sets up the board and then loops through computerMove and humanMove.

[toggle code]

  • gosub initialize
  • if %firstMover$="human" gosub humanMove
  • loop
    • gosub computerMove
    • gosub humanMove
  • endloop

The humanMove routine asks the player for their move. The input routine uses INKEY$ to get either a two-digit number or the commands HELP or PASS. Using INKEY$ in this way provides a flashy cursor and also reduces the chance of the board getting messed up by a long entry.

Tim Hartnell’s Reversi

This is what the original version looked like from Hartnell’s book. As you can see I haven’t changed the basic board.

If the player attempts to pass, the program checks to verify that they have no moves left. It highlights any moves available. I pretty much just took the logic that the computer uses to choose its move, and made it a subroutine. You can speed up the program by uncommenting the lines in findMove that start with the comment “if this was the human”:

[toggle code]

  • if (%board%(%currentRow%+%rowOffset%, %currentColumn%+%columnOffset%)=%mover%) then
    • %currentQuality%+=%flipCount%
    • /*
    • //if this was the human, all we care about is that there is a possible move
    • if (%mover% = %human% and %flipCount% > 0) then
      • %flipQuality% = 1
      • return
    • endif
    • */
  • endif

This will return from findMove immediately on finding a valid move, instead of finding and highlighting all possible moves.2

The program does not keep track of the score in any complicated manner. When it prints the board after each side makes its move, it counts up the number of X’s and O’s. That’s the score. The program uses a trick from the Hartnell book of not using CLS between each turn. That makes it look like the board is updating individual cells, even though it’s really updating every cell. Cells that have the same value look like they aren’t changing. Only cells with different values look like they’re changing.

Each of humanMove and computerMove call gameStatus at the end of the move to print the board and to see if the game is over. There are three ways for the game to end:

  1. Either the computer or the human has no pieces on the board.
  2. All sixty-four of the spaces have been filled.
  3. Neither the computer nor the human can make a move.

The rules are:

  1. If you have a move you must take it.
  2. A move consists of sandwiching one or more of your opponent’s pieces between an existing piece of yours and the piece you are laying down.
  3. If you do not have a move, you must pass.

The findMove routine does double duty: it chooses a move for the computer, and it highlights potential moves for the player, if the player attempts to pass.

If you want to highlight what moves the computer is choosing from, you can alter the code to show it for both sides instead of just for the human. Change:

[toggle code]

  • if (%mover% = %human%) then
    • //highlight the potential move
    • if (%currentQuality% > 0) then
      • if (%moveLocation% > 0) then
        • print@%moveLocation%, chr$(%blank%);
      • endif
      • %moveLocation% = %row%*32 + 4+%column%*2
      • print@%moveLocation%, chr$(%mover%+32);
    • endif
  • else

to:

[toggle code]

  • //highlight the potential move
  • if (%currentQuality% > 0) then
    • if (%moveLocation% > 0) then
      • print@%moveLocation%, chr$(%blank%);
    • endif
    • %moveLocation% = %row%*32 + 4+%column%*2
    • print@%moveLocation%, chr$(%mover%+32);
  • endif
  • if (%mover% = %computer%) then
Reversi thinking about its move

The Color Computer thinking about its next move.

This will cause the routine to highlight for both the player and the computer, but only adjust desirability for the computer. Desirability only matters for the computer. For the human player, all we care about is whether a move exists at all.

In the gameOver routine, if the player answers N to whether they want to play again, the program tries to RUN "AUTOEXEC:1". That’s a program I have that lists the most common games I like to play on the Color Computer; you’ll want to either remove the entire else section of the line or replace the program name with one of your own.3

The superbasic archive (Zip file, 18.9 KB) contains both the superBASIC source code for reversi, and the REVERSI.BAS Extended Color BASIC code that it transforms into.

In response to TRS-80 Color Computer: The TRS-80 Color Computer was a fascinating implementation of the 6809 computer chip, and was, with from the Color Computer 1 through 3, possibly the longest-running of the old-school personal computers.

  1. Hartnell‘s games have a tendency to need a couple of loops to realize that a game is over. His chess game was the same way.

  2. I used to think that exiting from a FOR/NEXT loop early was a bad idea in old-school BASICs, but now I think it doesn’t matter. Extended Color BASIC appears to clear the FOR/NEXT stack on a return from GOSUB, to where the stack was on invoking the GOSUB.

  3. It’s called “AUTOEXEC.BAS” because the CoCo SDC looks for a file with that name and runs it automatically on startup. So if you have a CoCo SDC an AUTOEXEC is very useful to show off your computer to those not familiar with retro computers.

  1. <- PCBASIC to CoCo
  2. Hunt the Wumpus ->