Tackling the Logiker 2023 Vintage Computing Christmas Challenge – part 2

See also: part 1, part 2, part 3 and part 4.

As I write this, I have no idea how to make this work. Producing this pattern:

   *     *     *
* * * * * *
* * * * * *
* * * *
* * * * * *
* * * * * *
* * *
* * * * * *
* * * * * *
* * * *
* * * * * *
* * * * * *
* * *
* * * * * *
* * * * * *
* * * *
* * * * * *
* * * * * *
* * *

…seems like it should be simple. Three asterisks, then six, then six, then four, then six, then six, then three… Spaces that go five, three, one, zero and then back up. Unhelpful.

But, it’s also just one pattern repeated across the screen three times…

   *
* *
* *
* *

And then it’s reversed, so I think if we can do the above, we can do the whole pattern. We see spaces of three, two, one, zero on the left, and zero, one, three, and five in the inside.

Color BASIC does not have a SPC() option (my VIC-20 did, I think) for outputting spaces, but TAB() will go to a specific column. Maybe we can figure out which column the asterisks should be in:

.........1111111111
1234567890123456789
* * *
* * * * * *
* * * * * *
* * * *

This gives us 4, 10 and 16. Then 3 and 5, 9 and 11, and 15 and 17. Then 2 and 6, 8 and 12, and 14 and 18. Finally, 1 and 7 and 13 and 19. I don’t know why, but I kind of like thinking about it as tab positions.

10 FOR SP=3 TO 0 STEP-1
20 PRINT TAB(SP);"*";TAB(6-SP);
30 IF SP<3 THEN PRINT "*";
40 PRINT
50 NEXT

That would give us one of the pyramid shapes. To complete the bottom, we’d do another FOR/NEXT loop. At least, that’s what I would do. BUT, in a comment to part 1, Jason Pittman had a smarter idea:

Awesome! I’ve got an idea on this one but I’m not going to jump ahead this year and I’m just going to follow along.One thought here is that you could combine the two print loops on 100 and 110 by coming up with a series that goes “0 1 2 3 2 1”. I did it by replacing 100 and 110 with this: “100 FOR A=-3 TO 2:PRINT A$(ABS(ABS(A)-3)):NEXT”

Or, you could shorten that a little if you reverse the direction of the array (so that it looks like “VVV”) and use “100 FOR A=-3 TO 2:PRINT A$(ABS(A)):NEXT” – Jason Pittman

I could print one diamond like this:

10 FOR A=-3 TO 3:SP=ABS(A)
20 PRINT TAB(SP);"*";TAB(6-SP);
30 IF SP<3 THEN PRINT "*";
40 PRINT
50 NEXT

That prints almost the entire diamond, except for the final asterisk. Because, if I wanted to print three of them, I’d do this in a loop, then print the final asterisk row at the end.

Unfortunately, as I start going down this rabbit hole, I find the code of loops and such ends up looking larger than some much simpler approaches, like one shown to my by Rick Adams. His code was written for a PDP-8 BASIC, which lacks things like ELSE and MID$. His technique was to have strings representing parts of the pyramid:

"   *  "
" * * "
" * *"
"* "

…then to print each string three times across the screen. This produced:

"   *     *     *  "
" * *  * *  * * "
" * * * * * *"
"* * * "

…and then do it backwards. There is a missing “*” on the right, that gets printed with an “IF”. In a chat, we bounced around some ideas to shrink the code, but looking at his approach, it seems everything I try to do gets larger:

  • Try “run length encode” where DATA statements represent the spaces. Print that many spaces, then an asterisk, and repeat.
  • Try DATA statements showing the positions of the asterisks. DATA is large than a string.
  • Try simulating a “SET(x,y)” to draw it, but using PRINT@ on the CoCo. Alas, the CoCo 32×16 screen is too small to fit the whole pattern, so even if this was smaller, it would still require extra code at the end to scroll the screen and print the final few lines (as the top portion scrolls off). BUT, using a CoCo 3 40/80 column screen would work using LOCATE x,y instead. But still, larger.

Is there an elegant solution to this challenge that doesn’t involve just PRINTing strings?

We shall continue… Next time…

15 thoughts on “Tackling the Logiker 2023 Vintage Computing Christmas Challenge – part 2

  1. Sean Conner

    One thing I noticed—you have three asterisk separated by five spaces, printed twice for each line. The first line both are printed at the same horizontal position; the second line offset from each other, and so on, then the process reverses.

    The version I settled on uses a bit mask to alternate between spaces and asterisks (since I’m doing this in assembly) and that is the shortest version yet.

    Reply
  2. Jason Pittman

    This is the last attempt I came up with. It uses the same “-3 to 2 … ABS()” from the other example I sent on part 1. I think one potential trick here is to treat it as if you are holding a rubber stamp that stamps out three asterisks that are six spaces apart. You want to make this pattern by stamping it twice on each line. You’re keeping track of a starting position on each row (1027 + 32 for each row) and an offset to add and subtract to the starting position for each row. On the first line, the offset is zero, so you stamp it twice on top of itself at the starting position. On the next line, the offset is 1, so you stamp it twice, but one time you add -1 and the other time you add +1 to the starting position. Does this make any sense?

    1 CLS:P=1027:FORC=1TO3:FORX=-3TO2:FORS=0TO12STEP6:POKEP-3+ABS(X)+S,106:POKEP+3-ABS(X)+S,106:NEXT:P=P+32:NEXT:NEXT:GOTO1

    Reply
  3. Jason Pittman

    Yea, it’s a bummer that these patterns tend to inadventantly “stack the deck” against doing them on a CoCo. In that example, I’m just POKEing into addresses that are outside of the text screen for the last few rows, and it doesn’t seem to crash it, so I just pretended that it was showing the whole pattern.

    Reply
      1. Jason Pittman

        I may play around with LPOKE. This should get it on the 40 column screen. I bet there is a crafty way to (a) not do the last line manually outside of the loops (b) remove one of the FOR loops (c) Shoot, there’s probably some crafty wizard way to do it in one FOR loop with logical operators, but I wouldn’t ever find it.

        1 WIDTH40:FORZ=0TO12STEP6:FORX=-3TO2:FORS=0TO12STEP6:LOCATEABS(X)+S,Z+X+4:PRINT”“;:LOCATE6-ABS(X)+S,Z+X+4:PRINT”“;:NEXT:NEXT:NEXT:FORX=3TO15STEP6:LOCATE X,19:PRINT”*”;:NEXT

        Reply
        1. Jason Pittman

          Eh. It butchered it when I pasted it. Will it let me do a markdown code block? Let’s see…

          1 WIDTH40:FORZ=0TO12STEP6:FORX=-3TO2:FORS=0TO12STEP6:LOCATEABS(X)+S,Z+X+4:PRINT"*";:LOCATE6-ABS(X)+S,Z+X+4:PRINT"*";:NEXT:NEXT:NEXT:FORX=3TO15STEP6:LOCATE X,19:PRINT"*";:NEXT

          Reply
  4. Jason Pittman

    Here’s another rather inefficient approach:

    10 WIDTH 40
    20 FOR S = 3 TO 33 STEP 6
    30 FOR X = 0 TO 18
    40 IF S + X < 19 THEN LOCATE S+X,X:PRINT "*";:LOCATE X,S+X:PRINT "*";
    41 IF S - X >= 0 AND S - X < 19 THEN LOCATE S-X,X:PRINT "*";
    50 NEXT X
    60 NEXT S
    70 GOTO 70

    Reply
    1. Jason Pittman

      Oops…it should be starting the S loop farther back so it only has to have one PRINT on line 40. Is there some wizardry to do this with a single PRINT statement?

      10 WIDTH 40
      20 FOR S = -15 TO 33 STEP 6
      30 FOR X = 0 TO 18
      40 IF S+X < 19 AND S+X >= 0 THEN LOCATE S+X,X:PRINT "*";
      41 IF S-X >= 0 AND S-X < 19 THEN LOCATE S-X,X:PRINT "*";
      50 NEXT X
      60 NEXT S
      70 GOTO 70

      Reply
  5. Jason Pittman

    Merry Christmas! Here’s one more CoCo 3 attempt that I came up with. This one just pecks it out randomly. Basically, X and Y are the center point of one of the nine diamonds, chosen at random. RX is a random X offset (-3 to 3). RY is RX adjusted to be the number of horizontal spaces needed for the vertical offset (Like…one line above the diamond center the asterisk needs to be offset +/- 2 spaces horizontally, 2 lines above center needs to be offset 1, etc) and D is a random -1 or 1 that determines if the asterisk is drawn above or below the center point. It’s fun to watch, while also being the slowest way imaginable to achieve the goal.

    0 WIDTH40
    1 X=RND(3)*6:Y=RND(3)*6:RX=RND(7)-4:RY=ABS(RX)-3:D=RND(2)*2-3:LOCATE X+RX,Y+RY*D:PRINT"*";:GOTO 1

    Reply
    1. Allen Huffman Post author

      I really like this one, though I need to dissect it to understand the maths. This is quite small! And I think WIDTH 40 could be left out, and just say “run from a 40 column screen”. Then you could rename to 0 and just say “GOTO” and the end and save another byte.

      Reply
  6. Pingback: Tackling the Logiker 2023 Vintage Computing Christmas Challenge – part 3 | Sub-Etha Software

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.