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]