Studente: Luca Del Bolgia The RulesGame Attività Progettuale di Linguaggi e Modelli Computazionali M Prof.: Enrico Denti Studente: Luca Del Bolgia
Descrizione Del Problema Editor di giochi: Architettura predefinita; Regole Personalizzabili; Utilizzo di BOT: Random (“Stupidi”); Guidati da euristiche (“Intelligenti”);
Definizione delle regole Creazione dello stato iniziale RulesGame Language Definizione delle regole Creazione dello stato iniziale Scrittura JAXB File XML di configurazione PercorsoParser Esecuzione del gioco Inizializzazione del gioco Lettura tuProlog
Architettura Predefinita Due schieramenti: Attaccanti: devono raggiungere un TOT di obiettivi; Difensori: devono ostacolare ed eliminare gli attaccanti; Tipologie di caselle: Causano effetti sia positivi che negativi ai giocatori che le attraversano; Entità Passive: Interagiscono con i giocatori che si fermano su di esse; Numero di Mosse: Il numero di mosse viene deciso in modo random a run-time
Architettura Predefinita Si utilizza il linguaggio Prolog per creare l’architettura di base; Sono quattro le regole principali del sistema: Lo spostamento del giocatore; La gestione dei turni; I BOT random; I BOT guidati da euristiche;
Lo stato corrente
RulesGame Language Nasce il bisogno di un linguaggio semplice e facilmente comprensibile sia da utenti principianti che utenti esperti di programmazione, per creare regole personalizzate di (quasi) qualsiasi tipo per un gioco. Il gioco non sarà completamente implementabile: una parte del sistema è pre-implementato, e definisce l’architettura di base. Alcune regole di base potranno essere superate da utenti esperti del linguaggio Prolog, che potranno scrivere le regole in modo che il sistema si comporti in modo completamente personalizzato.
RulesGame Language Token della grammatica: < CASELLE: "caselle"> <QUADRA_APERTA: "[" > <QUADRA_CHIUSA: "]" > < TONDA_APERTA:"(" > < TONDA_CHIUSA:")" > <DUE_PUNTI: ":"> <ATTACCANTI: "attaccanti" > <DIFENSORI: "difensori" > < ATTACCANTE: "attaccante" > < DIFENSORE:"difensore" > <ENTITA_PASSIVE: "entitapassive"> <STRUMENTI: "strumenti"> < INIZIALIZZAZIONE: "inizializzazione" > <DEFAULT_CASELLA: "free"| "windefender"| "winattacker" | "killdefender" | "killattacker" | "kill" | "block" | "damage" | “cure“ | "damageattacker“ | "damagedifender"> <DEFAULT_INFO: "health"> <DEFAULT_EURISTICA: "scorenemies"| "life">
RulesGame Language Token della grammatica: <DEFAULT_ENTITA_PASSIVA_ATTACCANTE: "score" | "scoredestroy"> <DEFAULT_ENTITA_PASSIVA_DIFENSORE: "destroy"> < ELIMINATED: "eliminated" > < NOTHING: "nothing" > < VIRGOLA: "," > < BOOLEAN: "true"|"false"|"True"|"False"> < BOT: "bot"> < MOSSE: "mosse" > < HURT: "hurt"> < HEAL: "heal" > <NOME : (["a"-"z","_"])+ > <CODICE: ("{")(["A"-"Z","a"-"z","_","(",")","[","]","0"-"9",":","- ",".",",","!","'","|","<",">","=","+","*","/","^","\\","%"])+("}") > < NUMERO: ["1"-"9"](["0"-"9"])* >
RulesGame Language Produzioni della grammatica: Scopo::=Regole Inizializzazione <EOF> Regole::=Caselle Giocatori EntitaPassive Caselle::= <CASELLE><QUADRA_APERTA> (RegolaCasella)+ <QUADRA_CHIUSA> Giocatori::=Attaccanti Difensori Attaccanti::= <ATTACCANTI> <QUADRA_APERTA> Info Euristica Obiettivi Difensori::= <DIFENSORI> <QUADRA_APERTA> Info Euristica EntitaPassive::= <ENTITA_PASSIVE> <QUADRA_APERTA> (RegolaEntitaPassiva)* <QUADRA_CHIUSA>
RulesGame Language Produzioni della grammatica: RegolaCasella::= Nome <DUE_PUNTI>(<DEFAULT_CASELLA>| Codice) Info::= < NOTHING > | <DEFAULT_INFO>| Codice Euristica::= <DEFAULT_EURISTICA>|Codice Obiettivi::= <NUMERO> RegolaEntitaPassiva::= Nome<DUE_PUNTI> <ATTACCANTE> (< NOTHING >| < ELIMINATED >|< HURT >| < HEAL >| <DEFAULT_ENTITA_PASSIVA_ATTACCANTE>| Codice) <DIFENSORE> (< NOTHING >|< ELIMINATED >|< HURT >| < HEAL >| <DEFAULT_ENTITA_PASSIVA_DIFENSORE>| Codice) Codice::= < CODICE > Nome::= < NOME >
RulesGame Language Produzioni della grammatica: Inizializzazione::= < INIZIALIZZAZIONE > < QUADRA_APERTA > Griglia Mosse < QUADRA_CHIUSA > Griglia::= (Casella)+ Casella::= < NUMERO > < VIRGOLA >< NUMERO >< DUE_PUNTI > Nome < VIRGOLA >(< NOTHING >|Nome)< VIRGOLA > (Attaccante|Difensore|< NOTHING >) Attaccante::= < ATTACCANTE > < NUMERO >(< TONDA_APERTA >Bot <TONDA_CHIUSA >)? Difensore::= < DIFENSORE > < NUMERO >(< TONDA_APERTA >Bot Mosse::= < MOSSE ><DUE_PUNTI ><NUMERO > Bot::= < BOT >< VIRGOLA >< BOOLEAN >
RulesGame Language-esempio 1/5 Per prima cosa si creano le tipologie di caselle, definendo il nome del tipo e quali sono gli effetti dell’attraversamento su una di esse. Nome Effetto caselle [ libero:windefender bloccato:block ] Può essere sostituito da codice Prolog, racchiuso tra graffe, per maggiori info vedere il manuale.
RulesGame Language-esempio 2/5 Si definiscono informazioni aggiuntive, euristica e obiettivi dello schieramento attaccanti. Informazioni Obiettivi attaccanti [ nothing scorenemies 1 ] Euristica Può essere sostituito da codice Prolog, racchiuso tra graffe, per maggiori info vedere il manuale.
RulesGame Language-esempio 3/5 Si definiscono informazioni aggiuntive, euristica dello schieramento difensori. Informazioni difensori [ nothing scorenemies ] Euristica Può essere sostituito da codice Prolog, racchiuso tra graffe, per maggiori info vedere il manuale.
RulesGame Language-esempio 4/5 Si definiscono le entità passive: nome, effetto sull’attaccante ed effetto sul difensore per ognuna. Effetto Attaccante Nome entitapassive [ fine: attaccante score difensore nothing ] Effetto Difensore Può essere sostituito da codice Prolog, racchiuso tra graffe, per maggiori info vedere il manuale.
RulesGame Language-esempio 5/5 Infine si crea lo stato iniziale. Tipo casella Colonna inizializzazione [ 1,1:libero,nothing,attaccante1 1,2:libero,nothing,nothing ... 2,3:libero,nothing,difensore1(bot,true) 3,1:bloccato,nothing,nothing 3,2:libero,nothing,nothing 3,3:libero,fine,nothing mosse:2 ] Entità passiva Riga Nome giocatore Definizione BOT Max Mosse
RulesGame Language Poiché il linguaggio non presenta self-embedding esso è una linguaggio di tipo 3. La grammatica appena presentata è di tipo 2, poiché non è lineare ne a destra ne a sinistra, però è facile trasformarla in una grammatica lineare a destra, semplicemente eliminando un sacco di simboli non terminali, che sono stati utilizzati per avere maggiore chiarezza. Scopo::=Regole Inizializzazione <EOF> Regole::=Caselle Giocatori EntitaPassive Caselle::= <CASELLE><QUADRA_APERTA>…………… La soluzione è pessima in quanto a leggibilità e chiarezza.
RulesGame Language Prima produzione più pulita e chiara… Altra soluzione, cambiando “un poco” la grammatica: Scopo::= Caselle::= <CASELLE><QUADRA_APERTA>…………… <GIOCO> Regole Inizializzazione <EOF> <QUADRA_APERTA> Caselle Giocatori EntitaPassive Inizializzazione <QUADRA_CHIUSA> <EOF> Prima produzione più pulita e chiara…
RulesGame Language Regole ed inizializzazione File di configurazione XML
JAXB:Java Architecture for XML Binding JAXB permette agli sviluppatori java di accedere e processare I dati XML senza conoscere XML; per esempio non c’è bisogno di creare o usare un parser SAX oppure scrivere metodi di callback.
File XSD di esempio-RulesGame.xsd <?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.jaxb.parser/RulesGame/" targetNamespace="http://www.jaxb.parser/RulesGame/"> <element name="Gioco" type="tns:gioco"></element> <complexType name="gioco"> <sequence> <element name="Motore" type="tns:motore"></element> <element name="Regole" type="tns:regole"></element> </sequence> </complexType> <simpleType name="motore"> <restriction base="string"></restriction> </simpleType> <complexType name="regole"> <element name="StatoIniziale" type="tns:statoIniziale"></element> <element name="Mosse" type="int"></element> <element name="BOTS" type="tns:bots"></element> <simpleType name="statoIniziale"> <complexType name="bots"> <element name="BOT" type="tns:bot" maxOccurs="unbounded" minOccurs="0"> </element> <complexType name="bot"> <attribute name="nome" type="string"></attribute> <attribute name="euristica" type="boolean"></attribute> </schema>
JAXB:creare le classi java da file XSD (Binding a schema) Fare il binding di uno schema significa generare un set di classi java che lo rappresentano. Ogni classe avrà dei metodi get e set per gli attributi ed elementi interni all’elemento XML corrispondente.
JAXB:scrivere un file XML Per scrivere un file XML bisogna creare un’istanza del XmlRootElement ed inizializzarla a dovere (utilizzando le set). Infine utilizzare un istanza della classe Marshaller (si ottiene dal JABXContext) per creare il file XML corrispondente.
JAXB:scrivere un file XML-esempio 1/3 try { // la stringa “jaxb.parser” rappresenta il package delle classi create con JAXB JAXBContext jc = JAXBContext.newInstance("jaxb.parser"); jaxb.parser.ObjectFactory factory=new jaxb.parser.ObjectFactory(); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,new Boolean(true)); jaxb.parser.Gioco gioco=factory.createGioco(); //creazione del XmlRootElement
JAXB:scrivere un file XML-esempio 2/3 jaxb.parser.Regole regole=factory.createRegole(); jaxb.parser.Bots bots=factory.createBots(); regole.setStatoIniziale("["+statoCaselle+","+statoAttaccanti+","+statoDifensori+","+statoTurno+"]"); regole.setMosse(mosse); //mosse è un intero regole.setBOTS(bots); gioco.setMotore(motore); //motore è una stringa gioco.setRegole(regole);
JAXB:scrivere un file XML-esempio 3/3 marshaller.marshal(gioco, new FileOutputStream(fileName)); } catch (JAXBException e) { e.printStackTrace(); catch (FileNotFoundException e)
JAXB:leggere un file XML Per leggere un file XML bisogna creare un’istanza dell’Unmarshaller (si ottiene dal JABXContext), dal quale ricaveremo l’XmlRootElement. Quindi tramite le get sarà possibile accedere a tutti i “campi” del file XML.
JAXB:leggere un file XML-esempio 1/2 JAXBContext jc = JAXBContext.newInstance("jaxb.parser"); //creazione dell’Unmarshaller Unmarshaller unmarshaller = jc.createUnmarshaller(); //creazione del RootElement dal file XML Gioco gioco=(Gioco)unmarshaller.unmarshal(new File(nomeFile)); //getMotore restituirà una stringa writer.println(gioco.getMotore());
JAXB:leggere un file XML-esempio 2/2 JAXBContext jc = JAXBContext.newInstance("jaxb.parser"); Unmarshaller unmarshaller = jc.createUnmarshaller(); Gioco gioco=(Gioco)unmarshaller.unmarshal(new File(nomeFile)); Regole regole=gioco.getRegole(); Bots bots=regole.getBOTS(); List<Bot> list=bots.getBOT(); statoCorrente=new Stato(regole.getStatoIniziale(),list); MAX_MOSSE=regole.getMosse();
JAXB-conclusioni JAXB risulta molto utile e facile da utilizzare; in questo modo si riesce a disaccoppiare totalmente il programma java dalla sintassi XML dei file utilizzati. Inoltre un vantaggio non da poco è dato dalla creazione e lettura di file tramite tecniche che utilizzano un XSD Schema: difatti l’XML verrà scritto seguendo le regole dettate nello schema, e, in automatico, verrà validato all’atto della lettura, dando una eccezione nel caso di validazione errata. XSD inoltre permette maggiori vincoli nei confronti di DTD, quindi maggiori vincoli sintattici. Sito di approfondimento: http://www.oracle.com/technetwork/articles/javase/index-140168.html#introjb JAXB scaricabile da: http://www.oracle.com/technetwork/java/1-6-136288.html Per utilizzare al meglio JAXB consiglio il plugin eclipse XJC: http://www.webmanie.de/cms158/index.php?option=com_content&view=article&id=13&Itemid=0
Inizializzazione ed esecuzione del gioco Nel file XML di configurazione sono presenti alcune informazioni utili per: Creare il “motore” del gioco Informazioni all’interno del file XML; Architettura di base già implementata; Inizializzare il gioco Stato iniziale (in formato Prolog); Mosse massime per giocatore; Lista dei bot;
tuProlog-il motore del sistema La comunicazione tra motore ed applicazione è gestita da tuProlog, e le query fatte al motore Prolog possono essere di 4 tipologie: Richiesta di spostamento Prossimo turno Spostamento Bot Random Spostamento Bot con Euristica
tuProlog-query Richiesta di spostamento spostamento(Percorso, Giocatore, Siniziale, Sfinale, SUCCESS) Prossimo turno prossimoTurno(Scorrente, Sfinale)
tuProlog-query Spostamento Bot Random Spostamento Bot con Euristica movimentoCasualeBot(MaxMovimento, Siniziale, Sfinale, SUCCESS) Spostamento Bot con Euristica movimentoEuristicoBot(Mosse, Siniziale, Sfinale, Profondita, SUCCESS)
PercorsoParser Il compito di questo compilatore è di trasformare una stringa rappresentante lo spostamento richiesto da parte dell’utente attraverso la griglia di gioco, in una corretta rappresentazione del tragitto in Prolog, e quindi utilizzabile correttamente nella query al motore del gioco tramite tuProlog. Utente nella casella 3,4: up,right,down Prolog: [transito(on(2,4)),transito(on(2,5)),fine(on(3,5))]
PercorsoParser -top down S F Linguaggio Tipo 3 Automa Riconoscitore <TOKEN_MOSSE> S F Automa Riconoscitore “top down” <VIRGOLA> Linguaggio Tipo 3 S <TOKEN_MOSSE> F | <TOKEN_MOSSE> F , S Grammatica Tipo 3: Espressione regolare: (<TOKEN_MOSSE> ,)* <TOKEN_MOSSE>
PercorsoParser -bottom up I S Linguaggio Tipo 3 Automa Riconoscitore <TOKEN_MOSSE> I S Automa Riconoscitore “bottom up” <VIRGOLA> Linguaggio Tipo 3 I <TOKEN_MOSSE>| <TOKEN_MOSSE> S S , I Grammatica Tipo 3: Espressione regolare: <TOKEN_MOSSE> (,<TOKEN_MOSSE>)*
Possibili sviluppi futuri Aggiungere nuove funzionalità di base tramite la costruzione di regole personalizzate. Modificare l’architettura Prolog di modo che possa sostenere anche altre tipologie di gioco (con un relativo aumento del delay per Bot Euristici). Creazione di una interfacca utente personalizzata, correlata alle regole implementate, utilizzando la buona modularità del sistema.