A Day At The Animal Races è il mio secondo gioco (il primo è Squash Trainer) in gara per la 12a edizione (2023) del BASIC 10 Liner Contest, categoria PUR-80. Puoi scaricarlo o giocare online accedendo alla pagina retrobits.itch.io/animalrace10l. Il download include il listato del programma e la documentazione dettagliata.
Come giocare
Cinque diversi animali gareggiano l’uno contro l’altro e tu hai la possibilità di mettere alla prova la tua abilità nel scegliere il vincitore.
Aspetta che gli animali siano pronti per partire, quindi seleziona un animale e decidi quanto vuoi scommettere (fino a un limite di $9). Al termine della gara, le tue vincite o perdite verranno calcolate e verrà visualizzato il nuovo totale. Puoi vincere il gioco accumulando $256 o più.
Tutti gli animali si muovono all’incirca alla stessa velocità, ma partono da posizioni diverse. Le probabilità di vincita per ogni animale sono correlate alla posizione di partenza ma includono un elemento casuale. Alcune corse favoriscono il giocatore e dovresti scommettere fino al limite. Altre sono sfavorevoli e dovresti scommettere con attenzione.
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).
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.
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:
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:
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:
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.
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.
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:
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!
Il programma è una versione semplificata (l’implementazione originale determina anche se gli elementi della successione siano numeri primi) e adattata per Tiny BASIC dell’esempio 4.18 del libro Programmare in BASIC (seconda edizione) di Byron S. Gottfried:
01 REM BASED ON EXAMPLE 4.18 FROM PROGRAMMING WITH BASIC BOOK BY BYRON S. GOTTFRIED
02 REM ADAPTED TO TINY BASIC BY MARCO'S RETROBITS
03 REM HTTPS://RETROBITS.ALTERVISTA.ORG (ENGLISH)
04 REM HTTPS://SOMEBITSOFME.ALTERVISTA.ORG (ITALIAN)
05 REM HTTPS://RETROBITS.ITCH.IO
10 REM GENERATION OF FIBONACCI NUMBERS
20 PRINT "N= (3<=N<=23)";
30 INPUT N
35 IF N < 3 THEN GOTO 20
36 IF N > 23 THEN GOTO 20
40 PRINT
50 PRINT "GENERATION OF FIBONACCI NUMBERS"
60 PRINT
70 LET G=1
80 LET H=1
90 PRINT "I= ";1,"F= ";1
100 PRINT "I= ";2,"F= ";1
110 LET I=3
120 LET F=G+H
200 PRINT "I= ";I,"F= ";F
210 LET H=G
220 LET G=F
230 LET I=I+1
235 IF I<=N THEN GOTO 120
240 END
Nel listato è evidente l’assenza del ciclo FOR, sostituito da meno eleganti IF e GOTO. Inoltre, la serie generata è limitata a un massimo di 23 elementi a causa della precisione limitata (16 bit) del tipo di dato numerico in questa implementazione dell’interprete.
Riporto di seguito l’output della generazione dei primi 20 numeri di Fibonacci:
Ho deciso di aggiungere questo programma per puro sentimento nostalgico, in quanto mi ricorda con piacere le esercitazioni di informatica ai tempi della scuola, tanti anni fa.
C'è una cassetta di mele e pere.
Alcune sono grandi, altre piccole; alcune sono gialle, le altre sono verdi.
Non ci sono pere piccole né mele piccole e verdi.
Sono resi noti alcuni numeri: 25 mele, 17 pere, 32 frutti grandi, 28 gialli.
Ci sono due mele verdi in più rispetto alle pere verdi.
Trova il numero di mele grandi gialle.
Il problema è riconducibile a un sistema lineare di 5 equazioni in 5 incognite, per la cui risoluzione sono disponibili strumenti matematici ben noti (forse ne ho anche implementato qualcuno, quando ero studente), ma in questo caso ho deciso di divertirmi un po’ implementando in Tiny BASIC un algoritmo di forza bruta per verificare tutte le soluzioni teoricamente possibili, fino a che si trova quella effettivamente corretta. Il listato del programma è riportato di seguito:
1 REM ********************
2 REM * APPLES AND PEARS *
3 REM ********************
4 REM BRUTE FORCE TINYBASIC IMPLEMENTATION
5 REM BY MARCO'S RETROBITS
6 REM RETROBITS.ALTERVISTA.ORG
7 REM PLEASE TAKE A SEAT, THIS COULD BE SLOW
8 REM ********************
10 REM THERE WAS A BOX OF APPLES AND PEARS
11 REM SOME ARE BIG, SOME ARE SMALL;
12 REM SOME ARE YELLOW, REST ARE GREEN
13 REM THERE ARE NO SMALL PEARS
14 REM AND NO SMALL GREEN APPLES.
15 REM SOME NUMBERS ARE GIVEN:
16 REM 25 APPLES, 17 PEARS
17 REM 32 BIG FRUITS
18 REM 28 YELLOW ONES.
19 REM THERE ARE TWO MORE GREEN APPLES THAN GREEN PEARS.
20 REM FIND THE NUMBER OF BIG YELLOW APPLES.
30 REM C: SMALL YELLOW APPLES
40 REM D: BIG YELLOW APPLES
50 REM E: BIG GREEN APPLES
60 REM F: BIG YELLOW PEARS
70 REM G: BIG GREEN PEARS
80 REM A: APPLES; P: PEARS
90 REM B: BIG FRUITS; Y: YELLOW ONES
100 LET A = 25
110 LET P = 17
120 LET B = 32
130 LET Y = 28
200 REM FOR C = 1 TO A
201 LET C=1
210 REM FOR D = 1 TO A-C
211 LET D = 1
220 REM FOR E = 1 TO A-C-D
221 LET E = 1
230 REM FOR F = 1 TO P
231 LET F = 1
240 REM FOR G = 1 TO P-F
241 LET G = 1
250 GOSUB 2000
260 IF S = 0 THEN GOTO 460
270 PRINT "SOLVED!"
280 PRINT "SMALL YELLOW APPLES:", C
290 PRINT "BIG YELLOW APPLES:", D, "*"
300 PRINT "BIG GREEN APPLES:", E
310 PRINT "BIG YELLOW PEARS:", F
320 PRINT "BIG GREEN PEARS:", G
400 END
460 REM NEXT G
461 LET G = G+1
462 IF G <= P-F THEN GOTO 250
470 REM NEXT F
471 LET F = F+1
472 IF F <= P THEN GOTO 240
480 REM NEXT E
481 LET E = E+1
482 IF E <= A-C-D THEN GOTO 230
490 REM NEXT D
491 LET D = D+1
492 IF D <= A-C THEN GOTO 220
500 REM NEXT C
501 LET C = C+1
502 IF C <= A THEN GOTO 210
510 PRINT "NO SOLUTION!"
520 END
1990 REM ** CHECK ROUTINE **
2000 LET S = 0
2001 REM PRINT C, D, E, F, G
2010 REM 25 APPLES, 17 PEARS
2020 IF C + D + E <> A THEN RETURN
2030 IF F + G <> P THEN RETURN
2040 REM 32 BIG FRUITS
2050 IF D + E + F + G <> B THEN RETURN
2060 REM 28 YELLOW ONES
2070 IF C + D + F <> Y THEN RETURN
2080 REM THERE ARE TWO MORE GREEN APPLES THAN GREEN PEARS
2090 IF E <> G + 2 THEN RETURN
2100 REM ** SOLVED! **
2110 LET S = 1
2990 RETURN
Ogni volta che ho a che fare con Tiny BASIC, inizialmente mi stupisco del fatto che questo dialetto non preveda i cicli FOR…NEXT. Questo in realtà non è un grosso problema, in quanto si può ovviare con le (meno eleganti) istruzioni di IF e GOTO. Un’altra limitazione è data dai nomi delle variabili, che possono essere costituiti da un’unica lettera maiuscola.
Ho eseguito il programma “Mele e Pere” su TinyBasicBlazor, l’ambiente TinyBASIC interattivo per web browser da me realizzato a partire da TinyBasic.NET e descritto in questo post. La soluzione ha richiesto più di mezz’ora (devo verificare il motivo), mentre con TinyBasic.NET in versione console, sono necessari pochi secondi.
Ah, quasi dimenticavo: ci sono 7 mele grandi e gialle!
SMALL YELLOW APPLES: 10
BIG YELLOW APPLES: 7 *
BIG GREEN APPLES: 8
BIG YELLOW PEARS: 11
BIG GREEN PEARS: 6