Progetto PacMan
Transcript
Progetto PacMan
Appello di Giugno e Luglio 2008 Pac-Man Laurea Triennale in Comunicazione Digitale Laboratorio di Programmazione 1 Descrizione Il progetto consiste nel realizzare un programma per simulare (con notevoli restrizioni) il video-gioco Pac Man1 . In particolare data una configurazione iniziale per il campo di gioco (posizione di pac-man, dei fantasmi e delle pillole) e una sequenza di mosse si dovrà simulare l’avanzamento della partita. 2 Pac-Man 2.1 Il Gioco Nella versione originale del gioco, il giocatore deve guidare una creatura sferica di colore giallo, chiamata pac-man, facendole mangiare tutti i numerosi puntini disseminati ordinatamente all’interno del labirinto e, nel far questo, deve evitare di farsi mangiare a sua volta da quattro fantasmi, pena la perdita immediata di una delle vite a disposizione. Per facilitare il compito al giocatore sono presenti, presso gli angoli dello schermo di gioco, quattro pillole speciali (power pills) che rovesciano la situazione rendendo vulnerabili i fantasmi, che diventano blu e, per qualche istante, invertono la loro marcia; per guadagnare punti, è possibile in questa fase andare a caccia degli stessi fantasmi, per mangiarli. Una volta fagocitati, però, questi tornano alla base (il rettangolo al centro dello schermo) sotto forma di un paio di occhi, per rigenerarsi ed attaccare di nuovo pac-man. Figura 1: Coin-Op Screenshoot. Completato un labirinto attraverso la fagocitazione di 1 http://it.wikipedia.org/wiki/Pac-Man tutti i puntini, pac-man passa a quello successivo, identico nella struttura. Durante il gioco, ogni cosa che finisce in bocca a pac-man viene contabilizzata sotto forma di punti. I puntini disseminati lungo il labirinto valgono 10 punti ognuno mentre le power pills di punti ne offrono 50 ognuna. È possibile ottenere punti extra anche mangiando i fantasmi una volta resi vulnerabili da una delle power pills: in tal caso si ottengono 200, 400, 800 e 1.600 punti fagocitando i fantasmi in sequenza (200 punti con il primo fantasma, 400 con il secondo e cosı̀ via). Esiste anche un’altra possibilità per l’aumento dei propri punti: a un certo momento, durante l’esecuzione di ogni livello, appare al centro del labirinto un’icona, il più delle volte rappresentante un frutto. Se il giocatore è abbastanza abile da recuperarla prima che scompaia, accresce il proprio punteggio. 2.2 Semplificazioni e Varianti Ovviamente non è possibile, nell’ambito del progetto, implementare interamente il gioco stesso ma dovrete realizzarne una simulazione che permetta il passaggio da una configurazione ad un’altra. Il tutto con le seguenti limitazioni/varianti rispetto al gioco originale. • Pac-man si muove secondo una logica predeterminata e senza l’intervento del giocatore; • esistono solo quattro fantasmi (blinky, pinky, inky e clyde) ognuno segue una sua logica preconfezionata; • l’area centrale di ristoro dei fantasmi non esiste; • quando fagocitato da pac-man il fantasma riappare nella configurazione successiva nel punto in cui si trovava; • l’effetto della pillola dura per cinque configurazioni successive; • si hanno solo tre vite, l’esser mangiato dai fantasmi ha solo l’effetto di perdere un omino, la situazione di pillole, puntini e fantasmi rimane inalterata e pac-man (al termine della configurazione successiva) riparte dal punto in cui si trovava quando è stato mangiato; • non ci sono i bonus. 3 Classi da Realizzare È obbligatorio realizzare in Java il programma descritto nelle sezioni precedenti utilizzando le seguenti classi: MazeElement MazeElement è una classe astratta usata per descrivere il comportamento, in astratto, dei vari elementi in gioco. Attributi • int x e int y: variabili di istanza che memorizzano la posizione corrente dell’elemento sul campo di gioco. Notare la peculiare presenza di alcuni attributi nella classe astratta, vale sempre la regola che lo stato degli oggetti deve essere nascosto ma in questo caso deve poter essere usato dalle classi concrete che estenderanno la classe astratta. Metodi • public void move(int x, int y): sposta la posizione corrente del corrispondente elemento al punto specificato dai valori passatigli. Non fa nessun controllo sulla validità dello spostamento. • public String toString(): metodo dall’ovvio significato ereditato da Object e ridefinito in modo da garantire la rappresentazione di ogni singolo elemento come spiegato descrivendo la configurazione del campo da gioco. • public int getValue(): metodo che ritorna il valore associato all’elemento quando fagocitato da pac-man; ovviamente non tutti gli elementi hanno un valore associato. • public int getHorizontalOffset() e public int getVerticalOffset(): metodi per determinare di quanto e in che direzione l’elemento si muove. La classe MazeElement dovrà essere estesa da diverse altri classi che rappresenteranno i vari elementi del gioco. Nel seguito descriveremo le singole classi senza entrare nel merito dell’implementazione dei metodi ereditati ma solo del comportamento delle sue istanze. Pill Le istanze della classe Pill (che estende MazeElement) rappresentano le pillole energetiche. Ovviamente non si spostano dalla posizione in cui si trovano e si possono trovare ovunque all’interno del campo di gioco e in quantità non prefissata. Il punteggio a loro associato è 50. Quando ingoiata, la pillola energizzante, rende i fantasmi vulnerabili agli attacchi di pac-man per 5 turni; ingoiare una pillola energizzante prima dello scadere dell’effetto di un’altra pillola energizzante ha l’effetto di ripristinare il computo dei turni. Dot Le istanze della classe Dot (che estende MazeElement) rappresentano i puntini sparpagliati nel campo di gioco. Valgono le stesse regole descritte per le pillole energetiche: non si spostano e possono essere ovunque in qualsiasi quantità. Il punteggio a loro associato è 10. Wall La classe Wall estende MazeElement e rappresenta le caselle piene che danno forma al campo di gioco. Sono inamovibili e infagocitabili. Empty La classe Empty estende MazeElement e rappresenta le caselle vuote che ovviamente non si spostano e non possono essere mangiate. MobileElement MobileElement, classe astratta derivata da MazeElement, rappresenta la classe progenitrice di tutte le entità mobili (fantasmi e pac-man) presenti nel gioco. Attributi • Behavior bev: definisce il comportamento dell’elemento mobile (vedi descrizione classe Behavior). Nota. I costruttori delle sottoclassi di MobileElement non hanno un parametro di tipo Behavior il comportamento è cablato nella classe stessa. PacMan La classe PacMan rappresenta, ovviamente, pac-man e se ne ha al più un’istanza attiva sul campo di gioco. Muovendosi, pac-man, fagocita tutti i puntini e le pillole energetiche che incontra lasciando il vuoto al loro posto. L’incontro con un fantasma gli è fatale se non è attivo l’effetto di una pillola energizzante. Quando muore, pac-man, riappare nella stessa posizione all’interno della configurazione successiva. Ghost La classe Ghost rappresenta i fantasmi e se ne hanno al più quattro istanze attive sul campo di gioco. I fantasmi quando si spostano lasciano il campo di gioco inalterato (cioè non mangiano né puntini né pillole energetiche). Se si scontrano con pac-man e il sistema non è sotto l’effetto di una pillola energizzante cioè sono trascorsi più di cinque turni da quando pacman ha ingoiato una pillola energizzante allora riescono a divorarlo. Vice versa se si scontrano nel periodo di attività della pillola energizzante è pac-man ad avere la meglio e fagocita i fantasmi, il primo varrà 200 punti, il secondo 400, il terzo 800 e il quarto 1600. Behavior Questa classe astratta rappresenta il comportamento che caratterizza i singoli elementi mobili presenti sul campo da gioco. Ci sono cinque comportamenti predefiniti associati ad altrettante classi concrete: • Pac-Man Behavior (classe PacManBehavior) — rappresenta il comportamento di pac-man e consiste nell’andare dritto finché non scontra un muro in quel caso gira a sinistra; inizialmente si muove verso destra; • Blinky Behavior (classe BlinkyBehavior) — rappresenta il comportamento del fantasma rosso ed è in tutto e per tutto uguale a quello di pac-man; inizialmente si muove verso sinistra; • Pinky Behavior (classe PinkyBehavior) — rappresenta il comportamento del fantasma rosa e consiste nell’andare dritto finché non scontra un muro in quel caso gira a destra; inizialmente si muove verso sinistra; • Inky Behavior (classe InkyBehavior) — rappresenta il comportamento del fantasma azzurro e consiste nell’andare dritto finché non scontra un muro in tal caso si gira di 180 gradi e torna indietro; inizialmente di muove verso l’alto; • Clyde Behavior (classe ClydeBehavior) — rappresenta il comportamento del fantasma arancione e consiste nell’andare dritto finché non scontra un muro in tal caso si gira di 180 gradi e torna indietro; inizialmente di muove verso il basso; indipendentemente dal comportamento, tutti gli elementi mobili si muovono di una casella alla volta e raggiungere il bordo del campo di gioco è equivalente ad aver incontrato un muro. Attributi • int oldx, oldy: rappresentano le coordinate prima dello spostamento; Metodi I metodi definiti da questa classe e realizzati nelle sottoclassi saranno usati dalle istanze della classi concrete derivate da MobileElement per realizzare lo spostamento: • abstract public int getNewX() e abstract public int getNewY(): restituiscono rispettivamente la posizione sulle ascisse e sulle ordinate che assumerà l’elemento dopo lo spostamento. Maze Maze è la classe che descrive il campo di gioco (lo schermo del videogioco per intendersi) durante il gioco stesso. Sostanzialmente può essere schematizzato come una matrice di n × m elementi, con n e m non definiti a priori. Ogni elemento o sarà vuoto o conterrà un pezzo di muro, un puntino, una pillola energizzante, un fantasma o pacman. In ogni istante un’istanza della classe Maze fornirà uno snapshot della situazione (configurazione) corrente del campo di gioco. La configurazione è codificata in una stringa come segue: • una coppia di interi (seguito ognuno da una barretta verticale — |), compresi tra 1 e 100, rappresentano le dimensioni del campo di gioco (prima il numero di righe, poi il numero di colonne); 0 0 7 10 Figura 2: Esempio di configurazione. • un intero tra 0 e 5 (estremi inclusi) seguito da una barretta verticale (|) rappresentate il fatto che la configurazione sia sotto l’effetto (e per quanti turni ancora) di una pillola energizzante; • una coppia di interi (seguito ognuno da una barretta verticale — |) rappresentanti, rispettivamente, il punteggio corrente e il numero di vite rimaste; • segue la descrizione del campo di gioco; ogni riga è rappresentata da una sequenza di coppie nc dove n ∈ [1, · · · , 9] rappresenta il numero di caselle contigue contenenti lo stesso tipo di elementi mentre c ∈ {’X’, ’r’, ’p’, ’c’, ’o’, ’P’, ’d’, ’W’, ’ ’} rappresenta l’elemento in questione; notare che avere n ∈ [1, · · · , 9] non limita a 9 la lunghezza delle righe in quanto si possono avere due o più coppie contigue dello stesso elemento, ad es. 9 7 ; • i caratteri usati nella configurazione hanno il seguente significato: – ’X’ — pac-man; – ’r’ — fantasma rosso (comportamento blinky); – ’p’ — fantasma rosa (comportamento pinky); – ’c’ — fantasma azzurro (comportamento inky); – ’o’ — fantasma arancione (comportamento clyde); – ’P’ — pillola energizzante; – ’d’ — puntino; – ’W’ — pezzo di muro; – ’ ’ — casella vuota. • $ rappresenta la fine di una riga del campo di gioco; La Figura 2 mostra una possibile configurazione per un campo di gioco di 7 × 10 caselle. La corrispondente stringa sarà: 7|10|0|1010|2| 9W1W$2d2 2W3d1W$1W1X1W3 2W1d1W$1W1 3W1 2W2 $ 1P1o1W3d1W1p1 1W$1W3 2W1r1 1P1W$3W1c6W$ Notare che, anche se si è andati a capo, l’esempio riportato, nel file sarà su un’unica riga e che il simbolo rappresenta uno spazio. Attributi • MazeElement[][] maze: variabile d’istanza che memorizza la configurazione corrente del campo di gioco. Ogni elemento della matrice conterrà un elemento diverso da null. • int rows e int columns: numero totale delle righe e delle colonne che compongono il campo di gioco. • String filename: variabile di istanza contenente il nome del file su cui si salvano le configurazioni e che viene usato per il ripristino della configurazione. Implementare anche i corrispondenti metodi publici String getFilename() e void setFilename(String) dall’ovvio significato. • int score: variabile di istanza contenente il punteggio corrente. Metodi e Costruttori • public Maze(String filename): costruttore che configura il campo di gioco, filename è il nome del file su disco contenente una serie di configurazioni, una per riga, l’ultima configurazione letta diventerà la configurazione corrente. • void setMazeElement(int, int, MazeElement) e MazeElement getMazeElement(int, int): metodi accessori per la gestione del singolo elemento del campo di gioco; • public String toString(): metodo che crea e ritorna una stringa rappresentante la configurazione corrente della campo di gioco, sfruttando le convenzioni descritte precedentemente; • public void setMaze(String): metodo che permette di inizializzare il campo di gioco alla configurazione passata come parametro, la configurazione è codificata nella stringa secondo le stesse convenzioni descritte precedentemente; • public String getMaze(): metodo che ritorna la configurazione corrente codificata secondo le convenzioni descritte precedentemente; • public void write(): metodo che appende la configurazione corrente del campo di gioco al file specificato dall’attributo filename; • public void reload(): metodo che rilegge dall’ultima riga del file indicato dall’attributo filename la configurazione del campo di gioco; • public void backup(String): metodo che effettua una copia di backup della configurazione del campo di gioco, salvandola in un file il cui nome è specificato nella stringa passata come argomento, il file verrà creato ex-novo; • void move(): metodo che fa avanzare la configurazione di un passo; partendo dall’angolo in alto a sinistra e procedendo da sinistra a destra per righe successive; lo spostamento deve essere fatto in situ e non su una copia della matrice sfruttando i vari metodi forniti dai vari MazeElement, sarà il metodo move() a gestire i casi particolari (come le collisioni); Attenzione che i vari metodi potrebbero sollevare delle eccezioni queste non sono state specificate nel testo ma dovranno essere gestite cum grano salis. Ovviamente come sono definite ed usate sarà oggetto della valutazione. A parte quanto espressamente richiesto, è lasciata piena libertà sull’implementazione delle singole classi e sull’eventuale introduzione di classi aggiuntive, a patto di seguire correttamente le regole del paradigma di programmazione orientata agli oggetti ed i principi di buona programmazione. Si suggerisce di porre particolare attenzione alla scelta dei modificatori relativi a variabili d’istanza e metodi, alla creazione di metodi di accesso alle variabili di istanza quando questi siano ritenuti necessari, alla definizione di classi e metodi astratti e di metodi o di variabili statici dove questi risultino opportuni, nonché alla dichiarazione e alla gestione delle eccezioni che possono venire lanciate dai vari metodi e alle relazioni di ereditarietà tra le varie classi. Si ricorda altresı̀ di rispettare alla lettera il formato descritto per interpretare il contenuto del file. Non è richiesto e non verrà valutato l’utilizzo di particolari modalità grafiche di visualizzazione: è sufficiente una qualunque modalità di visualizzazione basata sull’uso dei caratteri. È invece espressamente richiesto di non utilizzare package non standard di Java (si possono quindi utilizzare java.util, java.io e cosı̀ via) e di rispettare l’interfaccia fornita. I progetti che useranno pacchetti non standard non saranno corretti. 4 Modalità di Consegna Il progetto deve essere svolto a gruppi di al massimo tre persone che intendono sostenere l’intero esame di Fondamenti di Architetture e Programmazione - Laboratorio di Programmazione nell’appello di Giugno 2008 o Luglio 2008, e deve essere consegnato entro mezzanotte di domenica 22 giugno 2008, tramite il sito di sottoposizione pubblicato all’indirizzo: http://homes.dsi.unimi.it/~malchiod/LP/sottoposizione Per sottomettere un progetto è necessario che tutti i componenti del gruppo si registrino; successivamente un componente potrà creare un gruppo a cui affiliare i rimanenti componenti. La sottoposizione è fatta a nome del gruppo e vale per tutti i suoi componenti. Va sottolineato che delle sottoposizioni successive cancellano quelle fatte in precedenza. Dovranno essere consegnati tutti i sorgenti Java che permettano al programma di essere eseguito correttamente, compressi in un archivio di tipo ZIP che estragga i file nella directory in cui si trova l’archivio stesso (altri tipi di sottoposizioni verranno automaticamente rifiutate dal sito), senza creare una nuova directory. All’archivio dovrà anche essere accluso un breve documento in formato txt, rtf o pdf in cui: • verrà descritto il modo in cui interfacciarsi con il programma; • saranno illustrate le principali scelte implementative e le strategie utilizzate per svolgere il progetto Il sistema rifiuterà automaticamente le sottoposizioni i cui sorgenti contengano errori rilevati in fase di compilazione. È inoltre richiesto di consegnare, entro lunedı̀ 23 giugno 2008, una copia cartacea del codice sorgente e della documentazione del progetto, nella casella di posta (fisica, non elettronica) del docente di riferimento, situata all’ingresso del DSI/DICo, indicando chiaramente nome, cognome e numero di matricola di tutti i componenti del gruppo, nonché il turno e il docente di riferimento. Nella copia cartacea indicare anche in quali appelli i singoli componenti del gruppo intendono discutere il progetto. Le sottoposizioni che non seguono queste specifiche ed i programmi che non compilano correttamente non verranno valutati. È richiesto di indicare chiaramente all’inizio di tutti i documenti consegnati nome, cognome e matricola dei vari componenti del gruppo. 5 Valutazione La discussione del progetto con i singoli studenti verterà sulle modalità di implementazione adottate e sulla padronanza di alcuni dei concetti necessari per realizzare il progetto e/o spiegati a lezione. La valutazione del progetto sarà fatta in base alla: • conformità dell’implementazione scelta per risolvere il problema con il paradigma di programmazione a oggetti; • conformità del codice presentato alle regole di buona programmazione; • adeguatezza del documentazione presentata; • assenza di errori nel programma. Walter Cazzola Dipartimento di Informatica e Comunicazione Via Comelico 39/41 20135 Milano Stanza S220 — Tel. +39.02.503.16300 e-mail: [email protected] Dario Malchiodi Dipartimento di Scienze dell’Informazione Via Comelico 39/41 20135 Milano Stanza S238 — Tel. +39.02.503.16338 e-mail: [email protected]