Wednesday, 3 June 2026

Tetris for the Freebee (and Microbee)

Back in the early nineties I got my hands on a Gameboy. I didn't have any money for games, so just played the game that came with the Gameboy; Tetris. This was truly addictive and I estimate I played it for many thousands of hours, getting reasonably good with occasional high scores above 200,000 (big rocket), but not up to Woz level.

Recently I watched the (broadly fictionalised) movie of how that came to be, with the original Tetris running on a Soviet PDP-11 clone, with everything done in characters. Hey, I could do that on a Freebee, and it'd be a cool game to learn to write games in assembler with. So over the last month or so I did just that.

My version is reasonably close to the Gameboy one, but with some caveats. Gameboy runs with a 60Hz screen refresh rate, whereas Freebee and Microbee run at 50Hz. This means my drop rates, which are timed in video frames, aren't exactly the same as the Gameboy. In practice you won't notice until around level 8 or 9, where the difference rises above a couple of percent. Worst one is level 18 and 19, where I do 3 20ms frames (60ms) and Gameboy does 4 16ms frames (64ms).

But no need to grumble about the tiny differences. My version is every bit as fun as the Gameboy one, and I've wasted a lot of time now playing it (though I'm still to see a high score above 200,000).

I didn't really plan the game out much before writing it, so my development method is pure eighties spaghetti. I started by drawing some tetrominos in Basic to get an idea of what they looked like. I had to do it in an 80x24 screen, as the Tetris playfield is 22 rows vertically, so it won't fit in 64x16. Then I wrote code to allow me to move a tetromino left and right, and rotate it. I figured the easiest way to rotate was just to index through versions of the tetromino (wasteful in terms of RAM, but fast). Given the largest tetromino, the I, is 4 long, this dictates a 4x4 = 16 cell block, and given there's 7 tetrominos, that's 112 bytes. Not so bad.

An idea for speeding things up came to me in the shower. Rather than printing the tetromino PCG character and colour every time I move it, let's just initialise the whole playing area on the screen with the correct PCG characters, and turn them on and off using colour. So a colour of 0 (black foreground and background) is empty, and other colours have blocks. This also made the test easier, as unoccupied cells are 0.

I played with that for a while and got movement happening, and even automated dropping. But it didn't look perfect, as my method of testing a tetromino can fit in a space requires me to erase the tetromino from it's old space first, perform the check, then paste the tetromino in, either in it's old position if the move didn't work or else in it's new position. That caused tearing on the screen due to the erase.

So then I moved a copy of the playfield to RAM, and did all my tests on that, and simply updated the screen (colour) RAM once every frame. Tearing gone, at the expense of a few hundred bytes to store my playfield copy.

The rest of the code is just doing the arithmetic to update row and scores, detecting and counting erased rows etc. The whole game is like 3K. It's tiny!

So it works. And not just on Freebee. It works on a Premium Microbee too, and under emulation using uBee512.

All my code, and the binary, is on my Google drive

Running it in uBee512 requires getting it into memory. uBee512 likes disk and tape files. This is just raw code. There's debug mode though, which allows you to insert arbitrary code into memory. So from the folder where your Tetris.bin file is loaded, start ubee512 emulating a Premium machine, get it into basic (either emulate a P85 model or run disk basic from the PCF one), and right click to get a console. In the console, type --db-loadm=2304,Tetris.bin. Kill the console, then execute Tetris from Basic with a=usr(2304).

Here's some screen grabs, courtesy of Ubee512:

I've also uploaded a video to Youtube, where you can listen to me blather about it while I'm playing it on my Freebee.

No comments: