BooMfire: il mio programma per il 13° BASIC 10Liner Contest

Quest’anno non sono riuscito a trovare il tempo per realizzare nuovi giochi per il BASIC 10 Liner Contest, così ho ripreso e completato una vecchia idea, su cui avevo iniziato a lavorare qualche tempo fa: ispirato dal programma per MSX sviluppato da Roberto Capuano per l’11a edizione del contest, ho implementato una mia versione del noto effetto DOOM Fire, per ZX Spectrum. Per ottenere un’animazione fluida, ho abbandonato l’interprete Sinclair BASIC dello ZX Spectrum e mi sono affidato al compilatore ugBASIC di Marco Spedaletti. Il risultato è BooMfire, una demo realizzata in 9 linee di codice e candidata per la categoria SCHAU.

Penso che il risultato, che puoi osservare nel seguente video, non sia male:

Video che mostra BooMfire in azione (emulatore Fuse)

All’avvio del programma, viede disegnato il logo “BOOM“, per mezzo un algoritmo simile a quello utilizzato dal Kickstart dei computer Amiga per visualizzare l’immagine di richiesta inserimento floppy disk. Per lo riempimento, non ho utilizzato l’isitruzione PAINT di ugBASIC, ma ho implementato una subroutine che permettesse anche la riproduzione di una musica di sottofondo, per rendere meno noiosa l’attesa. Tale subroutine è basata sulla tecnica ricorsiva descritta nell’articolo A Fast Well-Behaved Pattern Flood Fill di Alvin Albrecht. A proposito di musica, il suono è riprodotto tramite chip AY-3-8912, per cui per apprezzare appieno la demo, non è sufficiente lo ZX Spectrum 48K, ma è necessario un modello avanzato (128K, +2, +3, Next, …).

L’animazione delle fiamme è la mia implementazione dell’effetto originariamente introdotto sulla versione di Final DOOM per Playstation, ovviamente riadattata per il computer Sinclair. L’animazione non lavora a livello di pixel, ma di carattere (8×8 pixel) e, mediante la pressione dei tasti 1, 2, o 3, è possibile simulare tre diversi livelli di sovrapposizione tra le fiamme e la scritta “BOOM“. Questo è stato possibile scegliendo opportunamente i colori di carta e inchiostro nelle tre corrispondenti “tavolozze”.

Puoi provare BooMfire utilizzando l’emulatore online oppure scaricarlo per eseguirlo su un emulatore o su un vero ZX Spectrum semplicemente accedendo alla pagina del progetto su retrobits.itch.io. Se sei interessato ad approfondire il funzionamento di BooMfire, puoi dare un’occhiata alla documentazione, corredata di codice sorgente commentato e inclusa nel download.

Enjoy the SCHAU!

Link e riferimenti

Read in English

Farmer Sam’s Dog Day: lavori in corso

Per celebrare la consegna delle unità ZX Spectrum Next prodotte per la seconda campagna KickStarter, avvenuta nelle scorse settimane in tutto il mondo, sto lavorando a una nuova versione di Farmer Sam’s Dog Day, il platformer da me realizzato.

Farmer Sam ha appena ricevuto il suo ZX Spectrum Next

La nuova verisone includerà alcune migliorie e soprattutto molti nuovi livelli! Per avere un assaggio della prossima uscita, ti invito a scaricare la demo che ho appena pubblicato sulla pagina del gioco sulla piattaforma itch.io.

Ma non è tutto: l’uscita di una versione fisica del gioco è all’orizzonte!

Resta sintonizzato per aggiornamenti!

Leggi in Inglese

Un po’ di rock’n’roll sullo Spectrum Next

Gli utenti dello ZX Spectrum Next hanno mostrato notevole apprezzamento per playvid, il comando realizzato da Allen Albright che ha esteso le potenzialità del nostro amato computer, permettendo la riproduzione di file video opportunamente codificati.

Dopo il rilascio da parte di em00k di makevid, front-end per ffmpeg che permette di semplificare la transcodifica di file video nei formati supportati da playvid, ho deciso di sperimentare la conversione. Per lo scopo, ho scelto un filmato che ritrare l’esecuzione del brano Hellish Rock’n’Roll registrata ad un concerto dei Doctor Feast, gruppo rock in cui suono la batteria. Purtroppo, sul PC che sto utilizzando non sono riuscito a portare a termine la conversione e sto cercando di capirne il motivo.

Fortunatamente, Xalior ha realizzato convert.py, un altro frontend per ffmpeg, questa volta in forma di script python. Tramite questo strumento, sono riuscito a portare a termine il lavoro.

Mi sono proposto di realizzare un video unico, non limitandomi a convertire la versione del brano registrata durante il concerto, bensì mixando la traccia video dell’esecuzione dal vivo con l’audio registrato in studio.

Il video, che puoi scaricare qui, è tutt’altro che perfetto, infatti la sincronizzazione tra audio e video non è precisa; inoltre il rapporto d’aspetto è 16/9, mentre sarebbe stato più adeguato 4/3, per coerenza col display dello ZX Spectrum.
Che dire, tutto in pieno spirito Punk!

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