Inform e Glulx/Le basi di Inform/I vettori

Indice del libro

I vettori

modifica

Se siete riusciti ad arrivare vivi fino a qui, devo farvi davvero i miei complimenti. Adesso però, prima di affrontare l’argomento di questo paragrafo, vi consiglio vivamente di bere un po’ d’acqua, rilassarvi completamente e magari uscire per un paio d’ore con la vostra moglie o fidanzata (e se siete dei single con qualche amica: non si sa mai, potrebbe nascere una nuova relazione amorosa).


Vi siete rilassati? Ok. Un vettore può essere considerato come un insieme di variabili indicizzate e in Inform può essere definito in questo modo:

Array nome_array->lunghezza_max_array;

Scrivendo ad esempio Array numeri->20; abbiamo a disposizione 20 celle (che equivalgono di fatto a delle variabili) alle quali è possibile accedere tramite un indice:

! Esempio sull'utilizzo dei vettori numerici - versione 1

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 10;
Array numeri->LUNGH_MAX;
[ Funz_princip; ClearScreen(); ! pulisce lo schermo LoadArray(numeri); PrintNumericArray(numeri, LUNGH_MAX); print "^^Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ LoadArray the_array i; for (i=1: i<=LUNGH_MAX: i++) the_array->(i - 1) = i; ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

All’inizio, il vettore numeri si presenta così:

  0     1     2     3     4     5     6     7     8     9  
  ?     ?     ?     ?     ?     ?     ?     ?     ?     ?  

abbiamo 10 celle che devono ancora essere inizializzate (non sappiamo quindi cosa contengono, da qui il "?"). I numeri che vanno da 0 a 9 sono gli indici delle celle (uno per ogni cella). Dopo la chiamata alla funzione LoadArray ecco come si ripresenta il nostro vettore:

  i     0     1     2     3     4     5     6     7     8     9  
  the_array->i     1     2     3     4     5     6     7     8     9    10 

Nel ciclo for di questa funzione, alla variabile i viene assegnato l’indice e l’istruzione:

the_array->(i - 1) = i;

fa riferimento alla cella corrispondente dell’indice (i – 1), e le assegna il valore della variabile i. Ricordatevi sempre che in Inform, l’indice della prima cella di un vettore non è 1, ma 0. Ecco perché ho messo (i – 1) al posto di i: se non lo avessi fatto, il contenuto della decima cella sarebbe stato 9 anziché 10.

Volendo semplificare un po’ le cose, possiamo fare in modo che il vettore numeri sia inizializzato al momento della sua dichiarazione:

! Esempio sull'utilizzo dei vettori numerici - versione 2

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 10;
Array numeri-> 1 2 3 4 5 6 7 8 9 10;
[ Funz_princip; ClearScreen(); ! pulisce lo schermo PrintNumericArray(numeri, LUNGH_MAX); print "^^Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

In questo modo, la funzione LoadArray non serve più, mentre la costante LUNGH_MAX continua a fungere da parametro all’istruzione PrintNumericArray (che, come dovreste ormai aver capito, stampa a video il contenuto di un vettore numerico).

 

Ecco adesso, un esempio che usa un vettore con le stringhe:

! Esempio sull'utilizzo dei vettori con le stringhe - versione 1

Include "Parser"; Include "VerbLib"; Include "Replace";
Array nome buffer "Massimo è andato a casa";
[ Funz_princip; ClearScreen(); ! pulisce lo schermo PrintStringArray(nome); print "^^Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

abbiamo ora un vettore nome di tipo stringa che dopo l’istruzione:

Array nome buffer "Massimo è andato a casa";

si presenta così:

  0     1     2     3     4     5     6     7     8     9     10    ... 
  0    23    M     a     s     s     i     m     o       è    ... 

La cella numero 2 (nome->1) contiene il numero 23 che corrisponde alla lunghezza della stringa in esso contenuta. La stringa vera e propria comincia quindi dalla cella successiva (nome->2). Nell’esempio appena visto, abbiamo assegnato una stringa a un vettore al momento della dichiarazione di quest’ultimo. Tuttavia, in un programma vero e proprio (e quindi in un’avventura testuale), difficilmente si utilizza un vettore una sola volta. Come si può, cioè, far sì che sia possibile assegnare al vettore nome più stringhe?
Osserviamo l’esempio che segue:

! Esempio sull'utilizzo dei vettori con le stringhe - versione 2

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 33;
Array nome->LUNGH_MAX;
[ Funz_princip; ClearScreen(); ! pulisce lo schermo
PrintToBuffer(nome, LUNGH_MAX, "Massimo è andato a casa"); PrintStringArray(nome); print "^"; PrintToBuffer(nome, LUNGH_MAX, "Massimo sta dormendo"); PrintStringArray(nome);
print "^^Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

Come potete facilmente vedere, è l’istruzione PrintToBuffer che effettua l’assegnamento da noi voluto. PrintToBuffer ha però bisogno di tre parametri obbligatori: il nome dell’array (nome), la sua lunghezza (la costante LUNGH_MAX o, se preferite, 33) e la stringa vera e propria racchiusa tra le virgolette.
Ricordatevi sempre che non potete mai usare una stringa che superi la lunghezza massima del vettore destinato a contenerla; dovete inoltre aggiungere 3 numeri alla lunghezza massima della vostra stringa fino a un massimo di 160 caratteri. In poche parole, in questo esempio non potete inserire una stringa lunga più di 30 caratteri, e la lunghezza del vettore che la deve contenere deve essere 33 su un massimo di 160. Piuttosto complicato, non è vero?

 

Vediamo ora, come fare in modo che sia l’utente a inserire una stringa:

! Esempio sull'utilizzo dei vettori con le stringhe – versione 3

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 18;
Array nome_player->LUNGH_MAX; Array nome_computer->LUNGH_MAX;
[ Funz_princip; ClearScreen(); ! pulisce lo schermo
print "^Come ti chiami? "; ReadArray(nome_player, LUNGH_MAX); PrintToBuffer(nome_computer, LUNGH_MAX, "massimo"); print "Ciao ", (PrintStringArray) nome_player, ", "; if((CmpStr(nome_player, nome_computer))==1) print "abbiamo lo stesso nome.^^"; else print "io sono ", (PrintStringArray) nome_computer, ".^^";
print "Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

L’istruzione ReadArray da me scritta, definita nel file Io.h (che contiene a sua volta anche le istruzioni CmpStr e PrintStringArray), è quella che permette l’inserimento in input di una stringa da parte dell’utente [1]. La riga ReadArray(nome_player, LUNGH_MAX); chiama quindi questa istruzione passandole, come parametri, il nome dell’array che deve contenere la stringa dell’utente e la sua lunghezza massima. L’istruzione CmpStr confronta due stringhe e restituisce il valore 1 se sono uguali, 0 se invece non lo sono. La riga CmpStr(nome_player, nome_computer); chiama quindi questa istruzione passandole, come parametri, i nomi degli array contenenti le due stringhe da confrontare. Occorre però notare ancora una cosa: perché al vettore nome_computer viene passata la stringa "massimo" anziché "Massimo"?
Dovete sapere che l’istruzione ReadArray (o meglio, l’istruzione KeyboardPrimitive usata da ReadArray), trasforma automaticamente tutte le lettere maiuscole in minuscole. Se l’utente digita quindi "Mario", il vettore nome_player conterrà "mario" anziché "Mario". Di per sé il problema non sarebbe tanto grave, se non fosse per il fatto che due righe più sotto il nome dell’utente viene stampato a video insieme a quello del computer.
Ecco allora come risolvere il problema:

! Esempio sull'utilizzo dei vettori con le stringhe - versione 4

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 18;
Array nome_player->LUNGH_MAX; Array nome_computer->LUNGH_MAX;
[ Funz_princip; ClearScreen(); ! pulisce lo schermo
print "^Come ti chiami? "; ReadArray(nome_player, LUNGH_MAX); nome_player->2 = UpperCase(nome_player->2); PrintToBuffer(nome_computer, LUNGH_MAX, "Massimo"); print "Ciao ", (PrintStringArray) nome_player, ", "; if((CmpStr(nome_player, nome_computer))==1) print "abbiamo lo stesso nome.^^"; else print "io sono ", (PrintStringArray) nome_computer, ".^^";
print "Premi un tasto per uscire^"; KeyCharPrimitive(); ! legge un carattere dalla tastiera ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

basta usare l’istruzione UpperCase passandole come parametro la lettera iniziale della stringa digitata dall’utente (contenuta a sua volta nella terza cella del vettore nome_player  ➨  nome_player->2).

 

Concludiamo il paragrafo con quest’ultimo programma:

! Esempio sull'utilizzo dei vettori con le stringhe - versione 5

Include "Parser"; Include "VerbLib"; Include "Replace";
Constant LUNGH_MAX 10;
Array nome->LUNGH_MAX;
[ Funz_princip car; do { ClearScreen(); ! pulisce lo schermo PrintToBuffer(nome, LUNGH_MAX, "Massimo"); ChangeStringArray(nome); print "Ciao, ", (PrintStringArray) nome, ".^"; print "^Vuoi continuare (s/n)? "; car = ReadChar(); } until (car == 'n'); ];
[ ChangeStringArray the_array i; for (i=2: i<=(the_array->1)+2: i++) { if (the_array->i == 'a' or 's') the_array->i = random('e', 'i', 'u'); } ];
[ Initialise; Funz_princip(); quit; ! fine del programma ];
Include "Io"; Include "ItalianG";

la funzione ChangeStringArray cambia le lettere "a" e "s" della parola "Massimo", scegliendo a caso fra le lettere "e", "i", "u" per mezzo dell’istruzione random. Quest’ultima, è anche in grado di generare dei numeri casuali come nel seguente esempio:

[Funz_princip a count;
  for (count=1: count<=10: count++)
  {
     a = random(6);
     print a, " ";
  }
];

a può valere un numero a caso compreso tra 1 e 6; un’efficace simulazione del lancio di un dado.
L’istruzione ReadChar (definita anch’essa nel file Io.h) legge un carattere inserito dall’utente proprio come nell’istruzione Presskey ma, a differenza di quest’ultima, deve essere seguito dalla pressione del tasto Invio[2].

  1. In Inform esiste anche un modo più semplice per chiedere in input una stringa da parte dell’utente, come spiegato alla fine del paragrafo successivo.
  2. Cliccate qui per scaricare i listati degli esercizi (i file 3.15_1.inf, 3.15_2.inf, 3.15_3.inf, 3.15_4.inf, 3.15_5.inf, 3.15_6.inf, 3.15_7.inf).