See also: part 1, part 2, part 3 and part 4.
If I would have told my teenage-self that one day I would be corresponding with Radio Shack ROM-Pak game programmer, Rick Adams, I would have not believed myself. Rick became a very well known name in the CoCo community, and I remember seeing his name in the title screen of Radio Shack ROM-Paks. Temple of ROM was one I played at Radio Shack, but never owned. I just recall thinking it was like a fancy version of my all-time favorite Atari VCS game, Adventure.

But I digress…
It started with a message containing a screen shot:

Rick had simplified the program by breaking up the pattern in to sections he could GOSUB to and print a few lines. It was simple, and smaller than printing the whole thing.
“Why line 2046?” I asked. Apparently, the PDP-8 BASIC he was using had that as the highest line number. This was one of many restrictions this version of BASIC had. Through our chat, I learned it had a limit to the length of a string, and could not do things like MID$(A$,1,1)=”A” which were methods I had been toying with.
The next thing he sent me was optimizing this pattern further, breaking it up in to just one part of the diamond shape:
1 DIM A$(4)
10 FOR I = 1 TO 4
20 READ A$(I)
30 NEXT I
40 FOR I = 1 TO 4
50 PRINT A$(I);A$(I);A$(I)
60 NEXT I
70 FOR I = 3 TO 1 STEP -1
80 PRINT A$(I);A$(I);A$(I)
90 NEXT I
300 DATA " * "
301 DATA " * * "
302 DATA " * *"
303 DATA "* "
2046 END
This proof-of-concept code worked by loading this pattern in to an array. It can print the top array string three times across the screen, then continue through the pattern. Then, for the reverse diamond, print the array backwards. This version was clever, though it left off the right-most asterisk of the bottom/middle row, which could be handled by adding an extra IF/PRINT for those lines. Neat!
But, even when packing everything together (the PDP-8 BASIC has its own way of combining lines using a backslash), it did not look like it would be the smallest approach to this challenge.
A bit later, I received this screen shot:

This, my friends, is what a programmer comes up with when they are tired of typing in Microsoft BASIC. Rick has a front-end (pre-processor?) that allows him to write nicely readable (for BASIC) code and then have it converted to Microsoft BASIC for loading on a CoCo.
I typed that in (well, not literally) to a CoCo and saw that it worked. But what is it doing? Let’s look at a packed CoCo version of this code he provided (adjusted to work on the 40 column screen):
1 WIDTH40:GOSUB2:FORK=1TO3:FORI=1TO3:GOSUB2:NEXTI:FORI=2TO0STEP-1:GOSUB2:NEXTI:NEXTK:END
2 A$=STRING$(20,32):FORJ=4TO16STEP6:MID$(A$,J-I)="*":MID$(A$,J+I)="*":NEXTJ:PRINTA$:RETURN
This looks like a similar approach that Jason Pittman had mentioned he was working on — drawing the pattern as if it was two asterisks that just get further apart as they move down the line (then closer together as it continues).
Rick’s version appears to work by starting with an empty string – generated using the STRING$(20,32) for a string of 20 CHR$(32) spaces. As it goes forward through the loop, it changes the character in the string at position J+I to be an asterisk, then the character at position J-I to be an asterisk . At the top/bottom of each diamond, the offset is 0, so it is just putting the asterisk on top of itself.
Let me break this apart, closer to his original pre-preprocessed source. I will put some extra spaces in to space out the loops:
1 GOSUB 100
2 FOR K=1 TO 3
3 FOR I=1 TO 3
4 GOSUB 100
5 NEXT I
6 FOR I=2 TO 0 STEP -1
7 GOSUB 100
8 NEXT I
9 NEXT K
10 END
100 A$=STRING$(20,32)
101 FOR J=4 TO 16 STEP 6
102 MID$(A$,J-I)="*"
103 MID$(A$,J+I)="*"
104 NEXT J
105 PRINT A$
106 RETURN
Line 100 – The subroutine creates an A$ of 20 space characters.
Line 101 – The FOR loop of 4 TO 16 STEP 6 will produce values of 4, 10 and 16. That matches the top spacing of the peak of the diamond shapes in the pattern:
.........11111111112
12345678901234567890
* * *
* * * * * *
* * * * * *
* * * *
Line 102 – at position J-I (I is set by a FOR loop before it GOSUBs to this routine) will be places an asterisk at that location inside the A$. The outer FOR I loop is 1 TO 3, calling this routine each time, so it would look like this:
I=1, J=4, 10, 16 (producing 4-1, 10-1 and 16-1 ... 3, 9 and 15).
"..*.....*.....*....."
I=2, J=4, 10, 16 (producing 4-2, 10-2 and 16-2 ... 2, 8 and 14).
".*.....*.....*......"
I=3, J=4, 10, 16 (producing 4-3, 10-3 and 16-3 ... 1, 7 and 13).
"*.....*.....*......."
Line 103 – this line does the same thing, but uses the position of J+I so the asterisk moves to the right each time:
I=1, J=4, 10, 16 (producing 4+1, 10+1 and 16+1 ... 5, 11 and 17)
"....*.....*.....*..."
I=2, J=4, 10, 16 (producing 4+2, 10+2 and 16+2 ... 6, 12 and 18)
".....*.....*.....*.."
I=3, J=4, 10, 16 (producing 4+3, 10+3 and 16+3 ... 7, 13 and 19)
"......*.....*.....*."
Since these two lines are adding asterisks to the same A$, the results actually look like this:
"..*.*...*.*...*.*..."
".*...*.*...*.*...*.."
"*.....*.....*.....*."
Line 104 – is the NEXT for the FOR/J, so it goes through all three entries (4, 10 and 16).
Line 105 – prints the modified string.
Line 106 – returns back to the main code.
You will notice that calling this routine like this misses the top line. Let’s look at the start of the program to see how it gets there:
Line 1 – This initial GOSUB to 100 is what draws that top line. When the program starts, all variables are zero. So the routine enteres with I set to 0, which would make J+I and J-I just be the J value, putting an asterisk at the 4, 10, and 16 positions:
"...*.....*.....*...."
Well. That’s clever.
Line 2 – This is just a FOR loop to draw the pattern three times.
Line 3 – This is the FOR loop that draws the top part of the diamond, but since I always starts at 0, it doesn’t draw the “top” row — that was done by LINE 1, and then when it draws the reverse/bottom of the diamond it will finish that pattern, which is the last row and start of the next diamond. (Confused yet?)
Line 4 – Draw the line for the top part of the diamond (inside the I loop of 1 to 3).
Line 5 – This is the NEXT for the top-to-bottom I loop.
Line 6 – This is a second I loop, that goes from 2 to 0.
Line 7 – Calling the GOSUB routine, so now it will be drawing like this:
I=2, J=4, 10, 16 (producing 4+2, 10+2 and 16+2 ... 6, 12 and 18)
".....*.....*.....*.."
I=1, J=4, 10, 16 (producing 4+1, 10+1 and 16+1 ... 5, 11 and 17)
"....*.....*.....*..."
I=0, J=4, 10, 16 (producing 4+0, 10+0 and 16+0 ... 4, 10 and 16)
"...*.....*.....*...."
And the second part of the GOSUB doing the right side of the pyramid shape:
I=2, J=4, 10, 16 (producing 4-2, 10-2 and 16-2 ... 2, 8 and 14)
".*.....*.....*......"
I=1, J=4, 10, 16 (producing 4-1, 10-1 and 16-1 ... 3, 9 and 15)
"..*.....*.....*....."
I=0, J=4, 10, 16 (producing 4-0, 10-0 and 16-0 ... 4, 10 and 16)
"...*.....*.....*...."
Together, the strings end up as:
".*...*.*...*.*...*.."
"..*.*...*.*...*.*..."
"...*.....*.....*...."
And that draws the bottom of the diamond!
Line 8 – The NEXT for the I (bottom of diamond) loop.
Line 9 – The NEXT for the “do it three times” loop.
Line 10 – END, so it won’t try to run the subroutine again.
Wow, that’s cool.
What do you think?
More to come…?
This is great! This is the direction I was going, but it didn’t occur to me that it would work better to just build a string of spaces that is already the width of the screen and MID$ the asterisks where they need to be.
I have not looked at compressed versions of each to see which one is smaller.
I did this with assembly language and got the executable down to 81 bytes. I did a similar thing to Rick’s program, although I used a bit mask to indicate where to print a space (a ‘0’ bit) and an asterisk (a ‘1’ bit, and there were enough bits left over for each line to center the image).
Do you mean, like representing the pattern using 0’s and 1’s of bytes?
Are you putting data on the screen, or calling some ROM routine to output like PRINT does?
To your first question, yes. It looks like:
stars fcb %00000001,%01000101,%00010100
fcb %00000010,%00101000,%10100010
fcb %00000100,%00010000,%01000001
fcb %00000010,%00101000,%10100010
fcb %00000001,%01000101,%00010100
top fcb %00000000,%10000010,%00001000
(hopefully, that’ll come out) The label top is printed first, then three copies of the data labeled by stars.
Second, I’m calling [$CHROUT] for character output. I did come across the video with the results (https://www.youtube.com/watch?v=RGv2u6epVTY) and the smallest assembly version was around 40 bytes I think. Pretty wild stuff.
I had zero ideas on this one – everything I tried was just larger. I expect the smallest ones made use of some kind of pattern, rather than encoding the image. Did you enter?
No, I did not. I didn’t feel like I needed Yet Another Account.
Was your asm for the CoCo? Would you be willing to let me share it in a blog post?