Ive been wanting to create my own version of digital rain for some time. The effect is well known from the Matrix movies, which used florescent green characters. Inspired by that version, I decided to go retro and generate a black and white stream of characters using the ZX81. Let the geekiness begin.
Wait, what is all this?
Turn in your nerd badge if you havent watched the Matrix. I mean, its like a revamped Ghost in the Shell. Sticking with me, then skip down. Still no? Go watch it. Are you listening? Go! Ill wait. Are you still here? Seriously, go watch it!
Okay, done? Good.
Now lets continue.
This ZX81 version isnt going to replicate the green flow of phosphorous digits in the Matrix. But, it can still make for a neat effect. Black on white is good enough, especially on an old TV. Scan lines just make it all the more interesting. The effect can be almost eerie. It isnt quite the same in an emulator, but still good enough.
Ive been running my version for the last day and it is quite mesmerizing. The randomly changing digits are subtle, adding to the effect. The screen is never full, with an ever changing pattern of numbers, letters, and symbols. Its not perfect, but it works well.
Very, cool. Howd you do it?
Writing a new ZX81 program on a computer that is almost 37 years old is, well, crazy. Yet, it is also quite freeing and fun. I love the simplicity of the BASIC language. Sure, its not the prettiest, but it gets the job done. I started, like I often do, by thinking about the problem.
My mind started first with the rain. I wanted to print a random letter, moving down the column. At some point, I would then erase from the top of the screen, dropping the letters until the column is clear. Once I had a clear plan in my mind, I started thinking about how to tie the columns together.
Sticking with simple, I started with an array that would represent the falling rain. I didnt want a lot of branching logic, so I created an infinite loop. The loop started by choosing a column, checking the array, and, if the column was empty or 0, I would set it to 1.
The next step was a
FOR loop that walked the entire array. If the column wasnt empty, I would branch to an array that would print rain. Otherwise, it skipped to the next column. Once done, the routine started over. A forever ending digital rain.
Lets print some rain.
The rain routine is actually two functions. If the column holds a positive number, the program would print a new letter. The index is then incremented until it reaches the bottom of the screen. At that point, it is set to a negative number.
If the index is negative, I branch to another routine that erases the rain from the top down. The effect is complete and looks pretty cool. At this point, I had a working version of digital rain.
Although the BASIC version works, it is a bit slow. Even at the start, I envisioned using MCODER to compile the program into a faster version. I did that right after getting a working basebefore adding the random letters.
One of the advantages of using an emulator is that loading ZX81 programs is faster than tape. It took about five minutes to convert it. I launched MCODER, loaded the BASIC program, made the required changes, and compiled it.
Lets tweak things a little.
Although I had a working version, it didnt quite look right. I two print routines that flashed a highlighted letter at the start. I like the effect, but, the way I processed the columns exposed a pattern. The flash would move from left to right as I checked each column. Not what I wanted. I cut the feature to focus on the random letter routine instead.
That routine took a bit more work than expected. I started with the idea that I would select a random number based on the current value of the index. The hope was to create a version that would be a single line of code. Although I got that to work, it was complex and I doubted it would compile using MCODER. So, I rethought the problem.
The next version stuck to an old favorite. I selected a location, then checked if something was already there. If yes, change it. No, I skipped it. This worked well, but was a bit slow. So, I added an another check o reduce how often I would change a character.
The program was complete. I compiled it, added a save routine, and set it to run the machine code at start. The only thing left was to grab a screenshot and write this article.
Thinking bigger, but not better.
That doesnt mean it is perfect. Even while writing it, I wondered if I should have used two arrays. The thought is the second array would hold the last character printed. I could then reintroduce the highlighted character. But, it would stay on the screen longer.
To get rid of the the static pattern, I also thought about creating another array. That one would hold a random order of updating the columns. Im sure it would work, but would add a bunch more code. I abandoned both thoughts as they were too complex, and I didnt think they would add much.
The last idea was to vary the rain, using an array to hold a different starting or ending position. This would add some veriaty to the rain. Yet, after seeing the current version, I dont think it would look as good. Plus, I supposed it run much slower. Again, not worth it.
In the end, the final program is 29 lines of code. Five of those lines arent required, dropping the final count to 25 lines. Six of those lines are the random letter routine, but it doesnt add a lot. Dropping it would leave 20 lines of core code.
Sometimes simplest is the best.