La sfida di Natale, edizione 2023

Logiker ha appena presentato i risultati dell’edizione 2023 della Vintage Computing Christmas Challenge (VC³ 2023), un’interessante concorso non competitivo di programmazione, orientato principalmente ai sistemi vintage, che si svolge nel periodo natalizio.

L’obiettivo è la realizzazione di un programma in grado di rappresentare fedelmente la seguente immagine, utilizzando un codice più compatto possibile:

Screenshot dell'immagine da realizzare per la Vintage Computing Christmas Challenge 2023
L’immagine da realizzare per la Vintage Computing Christmas Challenge 2023

I partecipanti sono stati più di 200 (Logiker ha condiviso tutte le entry su Google Drive, demozoo.org e scene.org; consulta la homepage per ulteriori link e dettagli) e, oltre ai consueti BASIC e Assembly, sono stati utilizzati i linguaggi più disparati, tra cui APL, SQL e Canvas (ambiente di cui non ero a conoscenza).
Alcuni programmi sono davvero impressionanti e meritevoli di studio!

Il mio programma

Avendo già partecipato all’edizione dell’anno precedente, a inizio Dicembre 2023 sono stato invitato da Logiker a prendere parte alla nuova sfida; ho così realizzato un programma in linguaggio BASIC per l’home computer Sinclair ZX Spectrum.

Il programma, chiamato The Snowing Christmas Sweater, è costituito da un’unica riga di codice che occupa solamente 63 byte e simula un effetto “nevicata”, stampando gli asterischi “*” in modo pseudo-casuale, fino a produrre l’immagine richiesta:

3 LET x=RND*VAL "18": PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI
Animazione che mostra il mio programma in esecuzione su ZX Spectrum
Il mio programma in esecuzione su ZX Spectrum

Per semplificare la realizzazione, ho deciso di procedere per piccoli passi, ponendomi inizialmente l’obiettivo di stampare l’immagine richiesta nella sua interezza, per poi modificare il programma per aggiungere l’effetto “nevicata” ed apportare le opportune ottimizzazioni.

Il primo passo è stato stampare una linea obliqua di asterischi. Sperimentando con il codice, mi sono reso conto che nella stampa con PRINT AT, è possibile specificare valori negativi come numero di riga e/o di colonna, senza causare errori nell’interprete, che utilizza effettivamente i valori assoluti. Con questo accorgimento, è stato possibile disegnare due segmenti con un singolo ciclo FOR:

100 FOR x=0 TO 18
200 PRINT AT x,x-3;"*"
300 NEXT x
Animazione che mostra 2 segmenti di asterischi, disegnati con un ciclo FOR
2 segmenti di asterischi, disegnati con un ciclo FOR

Iterando questo procedimento per 3 volte, sono riuscito ad ottenere metà della forma desiderata:

90 FOR a=-15 TO -3 STEP 6
100 FOR x=0 TO 18
200 PRINT AT x,a+x;"*"
300 NEXT x
310 NEXT a
Animazione che mostra il programma che disegna metà dell'immagine
Metà dell’immagine

L’immagine completa può quindi essere prodotta aggiungendo l’immagine stessa, ribaltata specularmente rispetto all’asse verticale, vale a dire stampando, in ciascuna iterazione, un ulteriore “*” alla colonna 18 – ABS(colonna corrente). La dimensione del programma ottenuto è: 116 byte:

90 FOR a=-15 TO -3 STEP 6
100 FOR x=0 TO 18
200 PRINT AT x,a+x;"*"
210 PRINT AT x,18-ABS (a+x);"*"
300 NEXT x
310 NEXT a
Animazione che mostra il programma che disegna l'immagine completa
Immagine completa

L’effetto ottenuto è carino, ma volevo che i fiocchi di neve*” apparissero casualmente sullo schermo. Ho quindi trasformato il programma in un ciclo infinito costituito da una sola riga di codice, che determina in ciascuna iterazione in modo pseudocasuale la posizione degli asterischi appartenenti a ciascuna delle due metà dell’immagine:

3 LET a=6*INT (RND*INT PI)-15: LET x=INT (RND*19): PRINT AT x,a+x;"*": PRINT AT x,18-ABS (a+x);"*": GO TO PI

Questa versione del programma occupa 88 byte. L’istruzione GO TO finale utilizza un espediente per ridurre la dimensione, infatti il π PI richiede solamente un token, mentre l’utilizzo della costante numerica “3” avrebbe richiesto 6 byte in più (si veda il capitolo relativo alla memoria sul manuale dello ZX Spectrum).

Nel passaggio successivo, ho ridotto il programma per utilizzare un’unico statement di PRINT, per stampare in ciascuna iterazione un asterisco, appartenente a una delle due metà dell’immagine scelta casualmente (dimensione: 83 byte):

3 LET a=6*INT (RND*INT PI)-15: LET x=INT (RND*19): PRINT AT x,INT (RND+RND)*18-ABS (a+x);"*": GO TO PI

Nel passaggio successivo, con un refactoring per rimuovere la variabile a, la dimensione del programma è scesa a 78 byte:

3 LET x=INT (RND*19): PRINT AT x,INT (RND+RND)*18-ABS (x+6*INT (RND*INT PI)-15);"*": GO TO PI

Nel passaggio successivo, sono riuscito a risparmiare ancora alcuni byte, sostituendo le costanti numeriche con l’utilizzo della funzione VAL (dimensione: 66 byte):

3 LET x=INT (RND*VAL "19"): PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI

Con un’ultima piccola modifica al codice che determina il valore x della riga in cui stampare il carattere “*“, ho risparmiato ancora 3 byte. La dimensione finale del programma è quindi 63 byte:

3 LET x=RND*VAL "18": PRINT AT x,INT (RND+RND)*VAL "18"-ABS (x+VAL "6"*INT (RND*INT PI)-VAL "15");"*": GO TO PI

Nota: la dimensione del programma è calcolata con: PRINT PEEK 23627+256*PEEK 23628-23755 (si veda il capitolo sulle variabili di sistema nel manuale dello ZX Spectrum).

Sicuramente, con un po’ più di tempo a disposizione (la scadenza era il 25 Dicembre), sarei riuscito a limare ancora qualche byte; mi sono riproposto di provarci comunque, come sfida personale.

Penso che con l’opportuna combinazione di colori, l’output del programma ricordi la trama di un maglione natalizio; ecco spiegato il nome The Snowing Christmas Sweater.

Screenshot dell'immagine a colori (bordo verde, carta rossa, inchiostro bianco brillante)
L’immagine a colori

Non sei d’accordo? Dai un’occhiata alla seguente immagine e dimostrami che ho torto! 😄

Ho anche realizzato un breve video per presentare il mio programma, disponibile sul mio canale YouTube:

Video di presentazione di The Snowing Christmas Sweater

Accoglienza e ulteriori ottimizzazioni

Al termine della scadenza per l’invio delle varie realizzazioni, ho pubblicato alcuni dettagli del mio programma sul gruppo Facebook BASIC on the ZX Spectrum, ricevendo con mia somma gioia l’apprezzamento da parte di Johan “Dr Beep” Koelman e Uwe Geiken, due autorità per quanto riguarda la programmazione dei computer Sinclair ZX.

Inoltre, Dr Beep ha ulteriormente ottimizzato il mio codice, riducendone la dimensione a soli 54 byte!

Partendo dal mio listato BASIC, una prima ottimizzazione apportata al codice che sceglie casualmente il valore 0 o 1 è stata la sostituzione di: INT (RND+RND) con la versione più concisa: (RND>RND).

Un’altra ottimizzazione è costituita dallo spostamento delle funzioni RND, ABS and INT all’interno della stringa processata dalla funziona VAL. Nel fare ciò, sono utilizzati i codici dei token corrispondenti alle funzioni e non i loro nomi, per cui ciascuna chiamata a una di queste funzioni occuperà solamente 1 byte. Il codice così ottenuto occupa solamente 55 byte:

3 LET x=VAL "RND*18": PRINT AT x,VAL "(RND>RND)*18-ABS (x+6*INT (RND*3)-15)";"*": GO TO PI

Un refactoring del calcolo della colonna del carattere “*” ha permesso di risparmiare ancora un byte, per cui la versione finale del codice è:

3 LET x=VAL "RND*18": PRINT AT x,VAL "(RND>RND)*18-ABS (x-3-6*INT (RND*3))";"*": GO TO PI

Riporto anche il codice formattato per BasinC (Sinclair BASIC IDE), in cui è evidente l’utilizzo dei codici dei token corrispondenti alle funzioni RND (165), INT (186) e ABS (189) all’interno delle stringa passate come parametri alla funzione VAL (vedi il set di caratteri dello ZX Spectrum):

3 LET x=VAL "\#165*18": PRINT AT x,VAL "(\#165>\#165)*18-\#189(x-3-6*\#186(\#165*3))";"*": GO TO PI

e lo stesso codice, formattato per il tool bas2tap (in cui i codici dei token sono espressi in notazione esadecimale):

3 LET x=VAL "{A5}*18": PRINT AT x,VAL "({A5}>{A5})*18-{BD}(x-3-6*{BA}({A5}*3))";"*": GO TO PI

Infine, Johan ha pubblicato sul gruppo ZX81 Owners Club il port per Sinclair ZX81 del programma. Dato che l’interprete BASIC dello ZX81 consente solo un’istruzione per linea, il programma è costituito da 3 linee:

3 LET x=VAL "RND*18"
4 PRINT AT x,VAL "(RND>RND)*18-ABS (x-3-6*INT (RND*3))";"*"
5 GOTO PI
Immagine che mostra il port per ZX81 di The Snowing Christmas Sweater
The Snowing Christmas Sweater, portato su ZX81 da Dr Beep

Concludendo, sono stato felice di partecipare, sia per i risultati raggiunti ma soprattutto perché questa sfida mi ha dato l’opportunità di divertirmi e di imparare qualcosa di nuovo sullo ZX Spectrum!


Read in English

Risultati del BASIC 10Liner Contest 2023

Sabato scorso sono stati pubblicati i risultati dell’undicesima edizione del BASIC 10Liner contest, tradizionale competizione a cui si può partecipare realizzando giochi e programmi per computer a 8 bit in sole 10 righe di codice in linguaggio BASIC.

Classifica BASIC 10Liners 2023

Purtroppo quest’anno, a differenza delle passate edizioni, non sono riuscito a entrare nella TOP 10. Infatti, i miei due giochi in gara per la categoria PUR-80, A Day At The Animal Races (ZX Spectrum) e Squash Trainer (ZX81), si sono classificati 16esimo e 27esimo rispettivamente, su 37 concorrenti.

Complimenti in particolare a RAX, che con Thrust 10 e Pacman 10, entrambi per Oric Atmos, si è aggiudicato sia la prima sia la seconda posizione della stessa categoria.

Thrust10 di RAX, per Oric Atmos
Pacman10 di RAX, per Oric Atmos

Sperando di fare meglio il prossimo anno, mi divertirò provando gli altri giochi e in particolare i vincitori!

Versione in Inglese

Squash Trainer: BASIC 10 Liner per ZX81

Squash Trainer è un nuovo videogioco di sport/azione per Sinclair ZX81, realizzato per la dodicesima edizione del BASIC 10 Liner Contest. Si tratta di una versione minimale di Pong per un giocatore; puoi vederlo in azione in questo video:

Squash Trainer gameplay video

In base a quanto stabilito dalle regole del contest per la categoria PUR-80, il programma è stato implementato in linguaggio BASIC, in 10 linee di codice, lunghe al massimo 80 caratteri.

Dato che l’interprete BASIC integrato nel computer permette l’utilizzo di una sola istruzione per linea, il programma è costituito da 10 istruzioni. Per aggirare in parte questa limitazione, il programma si avvale di un “trucco”, che consiste nel codificare più variabili all’interno di un’unica stringa. In questo modo, è possibile alterare il valore di più variabili in una singola istruzione.

Il listato BASIC è riportato di seguito; per una spiegazione dettagliata del codice, rimando alla documentazione dettagliata inclusa nell’archivio scaricabile dalla homepage del gioco.

1LET M$="?(X "+CHR$(4*(RND<.5))+"0 ?"
2LET C=(M$(1)="$")*(M$(2)>=M$(8))*(CODE M$(2)-CODE M$(8)<3)
3IF C THEN LET M$(4 TO 7)=" "+CHR$((RND<.5)*4)+STR$(1+VAL M$(6 TO 7))
4LET M$(4)=CHR$((M$(1)>"▀")*CODE M$(4)+4*(M$(1)="▀"))
5LET M$(5)=CHR$((M$(2)>" ")*(M$(2)<"0")*CODE M$(5)+4*(M$(2)=" "))
6PRINT AT CODE M$(1),CODE M$(2);" ";AT14,CODE M$(8);"   "
7LET M$(TO3)=CHR$(CODE M$(1)+CODE M$(4)-2)+CHR$(CODE M$(2)+CODE M$(5)-2)+INKEY$
8LET M$(8)=CHR$(CODE M$(8)+3*(M$(3)="P")*(M$(8)<".")-3*(M$(3)="O")*(M$(8)>" "))
9PRINT AT0,0;M$(6TO7);AT CODE M$(1),CODE M$(2);"▇";AT14,CODE M$(8);"░░░"
10GOTO 2*(M$(1)<"?")+20*((M$(1)="?")+(M$(6TO7)="99")>0)

Sempre sulla pagina dedicata al gioco, è possibile giocare online a Squash Trainer, grazie all’emulatore per browser web (i dispositivi mobili non sono supportati).

Buon allenamento!

Link e riferimenti

English version

La sfida della Stella di Natale

Si è da poco conclusa la Vintage Computing Christmas Challenge 2022 (VC³ 2022), un simpatico concorso di programmazione organizzato da Logiker per il periodo di Natale.

L’obiettivo della sfida principale, chiamata Christmas Star Challenge, consiste nella realizzazione di un programma per qualsiasi computer e linguaggio (preferibilmente per sistemi vintage), in grado di rappresentare fedelmente la figura mostrata nell’immagine seguente, ottimizzando il codice il più possibile, oppure di migliorarla.

Immagine da realizzare per la Christmas Star Challenge
Immagine da realizzare per la Christmas Star Challenge (fonte: Logiker).

In alternativa, optando per la challenge Wild, era possibile creare un programma completamente differente, purché a tema natalizio.

Centinaia di persone si sono cimentate con la sfida e tutti i programmi in gara sono presentati nel video realizzato dall’organizzatore:

Video dei Logiker con i risultati della sfida e presentazione di tutti i programmi in concorso.

La mia implementazione della Stella di Natale in Tiny BASIC

Ho deciso di partecipare alla Christmas Star Challenge realizzando un programma in Tiny BASIC. La stella, che occupa una superficie quadrata il cui lato misura 17 caratteri, può essere suddivisa in quattro triangoli sovrapposti:

01    *            
02    **           
03    ***          
04    ****         
05    *****        
06    ******       
07    *******      
08    ********     
09    *********    
10    **********   
11    ***********  
12    ************ 
13    *************
14
15
16
17
01            *    
02           **    
03          ***    
04         ****    
05        *****    
06       ******    
07      *******    
08     ********    
09    *********    
10   **********    
11  ***********    
12 ************    
13*************    
14
15
16
17
01
02
03
04
05*************    
06 ************    
07  ***********    
08   **********    
09    *********    
10     ********    
11      *******    
12       ******    
13        *****    
14         ****    
15          ***    
16           **    
17            *    
01
02
03
04
05    *************
06    ************ 
07    ***********  
08    **********   
09    *********    
10    ********     
11    *******      
12    ******       
13    *****        
14    ****         
15    ***          
16    **           
17    *            

L’idea è quindi quella di iterare su ciascuna delle 17*17 posizioni e di stampare un carattere “*” se il “punto” considerato appartiene ad almeno uno dei 4 triangoli, altrimenti uno spazio vuoto ” “:

 100 LET R=0
 110 LET C=0
 120 LET S=0
 130 IF R<13 THEN IF C>3 THEN IF C<R+5 THEN LET S=1
 140 IF R<13 THEN IF C<13 THEN IF C>11-R THEN LET S=1
 150 IF R>3 THEN IF C<13 THEN IF C>R-5 THEN LET S=1
 160 IF R>3 THEN IF C>3 THEN IF C<21-R THEN LET S=1
 800 IF S=0 THEN PRINT " ";
 810 IF S=1 THEN PRINT "*";
 900 LET C=C+1
 910 IF C<17 THEN GOTO 120
 915 PRINT
 920 LET R=R+1
 930 IF R<17 THEN GOTO 110
1000 END

Rimuovendo gli spazi superflui e sfruttando le abbreviazioni delle istruzioni Tiny BASIC, è stato possibile ridurre la dimensione del listato del programma a 203 caratteri:

1R=0
2C=0
3S=0
4IFR<13IFC>3IFC<R+5S=1
5IFR<13IFC<13IFC>11-RS=1
6IFR>3IFC<13IFC>R-5S=1
7IFR>3IFC>3IFC<21-RS=1
8IFS=0PR" ";
9IFS=1PR"*";
10C=C+1
11IFC<17GOTO3
12PR
13R=R+1
14IFR<17GOTO2
15END

Ed ecco l’output:

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

Non ho trovato un modo per ottimizzare ulteriormente il programma prima della fine della sfida; accetto comunque eventuali suggerimenti a riguardo!

Puoi osservare il programma in esecuzione su un computer Cosmac ELF emulato con Emma 02 nel seguente video, oppure eseguirlo e/o modificarne il codice utilizzando l’interprete online TinyBASICBlazor.

La mia implementazione in Tiny BASIC della Stella di Natale, in (lenta) esecuzione su Cosmac ELF, emulato con Emma 02.
La mia implementazione in Tiny BASIC della Stella di Natale, in esecuzione su TinyBASICBlazor, interprete Tiny BASIC per browser web.

Varianti ed evoluzioni

Data la semplicità della sintassi Tiny BASIC, che può essere considerato come un sottoinsieme della maggior parte dei dialetti BASIC disponibili, il programma può essere eseguito su una vastità di piattaform senza alcuna modifica (ad es. BBC Basic) o con modifiche minime. Ad esempio, su Sinclair ZX81 è sufficiente rimuovere l’istruzione “END” o sostituirla con “STOP” per avere una sintassi corretta.

Christmas Star - programma in esecuzione in BBC BASIC for SDL
La mia implementazione della Stella di Natale in esecuzione in BBC BASIC for SDL.

Proprio per il piccolo computer Sinclair, ho provato a compattare ulteriormente il codice del mio programma Tiny BASIC originale, anche se per ottenere risultati migliori in termini di dimensioni sarebbe stato necessario riscriverlo completamente sfruttando le caratteristiche del BASIC Sinclair.

Christmas Star - listato del programma per ZX81
Listato del programma per Sinclair ZX81.
Christmas Star - output del programma per ZX81
Output del programma per ZX81.
Programma per ZX81 in azione.

Infine, dato che lo scopo principale della competizione era quello di divertirsi, ho realizzato una versione Teletext della Stella di Natale, che riprende l’immagine di riferimento della sfida:

Christmas Star - versione Teletext
La Stella di Natale, versione Teletext.

La classifica ordinata per dimensione del codice sorgente è disponibile, insieme ai download di tutte le entry, su demozoo.org. Complimenti all’impareggiabile Dr. BEEP, che si è aggiudicato le prime posizioni con le versioni in Assembly per ZX81 e ZX Spectrum, il cui codice occupa solamente 27 e 29 byte rispettivamente!

Read in English

Risultati del BASIC 10Liner Contest 2022

Sabato scorso sono stati pubblicati i risultati dell’undicesima edizione del BASIC 10Liner contest, tradizionale competizione a cui si può partecipare realizzando giochi e programmi per computer a 8 bit in sole 10 righe di codice in linguaggio BASIC.

BASIC 10Liner Contest: “volantino” del concorso
BASIC 10Liner Contest: “volantino” del concorso

Analogamente allo scorso anno, ho partecipato per la categoria PUR-80 (massimo 80 caratteri per linea; abbreviazioni consentite) realizzando tre giochi, di cui due per ZX Spectrum (Bastilude, Fishie – Keep the sea plastic free!) e uno per ZX81 (JAMGame – Just Another Memory Game).

Fishie – Keep the sea plastic free! è entrato nella TOP 10, classificandosi 7° su 38 giochi in gara nella categoria PUR-80. Bastilude, nonostante la 25esima posizione, è stato particolarmente apprezzatto dal pubblico, che gli ha accordato il 2° posto nella classifica speciale Public’s Choice. JAMGame, infine, con la sua 18esima posizione si è assestato nella parte media della graduatoria.

Risultati del BASIC 10Liner Contest 2022.
Risultati del BASIC 10Liner Contest 2022 (grazie a Filippo Santellocco per l’immagine con tutti i risultati).
Nella classifica originale, Fishie è erroneamente associato al C64.

Nonostante sperassi in un posizionamento migliore di Bastilude, anche quest’anno posso ritenermi più che soddisfatto dei risultati raggiunti e come al solito ho già qualche idea che spero di poter sviluppare per la prossima edizione.

Ho avuto modo di esaminare o provare pochissimi dei giochi e programmi realizzati dagli altri concorrenti; tra questi ritengo particolarmente degni di nota 8-bit Sunset (vincitore della categoria SCHAU) e STOP THE micro EXPRESS (vincitore della categoria EXTREM-256). Quest’ultimo si avvale di una tecnica molto interessante di utilizzo dell’istruzione LPRINT, che ha consentito all’autore di rendere eccezionalmente fluide le animazioni.

Concludo con un ringraziamento a Gunnar, organizzatore del contest, ai giudici e a tutti i partecipanti!

Link e riferimenti

Read in English