RetroMagazine nr. 43 – Anno: 2023 – Autore: Eugenio Rapella
Quando il mio C64 ha visto il testo dell’ultimo “Quesito con la Susi” mi ha sussurrato: “Ehi, questo è proprio per me!”. Non potevo deluderlo. Ecco qui:
Susi sta chiacchierando con Luca.
Susi: “Ciao Luca, so che hai compiuto nove anni e so che hai tre fratellini più piccoli, tutti di età diverse.”
Luca: “Sì, è così. Se moltiplichi le nostre quattro età ottieni un numero di tre cifre e queste tre cifre corrispondono alle età dei miei fratelli.”
Quanti anni hanno i tre ragazzini?
Ecco qui il primo tentativo del mio C64:
100 for x=1 to 6 110 for y=2 to 7 120 for z=3 to 8 130 if x=y or x=z or y=z then 220 140 a=9*x*y*z 150 if a<100 or a>999 then 220 160 m=int(a/10):u=a-10*m:c=int(m/10):d=m-10*c 170 if x<>u and x<>d and x<>c then 220 180 if y<>u and y<>d and y<>c then 220 190 if z<>u and z<>d and z<>c then 220 200 print "***** a > ";a 210 print "** x,y,z > ";x,y,z 220 next z:next y:next x
I tre fratelli sono più giovani di Luca per cui le loro età vanno da 1 a 8 anni. Le età sono tutte diverse (niente gemelli) per cui l’età del più giovane (variabile x) non può superare i sei anni, quello di età intermedia (variabile y) avrà un’età tra due e sette anni e il maggiore dei fratellini (variabile z) non può avere meno di tre anni.
I tre cicli annidati “for-next”, si aprono alle istruzioni 100, 110, 120 e si chiudono alla 220, passano in rassegna tutte le possibili terne… senza andare troppo per il sottile.
Alla 130 si controlla se due delle variabili sono uguali tra loro, nel qual caso la terna non può essere la soluzione e si passa alla successiva (…then 220). Alla 140 la variabile a contiene il prodotto delle età dei quattro fratelli. Se a non è un numero di tre cifre (istr. 150), niente da fare, si va oltre (…then 220).
L’istruzione 160 si incarica di separare le tre cifre che formano il numero a: m=int(a/10) fornisce il numero formato dalle prime due cifre di a (ad esempio, se a=317, a/10=31,7 e m=int(a/10)=31 in quanto int(…) fornisce la parte intera dell’argomento) per cui u=a-10m isola l’ultima cifra, quella delle “unità” (continuando l’esempio precedente, u=317-1031=7).
Analogamente c=int(m/10) isola la prima delle tre cifre, quella delle “centinaia” (nell’esempio è m=31 per cui c=int(31/10)=int(3,1)=3) mentre d isola la seconda cifra, quella delle decine (nell’esempio d=31-1030=1). Morale: al termine dell’istruzione 160, le tre variabili u,d,c contengono le cifre che formano a (se a=317, avremo u=7, d=1, c=3). Siamo alla fine: x,y,z, le tre candidate ad essere la soluzione, lo sono davvero se sono le tre cifre che formano il numero a. Se (istr. 170) l’età più piccola non coincide con alcuna cifra di a, niente da fare, si va alla 220 per continuare con un’altra terna. Lo stesso avviene alla 180 per l’età del secondo fratellino e alla 190 per il terzo. Alla 200 si arriva solo se tutto, ma proprio tutto va bene (le tre età sono diverse tra loro: 130; il prodotto a delle quattro età è un numero di tre cifre: 150; le cifre di a sono le età dei tre fratelli: 170, 180, 190): viene stampato il valore di a e, come conferma, si stampano le età dei tre fratellini. Anche dopo aver trovato una soluzione, il programma prosegue il lavoro cosicché, alla comparsa della scritta READY, sapremo anche che la soluzione trovata è unica. Con i tre “for-next” annidati abbiamo esaminato 666=216 terne, demandando al programma il compito di escludere anche le terne che, in base al testo, non avevano, fin dall’inizio, possibilità di essere la soluzione. In realtà, leggendo il quesito, si può notare che la soluzione andrà pescata tra le “combinazioni di 8 oggetti a gruppi di 3”. In questo tipo di raggruppamenti gli oggetti che costituiscono il raggruppamento sono diversi tra loro (nel “Calcolo Combinatorio” vengono definite “Combinazioni Semplici”) e l’ordine dei tre elementi non ha importanza (“258” e “582” sono la stessa “combinazione”). Il numero delle combinazioni di 8 oggetti a gruppi di 3 è C(8,3) = (876)/(32*1) = 56.
Il seguente programmino consente al C64 di elencarle tutte:
100 x=1:y=2:z=3:k=0 110 k=k+1:print" k > ";k 120 print" x,y,z > ";x;y;z:print 125 get r$:if r$="" then 125 130 if z<8 then z=z+1: goto 110 140 if y<7 then y=y+1:z=y+1:goto 110 150 if x<6 then x=x+1:y=x+1:z=y+1:goto 110
Alla 100 si parte con la “prima” delle 56 combinazioni (k funge da contatore), formata da 1, 2, 3; questa viene stampata.
Con l’istr. 125 si attende che l’utilizzatore prema un tasto prima di stampare la successiva (se la si elimina, il C64 stampa rapidamente tutte le combinazioni, ma, alla fine, si riusciranno a vedere solo le ultime…).
Alla 130, finché il terzo elemento non raggiunge il valore 8, è lui che viene incrementato: 123/124/125/ … /128/. Quando questo avviene, si passa a considerare il 2°: y (istr. 140). Se non ha ancora raggiunto il suo valore massimo (7), è lui che viene incrementato, così come il terzo: /134/135/ ecc. Infine, anche quando y raggiunge il valore 7, si passa ad incrementare il primo (x) e gli altri di conseguenza. In questo modo i tre valori sono sempre in ordine crescente; facendo girare il programma (coraggio! Sono solo sette istruzioni) il meccanismo risulta ancora più chiaro.
A questo punto, possiamo modificare il programma del quesito facendo in modo che il Commodore testi solo le 56 terne ottenute come combinazioni, anziché le 216 del programma precedente. Inoltre non sarà più necessario verificare se nelle terne ci sono cifre ripetute, visto che gli elementi della combinazione sono, automaticamente, uno diverso dall’altro.
Ecco qui:
100 x=1:y=2:z=3 110 a=9xyz 120 m=int(a/10):u=a-10m:c=int(m/10):d=m-10c 130 if x<>u and x<>d and x<>c then 180 140 if y<>u and y<>d and y<>c then 180 150 if z<>u and z<>d and z<>c then 180 160 print " a > ";a 170 print "** x,y,z > ";x,y,z 180 if z<8 then z=z+1: goto 110 190 if y<7 then y=y+1:z=y+1:goto 110 200 if x<6 then x=x+1:y=x+1:z=y+1:goto 110
Questo programma è naturalmente più veloce (e un po’ più breve) del precedente anche se i tempi di attesa sono molto limitati per entrambi i “prg”.
Come faranno gli sfortunati lettori de “La Settimana Enigmistica” che non possiedono un C64 e che, peggio ancora, magari non leggono RMW? Dovranno passare in rassegna le 56 combinazioni delle tre cifre, moltiplicarle tra loro, moltiplicare poi per nove e vedere se il numero ottenuto è proprio formato dalle cifre considerate? In realtà c’è una bella scorciatoia: il numero 9xyz è un multiplo di nove per cui anche la somma delle sue cifre sarà un multiplo di nove (da dove viene questa proprietà? È presto detto: se u, d, c sono le cifre delle unità, decine e centinaia di un numero di tre cifre, il valore del numero è dato da 1000m+100c+u=(999m+99c)+(c+d+u). Il numero nella prima coppia di parentesi è senz’altro un multiplo di 9; lo sarà anche il numero di partenza se, e solo se, lo è anche c+d+u). Tenendo conto di questo e del fatto che l’età del più piccolo non può essere superiore a 3 (se le tre età fossero le più piccole possibili a partire da 4, si avrebbe 9456=1080 che supera le tre cifre) si riesce a ridurre il numero di candidati a sole … quattro terne.
Il mio Commodore 64 mi ha fatto promettere di non dire altro e, tanto meno, la soluzione (dice che altrimenti nessuno digita i listati) per cui mi fermo qui.