零行迷宫:8位机大神的一行代码能教会我们什么
Zero Lines Maze: What the 8-Bit Guy's One-Liner Can Still Teach Us

原始链接: https://retrogamecoders.com/zero-lines-maze/

The 8-Bit Guy 最近分享了对经典 C64 “10 PRINT” 迷宫的独到见解,引发了对高效 8 位编程的深入探讨。虽然最初的一行代码使用 `CHR$(205.5+RND(1))` 来生成滚动迷宫,但该视频重点介绍了四种巧妙的优化技巧: 1. **“零增量”循环**:通过结合使用 `FOR...STEP 0`(由于计数器从不推进,因此会创建一个无限循环)和直接模式命令,无需行号即可生成迷宫。 2. **硬件随机性**:用 C64 的 SID 芯片(语音 3 噪声寄存器)代替缓慢的 `RND` 函数,可以提供高速、基于硬件的随机字节。 3. **查找表 (LUTs)**:与其在运行时实时计算逻辑,不如将输出预先计算到数组中,这样程序可以立即获取数据,从而节省大量的 CPU 周期。 4. **识别瓶颈**:The 8-Bit Guy 演示了性能优化的关键在于找到“实际”瓶颈。在这种情况下,速度受限于硬件滚动,这证明了汇编语言并不一定能提高性能。 这些技术是在受限硬件中榨取最大效率的教科书级示范,证明了简单而巧妙的技巧往往优于暴力破解。

抱歉。
相关文章

原文

What can we learn from 8bitguy’s version of the famous C64 BASIC random maze …?

Say what you will about the 8-Bit Guy, but he just put out a fantastic take on the famous one-liner maze program. Even though I have typed that one-liner more times than I can remember, it still inspired me to write this post today, decades after I first learned it.

Yep, the 8-Bit Guy, controversial as he is,  sent me down a proper several day rabbit hole. There are at least four genuinely useful tricks hiding in his final program, but his video does not have a written version from what I can tell, so let me take you through them here.

How the 10 PRINT Maze (Famous Version) Works

Here is the original:

  10 PRINT CHR$(205.5+RND(1)); : GOTO 10

Run that on a C64 and you get an endless, scrolling random maze. It looks like magic. It is actually one of the most elegant little hacks in 8-bit BASIC. Many people have “riffed” on it, which was probably best done by Robin.

The whole thing is based on this guy CHR$(205.5+RND(1)).

RND(1) hands you a float between 0 and 0.999, so the result lands somewhere between 205.5 and 206.499. CHR$ ignores the fraction, so you get character 205 or character 206, at roughly 50/50 odds. Those two codes are the diagonal PETSCII graphics, the / and \ lines.

Print one or the other at random, let the screen scroll, and the diagonals join up into a maze. As 8 Bit Guy says, it looks a bit nicer on the Vic 20 font because it joins up better.

There’s no logic so it fits on one line.  It’s a bigger deal than you would think, even today it is worth eliminating IF statements. This code shows you can fold a random binary choice into a single expression with zero branches, and combined with the C64’s habit of truncating floats, and a coin-toss is done for you.

It’s famous now but it was originally straight out of the manuals shipped with the C64 and the VIC-20 back in 1980s, which is where a lot of us grey beards first met it.

You can now follow the tutorials and edit the code right in your web browser with the Online Retro IDE

– No downloads, configuration, etc necessary, and it is free!

Random Maze 8Bit Guy Version –  *Zero* Lines!

The 8-Bit Guy’s first nerd flex is making it shorter than one line. What??

Two things go into making that work:

  1. You can run a FOR ... NEXT loop straight at the BASIC prompt (direct or REPL mode I guess in today’s speak), no line number needed. It will happily execute a whole loop.
  2. STEP 0 is legal, which means the counter never advances, so the loop never ends. I always assumed it would error so never tried it, d’oh!

  Put them together and you get an infinite maze with zero program lines:

  FOR A=0 TO 1 STEP 0:PRINT CHR$(205.5+RND(1));:NEXT

I have to say STEP 0 as a deliberate infinite loop is one of those things that feels like cheating the first time you see it. It is the kind of trick worth keeping in your back pocket similar to WHILE (1) in C.

Three Speed Optimisations

As if that wasn’t enough knowledge to drop, the second half is a speed build, and this is where there are even more nuggets of wisdom:

Random from the SID, not from RND.

RND is slow no matter how you call it. Voice 3 of the SID can be set to a noise waveform, and once it is running, the top oscillator register gives you a fresh pseudo-random byte every time you read it:

  POKE 54287,255 : POKE 54290,128 : REM voice 3 = noise

  PEEK(54299) ... : REM random 0-255, fast

  Reading a hardware register beats computing a float. Lovely example of using the chip you already have instead of the maths library.

Precompute with Lookup Tables

This will be more familiar to RGC readers, and that is LUTs or Lookup Tables.

Converting a number to its binary digits on the fly is expensive. So the program spends a moment at startup building a string that maps every value to its binary representation. After that, turning 42 into its bits is just an array lookup, with no calculations necessary. Precompute once, fetch quickly forever after. This pattern shows up everywhere from sine tables to colour ramps, and it is one of the go-to habits in optimising 8-bit work.

Swap the Table, Not the Logic.

Once you have a table that emits “0” and “1”, you can replace those two characters in the table with the two diagonal glyphs, or any character you like. Same approach, different output. Decouple the data from the loop and you can repurpose the whole thing by just editing a string.

Full Listing Based on 8 Bit Guy Approach

[Edit a copy of the code and see it in action over on my online retro IDE]

The main differences here are I set the text colour and show a visible indication that the program is working because otherwise it takes so long it might seem to have frozen!

10 POKE 53280,0:POKE 53281,0:PRINT CHR$(5)
20 DIM M$(255)
30 A$=CHR$(205):B$=CHR$(206)
40 FOR I=0 TO 255:S$="":BT=128
50 FOR J=1 TO 8
60 IF (I AND BT) THEN S$=S$+B$:GOTO 80
70 S$=S$+A$
80 BT=BT/2:PRINT "{HOME}";I:NEXT J
90 M$(I)=S$:NEXT I
100 POKE 54287,255:POKE 54290,128
110 PRINT M$(PEEK(54299));:GOTO 110

Hot Paths, Again

Here is the part I love. The 8-Bit Guy reckons his fast version is bumping against the KERNAL’s screen-scroll speed, not BASIC’s, so even rewriting it in assembly probably would not help by much.

That is the whole optimisation game in a nutshell. Find the real bottleneck before you reach for the big hammer.

He profiled (“profiled”, but still) and discovered the limit was the hardware scroll, not the interpreter. Plenty of people would have pulled out the ASM based purely on assumption.

Bottom Line

So, there you have it, four solid takeaways from one line of BASIC.

If you haven’t already, go watch the video, it is a quick one and well worth ten minutes.

联系我们 contact @ memedata.com