Newsgroup: it.comp.giochi.avventure.testuali
Titolo: Haste is back...

Ebbene sì; Il ridisegno della macchina virtuale è completato. Si era reso
necessario perché alcune ingenuità che avevo commesso nella gestione degli
oggetti avevano reso impossibile lavorare su oggetti con maggiore
profondità di due livelli... me ne sono accorto solo quando ho iniziato a
fare i primi test di IF.
Prima di fare una versione voglio aggiungere un paio di cosette che reputo
troppo interessanti per lasciarle indietro; se mi dice bene posso fare
tutto entro oggi.
Come ho detto, haste non è uno scripting language specifico per le AT;
questo è un bene, perché il comando VERB di inform è la sua maledizione,
più che la sua benedizione... L'idea è quella di scrivere una libreria per
la creazione di AT. In realtà dovrebbe essere una cosa paurosamente
semplice da fare, rispetto a inform, perché in Inform la gestione di
stringhe e array è vicina allo zero, e non ci sono dizionari e altri
costrutti simili. 
Per darvi un assaggio di come funziona haste, ecco un piccolo esempio:
attributes
   light
   open
end
object Room1
  name = "La mia prima stanza"
  content = [ palla_bianca, piramide_rossa ]
  description = "Sei nella mia prima stanza!"
  e_to = Room2
[ ... altre proprietà ]
  enter()
    printl( "Benvenuto nella mia prima stanza" )
  end
  has light
end
object palla_bianca
  name = "La palla bianca"
  noun = [ "palla", "sfera" ]
  adjective = "bianca"
  ...
end
....
Assomiglia un po' a tads, ma ha gli attributi (come inform).
Ora, non avendo costrutti "speciali" per le IF, le relazioni di parentela
non sono automatiche. Ad esempio, sarebbe necessario creare un oggetto
World che contiene tutti gli oggetti "stanza" del gioco; questo si può fare
1) avendo un arrayone in world che contiene tutti gli oggetti o
2) chiamando una funzione AddToWorld( object ) per ogni stanza (lo si può
fare subito dopo la dichiarazione dell'oggetto) o
3) derivando la stanza dalla classe if_room, il cui costruttore si aggiunge
automaticamente al mondo:
object Room1 from if_room
  name = "La mia prima stanza"
  ...
end
 
Questa mi sembra la soulzione più elegante. Un altra maledizione di Inform è
che tutti gli oggetti definiti hanno caratteristiche "ifose". Questo ti fa
salvare un paio di caratteri per ogni oggetto, ma alle volte è una iattura.
Ci sono molti oggetti "degni di stare nel gioco" che non dovrebbero far
parte dell'universo di gioco. Ad esempio, gli item dei menu, gli oggetti di
supporto di vario genere; nelle MFS ho un "arbitro" che descide la
risoluzione dei combattimenti, ho la memoria per registrare gli
incatensimi, gli incantesimi stessi sono oggetti, ho persino "il cielo",
che gestisce lo stato di avanzamento del giorno o della notte. Vi assicuro
che rendere "invisibili" alcuni di questi oggetti ha richiesto una notevole
conoscenza di inform... che come tutti i linguaggi "specifici" è facile da
usare all'inizio, ma come tenti di fare una cosetta nuova 1) o è
impossibile o 2) ce la fai, ma sudando sette camicie.
Allo tesso modo, invece di listare il contenuto degli oggetti esplicitamente
penso che sia più interessante scrivere:
object palla_bianca from if_object( Room1 )
  name = "La palla bianca"
  noun = [ "palla", "sfera" ]
end
con il costruttore della classe if_object che aggiunge l'oggetto
direttamente dentro un parente.
Allo stesso modo, questi costruttori si occuperebbero di costruire l'oggetto
dizionario, che per ora organizzerei così:
object Dictionary
   verbs = [=>]
   nouns = [=>]
   adjectives = [=>]
   /** Adds a noun to the dictionary.
      Each dictionary entry puts in relation a noun with all the
      items having that noun. Each key is a word, and its relative
      value is a list of items where that word is used as a noun.
   */
   addNoun( word, item )
      printl ("Adding ", word, " for ", 
item.name
 )
      v = self.nouns
      if word notin v
         self.nouns[ word ] = [ item ]
      else
         self.nouns[ word ] += item
      end
   end
   /** Add adjective.
      See addNoun
   */
   addAdjective( word, item )
      if word notin self.adjectives
         self.adjectives[ word ] = [ item ]
      else
         self.adjectives[ word ] += item
      end
   end
end
In altre parole, quando il mondo si forma gli oggetti si registrano al
dizionario chiamando automaticamente dal loro costruttore
Dictionary.addNoun( "nome", me_stesso )
per ogni parola nella loro lista "noun". Se voglio sapere a quale oggetto
l'utente si riferisce, non devo fare altro che chiedere:
oggetti_che_dice_lutente = Dictionary.nouns[ parola ]
ed otterrò la lista degli oggetti che corrispondo a quella parola (se
esiste). Se avessi qualche dubbio, potrei anche incrociarla con:
oggetti_che_dice_lutente = Dictionary.adjective[ altra_parola ]
e escludere tutti i nomi che non compaiono in entrambe le liste...
I verbi saranno semplicemente fatti con:
Dictionary.verbs[ "saluta" ] = hello_world
function hello_world( nome, secondo )  
 printl( "Ciao mondo; il soggetto della frase era ", nome, 
  " e il complemento era ", secondo )
end
 
Inform ha ampiamente dimostrato che per costruire parser MOLTO complessi
sono sufficienti il soggetto della frase (che in inform è la variabile
noun) e un generico complemento, il cui tipo viene determinato dalla
struttura della frase, chiamato "second".
A dire la verità è più probabile che le entry dei verbi siano "oggetti" di
tipo verbo, come questo:
object azione_saluta from if_verb
   noun = ["ciao", "saluta" ]
   grammar = [ 
 ["*"] => self.saluta_tutti,
 ["*", "*noun" ] => self.saluta_qualcuno,
        ["*", "a", "*noun" ] => self.saluta_a_qualcuno
   ]
   saluta_tutti( noun, second )
     ...
   end
end
con "*" == il verbo, i token grammaticali "*noun", "*second", "*topic" ecc.
alla inform e la routine gestrice, che può essere all'interno dell'oggetto
o all'esterno a seconda dei gusti...
Per l'internazionalizzazione, potrebbe essere sufficiente:
function internazionalizza()
...
  azione_saluta.grammar = [ 
        ["*"] => azione_saluta.saluta_tutti,
        ["*", "*noun" ] => self.saluta_qualcuno,
        ["*", "at", "*noun" ] => self.saluta_a_qualcuno  // nota "AT" 
   ]
 
   azione_saluta.setNouns( ["hello", "hi"] )
end
cosa che cambierebbe sia la grammatica dell'oggetto che i suoi "nomi di
verbo"; il metodo setNouns penserebbe da solo ad aggiornare il dizionario,
e se le frasi in saluta_tutti ecc. sono messaggi configurabili (se ad
esempio invece di stampare frasi si una una routine configurabile come
print_message( number ) ) dovrebbe essere abbastanza semplice.
Anche il parser potrebbe essere internazionalizzato attraverso la semplice
ridefinizione di alcune strutture, così da poter accettare "lo prendo" o
"prendilo" in italiano e "get it" in inglese...
Cosa ne pensate?
Gian.

 Cosa ne pensate?
Giancarlo
ti avevo spedito tempo fa una email con alcune mie considerazioni sul 
World Model in Haste (dopo la discussione in chat in cui se ne era 
parlato, ormai un paio di mesi fa, se non sbaglio). Ti è arrivata? L'hai 
letta?
Riepilogo quello che avevo scritto. In particolare riflettevo sulla 
questione content/parent di cui avevamo discusso in chat. Ho letto 
velocemente questo tuo post e non so se oltre al linguaggio e alla 
macchina virtuale tu abbia già fatto qualcosa anche per il World Model. 
Ti ricopio e incollo qui le mie considerazioni (che potrebbero essere 
comunque già "vecchie" in relazione ai recenti progressi nello sviluppo).
Nella chat in questione tu parlavi di scrivere esplicitamente l'elenco 
dei contenuti di ogni oggetto (per esempio di una stanza). Il World 
Model si sarebbe allora occupato di creare automaticamente i riferimenti 
al parent negli oggetti.
Per quanto elegante come soluzione è secondo me piuttosto scomoda per il 
programmatore. Se diciamo che bisogna indicare il content forziamo 
l'autore a progettare l'avventura in modo poco naturale. Mi spiego 
meglio. Normalmente il "flusso" standard di creazione dell'avventura 
consiste nella definizione delle locazioni e poi degli oggetti che vi si 
trovano dentro. Supponiamo che io crei una stanza. Se ho fatto un buon 
progetto a monte so benissimo cosa conterrà. Posso quindi scrivere 
esattamente il contenuto di content (sic), non preoccupandomi di non 
aver ancora definito gli oggetti perché haste analizza il sorgente e poi 
crea l'albero degli oggetti (aggiungendo una proprietà parent). Se però 
non ho fatto il progetto prima di scrivere il codice o mi viene in mente 
di aggiungere un oggetto dopo che un beta-tester mi ha fatto notare che 
manca qualcosa, sono costretto a cambiare il codice già scritto e 
aggiungere detto oggetto nel content della stanza.
La soluzione solo parent è invece più "naturale" perché naturalmente le 
locazioni non hanno parent (non mi devo preoccupare di definirlo -- o 
magari hanno un parent comune definito dal WM in fase di 
inizializzazione) e gli oggetti normalmente li inserisco quando ho 
creato la locazione. Questa è la soluzione di inform con -> o con la 
proprietà found_in (per aggiungere più parent).
Analizzato questo fatto fondamentale penso che si potrebbe usare un 
approccio misto lasciando al programmatore la possibilità di usare l'uno 
o l'altro. Non so se questo provochi rallentamenti particolari nel 
sistema ma è naturalmente una cosa che si fa solo in fase di 
inizializzazione dell'object tree perché dopo dipenderà dalla 
particolare routine se usare content o parent. Questo sottintende il 
fatto che dopo l'inizializzazione e per tutta l'esecuzione ogni oggetto 
ha sempre sia un parent che un content. Se dobbiamo spostare un oggetto 
da una stanza al player aggiorniamo il content di quest'ultimo e il 
parent dell'oggetto.
Dopo queste considerazioni direi che un WM ridotto all'osso deve 
semplicemente gestire l'albero degli oggetti (in base ai comandi inviati 
dal parser), aggiornare alcune variabili di gioco e stampare i messaggi 
di descrizione e di risposta ai comandi.
Giusto per fare un po' di brainstorming mi viene in mente di definire 3 
oggetti di base:
1) game: gestisce le variabili di gioco e come evolve l'avventura...
2) player: il giocatore, quello che possiede, cosa può fare
3) world: il mondo delle locazioni e degli oggetti in esse contenuti
Giusto qualche idea/considerazione. MI piacerebbe aiutarti con il World 
Model ma sono troppo impegnato, ma un po' di discussione su come fare il 
WM perfetto, quello si può fare.
Ciao
Giovanni

 
Fantastico!
Gian.

 non può fare: è troppo incentrato sulla presenza di un solo giocatore...
multiplayer!! e vai!
Ciao
Giovanni

 
Assolutamente sì. Voglio che chi scrive un avventura non debba scrivere
manco una riga in più perché questa possa funzionare in multiplayer (beh,
se inizia a usare variabili e switch globali questi sono fatti suoi, e
nessuno glielo impedisce, ma il sistema, per conto suo, deve essere
totalmente MP).
Gian.

 totalmente MP).
D'altronde quello di un solo giocatore è un caso particolare di MP.
Ciao
Giovanni

 Cosa ne pensate?
a vederlo così mi sembra che il linguaggio si abbastanza facile visto 
che più o meno sono riuscito a capire tutto ciò che hai scritto.
Quando pensi ci sarà una libreria, e un poco di documentazione "for 
dummies"? (non è per farti fretta, solo curiosità di provare)
Che mi dici a proposito della multimedialità di haste?
ciao
marco

 
Anche a me è parso facile facile, ed inizio ad vere paura.
-- 
www.italiansaints.it
 - Il Fan Club Italiano Del Southampton f.c.
Anche un orologio rotto ha ragione, due volte al giorno.

 Che mi dici a proposito della multimedialità di haste?
Integrerò il toolit gtk al più presto. Penso di mettere dentro anche le
OpenAL. Sto finendo la gestione dei processi esterni per lanciare player e
cose del genere.
Gian.

Anche a me è parso facile facile, ed inizio ad vere paura.
A dire il vero iniziano a tremare i polsi anche a me..... ;-))
PaoloM
----------------------
http://www.maroncelli.net

 
Paura?
:-)

 :-)
Non vorrei che il tuo sistema sia troppo potente e facile da usare ;-)

 Anche a me è parso facile facile, ed inizio ad vere paura.
ritiro tutto, non sono riuscito neanche a stampare hello world :(
(non è a prova di dummies)
printl("Hello world.")
Error 3068 - : 0: Load error (Invalid symbol table position)
Premere un tasto per continuare . . .

riktik wrote:

Uhm, ma hai usato la versione linux?
Perché a me funziona: devo ancora finire le routine della versione
windows... che quindi è ancora quella MOLTO vecchia. 
(come avevo scritto nella prima mail ;-)
gian

 per cominciare a capire come funziona dovrebbe bastare.
Pensi di implementare qualcosa a supportdel debug?
bai
t

 Uhm, ma hai usato la versione linux?
no, non ho linux su questa macchina (lo so lo so, ma su questa non si può)
ciao

riktik wrote:

Allora resisti ancora un paio di giorni, che devo usare un paio di funzioni
specifiche per ogni sistema...
Gian.

tomb wrote:

Ovviamente. Tanto per cominciare, per il momento ho la funzione "inspect"
che verifica ricorsivamente il tipo e il contenuto di tutti gli oggetti.
Gian.

Giancarlo Niccolai wrote:

Dimenticavo: inspect si usa con inspect( variabile ); è già presente anche
il concetto di "informazioni di debug (tabella di linee nel sorgente).
Gian.