A small BASIC Contest was held from 13.8.2019 until 18.8.2019. The contest originated from an assembler contest by Nurpax (see Twitter and github) and was adapted for BASIC.
A PRINT-only version "compo" was held afterwards until the 24.8.2019.
Same rules as above, but additionaly:
In order not to reveal the code, first only a checksum (md5sum) plus the program size in bytes had to be anonunced. The code was revealed after the deadline only. (If you had a bas-file for CBM prg Studio, it was welcome too.)
Submissions were to be made here: Twitter or Forum64.de.
Bytes* | Programmer |
---|---|
68 | Atomcode (f64) |
75 | TNT/BF (aka Corporal Jonlan) |
76 | Logiker |
79 | YPS (f64) |
80 | wizball6502 (f64) |
? | Holy Moses/Role (f64) |
* regular size of file in bytes without truncating (which is CBM prg Studio + 4)
2019?"♥":fOX=2TO81:pO54238+X,.:pO982+aB(26-INT(5/8*X))*40+X,160:nE:wA.,.
0 print"{clr}":forx=2to41:y=982+int(x/5*{pi})*40:pokey+x,160:pokey+43-x,160:poke53278+x,0:next:cont
0pO53280,0:pO53281,0:?"{clear}":fOi=-39.5to40:pO4^5+i+abs(int(5/8*i)*40),160:nE:wait1,0
1 ?"{clear}":fOx=.5to40:pO53280+x,0:a=4^5+int(x*5/8)*40:pOa+x,160:pOa+40-x,160:nE:wA1,0
0 print"{clear}"
1 fori=0to41:poke53280+i,0:poke982+o+int(i*.625)*40+i*(1oro>0),160:next:o=43:goto1
The PRINT-only version was mainly for fun. Here is what the participants delivered:
0 forc=17to145step128:fori=7to45:poke53268+(iAND1),0:print"{reverse on}{space}"left$(chr$(c),91and2^(iand7));:next:print"{left}{insert}{space}{up}{right}";:next:cont
0 print"[clr,blau]":poke242,.:a$(1)="[links] [links]":a$(.)="[revers,links,links] [links,links]":a$="[runter]
1 fori=.to29step1.2:poke53280+i,.:printa$(iand1)a$;:next:a$="[hoch]":goto1
10 poke53280,0:poke53281,0:?"{clear}{reverse on}";:fori=0to3:x$="{down} {down} {down} {down} {down} ":?x$" ";:next:?x$"{left}{148} {up}{right}";:fori=0to4:?" {up} {up} {up} {up} {up}";:next:cont
2019?"♥":fOX=2TO81:pO54238+X,.:pO982+aB(26-INT(5/8*X))*40+X,160:nE:wA.,.
• Dem Algorithmus liegt die Überlegung zugrunde, beide Diagonalen zusammen als nur eine zu plottende Funktion zu behandeln, die 80 Zeichen breit ist, 26 Zeichen hoch und einer Dreieckkurve entspricht, und zwar von 0/24 nach 39/0 aufsteigend und dann von 40/-1 nach 79/23 wieder absteigend, wobei das Wrapping der theoretischen 80-Zeichen-Zeile auf 40 Zeichen dafür sorgt, dass der absteigende Teil um 1 weiter unten (-1 bis 23 => 0 bis 24) und 40 weiter links (40 bis 79 => 0 bis 39) geplottet wird. Es wird dabei keine Speicherzelle außerhalb des Bildschirmspeichers überschrieben.
Anders gesagt: Eine Gerade, deren oberer rechter Teil nach unten gespiegelt und nach links verschoben wird. Siehe Bild.
FOR X=2 TO 81:POKE 982+ABS(26-INT(5/8*X))*40+X,160:NEXT
• Die Rechen-Basis (982) ist etwas kleiner als der Ursprung (1024) gewählt und wird durch leicht erhöhte Koordinaten ausgeglichen.
• Die Nulllinie ist unten. Das aktuelle Y (die Zeile) wird berechnet, indem X mit der Steigung 5/8 multipliziert wird, fängt also bei 1 an (2*5/8). Das wird von 26 Zeilen abgezogen (25 echte Bildschirmzeilen plus einer gedachten wegen der kleineren Basisadresse), dann mal Zeilenbreite 40 genommen und zur Basisadresse 982 addiert, sodass die erste Zeilenadresse-2 die unterste ist. Das X selbst kommt für den Plot natürlich noch dazu, fängt mit 2 also genau auf der Zeilenadresse an. Das INT() ist notwendig, weil wir für Y Vielfache von 40 brauchen und nichts dazwischen.
• Wenn wir oben angekommen sind und das als Term errechnete Y >= 26 wird, wird das X >= 42, sodass dann das Wrapping greift (982+0*40+42=1024). Die ABS-Funktion entfernt das Vorzeichen der Zeilenberechnung und sorgt so dafür, dass die errechnete Zeile nicht Richtung Zeropage geht, sondern wieder größer wird. Bei X=81 und Y=|26-5/8*81|=24 ist Schluss: 982+24*40 ergibt Zeilenadresse-2 von Zeile 23. Plus die 81 aus X ergibt Spalte 39 in Zeile 24.
• Die Rahmen- und Hintergrundfarbe wird auf schwarz gesetzt, indem ab der letzten Spiegelung der entsprechenden VIC-Adressen Nullen geschrieben werden. Die letzte Spiegelung wurde gewählt, damit keine wichtigen Steuerregister des VICs verändert werden. Es wird lediglich der SID gelöscht.
• WAIT.,. wartet, bis der Inhalt der Adresse 0 mit 0 AND-verknüpft ungleich 0 wird und damit für immer. Lässt sich mit Stop+Restore abbrechen. Die 2 Byte kürzere CPU-Jam-Alternative ist SYS7, ruft aber beim VICE-Emulator den Debugger auf.
0 print"{clr}":forx=2to41:y=982+int(x/5*{pi})*40:pokey+x,160:pokey+43-x,160:poke53278+x,0:next:cont x starts from 2 instead of 0 to get the slope starting from wanted position. Base address is screen start -42 to offset the x starting from 2. Pi is in the calculation because it's used too seldom :) Current line is rendered mirrored. Colors are set by poking into VIC II registers inside the loop. Cont is nice enough to continue from itself. For completeness: conditional scroll, mimicking the winning assembler solution. 79 bytes. 0 forx=0to41:poke214,23+z/8:print:z=(zand7)+5:poke1982+x,160:poke2025-x,160:poke53280+x,0:next:cont x does two loops too many so that we have correct z value at "x=2". poke 214 controls the scrolling - we scroll only when z >= 8.
Meine Version ist ähnlich jener von atomcode , nur etwas länger. Aber sie sollte auch viel leichter verständlich sein.
0 forc=17to145step128:fori=7to45:poke53268+i,0:print"{reverse on}{space}"left$(chr$(c),91and2^(iand7));:next:print"{left}{insert}{space}{up}{right}";:next:cont We print two lines, the first one going downward and the second one going upward. Vertical direction is controlled by variable C which holds character code for petsdcii {down} or {up}. Variable I counts 39 iterations, one less than width of screen. Starting from 7 instead or 0 (or 1) is explained below. POKE command sets screen colors, nothing fancy there. PRINT command first prints reverse space. Then it may or may not print the vertical movement, controlled with the second argument of LEFT$() function. We want it to be at least 1 when we need a vertical move. We do that by extracting bits from a byte-sized immediate value. The sequence from left to right is 0, 1, 1, 0, 1, 1, 0, 1 which then repeats. Because the least significant bit is on the right, that needs to be reversed and we get binary value 10110110, 182 in decimal. As we can decide the I index freely without affecting size of the program, we rotate bits seven times to left to get value 01011011, 91 in decimal. That saves one byte. After the inner loop completes, we move cursor left, print {insert} to move previously printed reverse space to bottom right corner without scrolling the screen. Then we print the last space and move {up} and {right} to position the cursor for the second line. And as always, we end with CONT to halt the program. Note: as PRINT CHR$(0) does nothing, you can replace LEFT$(CHR$(C),XYZ) with CHR$(C*XYZ). That however requires XYZ to be either 0 or 1, which usually means you need to wrap it in SGN() or INT(). Doing that results in equally sized binary. BONUS: 85 byte version using RND() 0 forc=17to145step128:fori=0to38:poke53280+i,0:print"{reverse on}{space}"left$(chr$(c),rnd((iand7)-.5)*2);:next:print"{left}{insert}{space}{up}{right}";:next:cont
It needs to be 53280+(iAND1), so my shortest program is 86 bytes.