Tritris

Rules

You may have heard of a game called TETRIS, this is a 3-line remake of it.

Drop the pieces down; the lines which are completely filled disappear. You may rotate a piece with "up" arrow key.





Code and comments

I did not want to use the original TETRIS figureset (which consists of all tetrominoes) to avoid being yet another exact tetris clone. Pentominoes are too irregular and will crowd the place pretty quickly, triminoes are too few and too easy to fit, so I tried a set of all "pseudo-triminoes" – 3 square blocks where squares are connected on an edge or a vertex. There are 6 different shapes (5 if you consider mirror images the same). They are quite a bit easier to fit than tetromimoes, but not exactly trivial.

For speed of execution I wrote the game in assembler. There are 768 bytes in 3 lines, but some of it has to be wasted on overhead, so, let's say we have about 500 bytes left. You can write a lot in 500 bytes of assembler, so implemeting the game mechanics was not too difficult. The challenge lied in encoding it in a way that does not waste to much space when in BASIC form.

So, I encoded it by setting MSB in each byte and saving that high bit of seven consecutive bytes into another byte with high bit already set. When encoded this way, all bytes are printable characters and can be entered in string variables directly.

Now, when you write something like A$="TEXT" in MSX BASIC, it will not allocate string variable, instead it will reference A$ to a location inside program code. When you perform string operations, it will allocate space in a special "string storage" area and copy the bytes there. This is what +"" is doing, it forces the string values into the string storage area. The size and location of the string storage area is controlled by CLEAR operator. First argument is the size of a new storage area. The second argument is the beginning of user subroutines area, guranteed to be not used by BASIC. The string storage is tucked right before the user area. Sort of. There may be a file descriptor area in between, so I do MAXFILES=0 to get rid of it for sure.

One last piece of the puzzle is a subroutine that decodes the program before execution. It reads MSBs and writes them to their appropriate location. This routine is also written in assembler and tucked in the same string variables. There is one trick though. It has to be written using only the commands that are represented by printable characters.