Getting Creative with Custom Print Formatting on the ZX81
Explore my journey crafting custom formatting on the ZX81, including emulating the PRINT USING command.
My ZX81 programming has taken a back seat of late as I focused on other activities. Whether family, work, or the latest video game update, I haven’t put as much effort into finishing projects. For this month, I decided to focus on tackling an interesting problem, emulating the PRINT USING
command.
# Emulating the print formatting.
Since the ZX81 doesn't have a formatting command, I decided to emulate one. In the post I read, the user used a format like the following:
50 PRINT USING "### ##.##### ##.##### ##.#####"; I, XA, XS, XC;
Now this type of formatting isn’t unfamiliar to me, having used it many other languages including quite a bit in Perl. It is great for getting numbers to print the way you want them to, something I wish the ZX81 did have.
Since it doesn’t, the first thing I had to do was figure out some way to emulate that line. I landed on using a string that holds both the formatting and the variable. I could then tease apart the string to generate the line of text. Here is what my version of that line looks like:
80 LET U$="NNN NN.NN NN.NN.I,XA,XS;"
90 GOSUB 200
Two things. First, the ZX81 also doesn’t have a hash or number symbol. I used N instead. Second, the period is inverted after the format to denote the end of formatting. Any character not for formatting will be printed as is. Thus, the spaces are printed in this string. The variables follow and end with a semicolon.
# Making it work.
Once I had the basic idea, I converted the example program from the post into something that would work on the ZX81. First off, the screen sizes were different. This necessitated adjusting the final output. I wanted to keep the sine curve, so I fit it into the right hand side and shrunk the formatting.
Print Using Emulation , ZX81 Screenshot, 2024 by Steven Reid
This looked pretty good with just my test data, but I still needed to make the routine itself work. That took quite a bit more effort.
To start, I parse the variables out of the line. I know, this is backwards, but I need them to be able to do any work. I simply skip to the inverted period and then parse out the variable names. I do that by building a sting with each character until I reach a comma or the semicolon. Fortunately, the ZX81 makes it easy to then convert that variable to a value using the VAL
command.
After I have all the variables, I then walk the formatting command in a similar fashion. If I find the letter N, I start counting the number until it reaches a period or another letter. Once I do, I print the integer of the number with any leading spaces. Here is the snippet that prints that. Note I removed the line breaks to make it more readable.
820 LET V$=STR$ INT V(VAR)
830 PRINT " "( TO INT-LEN V$);V$;
If a period is hit, I work then on the factorial formatting. Now, I did have to work around how the ZX81 prints floating point numbers. Seems that it sometimes prints the leading zero, and other times not. Also, the factorial can be shorter or longer than the formatting. As such, it was a bit more complicated to print.
850 LET V$=STR$ (V(VAR)-INT V(VAR))
851 IF LEN V$>1 AND V$(1)="0" THEN LET V$=V$(2 TO )
852 IF V$(1)="." THEN LET V$=V$(2 TO )
855 IF LEN V$>INT THEN LET V$=V$( TO INT)
860 PRINT V$;"00000000"( TO INT-LEN V$);
Again, I removed line feeds to make this a bit more readable. I made extensive use of the string slicing abilities of the ZX81 to deal with leading spaces and trailing zeros.
# Not the prettiest code.
My main goal was to solve the problem. As such, the program isn’t as elegant or optimized as I would like. The routine works fine, but I probably could reduce the code size and remove some of the redundancy. I’m also sure that the actual command has additional features I didn’t emulate.
In either case, though, the program works as designed. It has some flexibility to it and shows that even in as limited a computer as the ZX81, you can still make it do interesting things.