Battaglia Navale
Progetto di Programmazione II del 9 Febbraio 2015
Per consegnare:
per consegnare, aprite un terminale e cambiate la directory corrente (cd
) raggiungendo la directory che contiene i vostri sorgenti; potete verificarlo dando il comando ls
; poi, date il comando
/mnt/pboldi00/consegna *.java
potete effettuare più consegne, ma verrà corretta solo l'ultima avvenuta con successo.
Vi ricordo che la documentazione delle classi standard è disponibile puntando il browser su
file:///usr/share/javadoc/java/index.html
È necessario realizzare un sistema di gioco per Battaglia Navale. Questo sarà costituito da:
Tabella
, Nave
, Sparo
, e così via.Giocatore
– definita con precisione più avanti – e una classe concreta GiocatoreArtificiale
. Questa dovrà implementare l'interfaccia Giocatore
con dei comportamenti automatici, in qualunque modo vi venga in mente – anche molto semplice. Un'implementazione naïf potrebbe per esempio consistere banalmente nel lanciare degli spari in maniera casuale.GiocatoreInterattivo
per permettere all'utente di giocare.Il progetto verrà valutato prima di tutto in base al suo corretto funzionamento rispetto ai requisiti qui descritti; quindi, in base alla pulizia del codice ed alla sua documentazione (si consiglia di commentare il codice, in particolare anche scrivendo i commenti javadoc
).
Tra coloro che consegneranno un progetto leggibile e ben funzionante, l'aver fornito un'implementazione più o meno intelligente del GiocatoreArtificiale
costituirà un bonus – e un vanto personale per voi, visto che li faremo competere tra loro!
Descriviamo ora nei dettagli come realizzare le classi necessarie al progetto. Se lo ritenete, potete apportare cambiamenti alle segnature dei metodi proposti ed anche – se lo ritenete – alla struttura delle Classi, restando ovviamente all'interno dei requisiti esposti nel paragrafo introduttivo. È però importante che non cambiate in alcun modo l'interfaccia Giocatore
, né la semantica del risultato del metodo effettuaSparo
.
N.B.: Oltre ai metodi qui indicati, ricordatevi di aggiungere ad ogni classe un valido metodo toString()
e, dove lo ritenete, anche un metodo equals
e un metodo hashCode
(con le segnature appropriate e che soddisfino i contratti previsti).
Una classe che racchiude una coppia di coordinate valide per una tabella. Viene costruita tramite due int
, che può poi restituire attraverso i metodi int getX()
e int getY()
. Potete assumere che x e y siano coordinate valide.
Una classe che rappresenta una nave posizionata nel campo. Deve avere:
int lunghezza()
int getX()
e int getY()
che restituiscono le coordinate minori tra quelle occupate dalla nave. In altre parole, la casella (x,y) è la casella della nave più vicina a (0,0) (l'angolo in alto a sinistra della tabella).boolean isOrizzontale()
che ritorna true
sse la Nave è disposta orizzontalmente.Nave(int x, int y, boolean isOrizzontale)
.Come si è detto, potete aggiungere altri metodi secondo necessità.
Le sottoclassi concrete di Nave
sono
Portaerei
, di lunghezza 5; all'inizio, ce ne sarà 1.Corazzata
, di lunghezza 3; all'inizio, ce ne saranno 2.Cacciatorpediniere
, di lunghezza 2; all'inizio, ce ne saranno 3.Sottomarino
, di lunghezza 1; all'inizio, ce ne saranno 4.Questa classe deve rappresentare un campo di gioco di battaglia navale di un giocatore.
Tabella(int k)
costruisce una tabella vuota di dimensioni k × k.
boolean inserisci(Nave n)
: inserisce la nave n in questa tabella.
Il metodo restituisce true
se è stato possibile inserire la nave correttamente, ovvero se:
void terminaInserimento()
: conclude la fase di inserimento navi, rendendo immodificabile la tabella.
boolean isInizioLegale()
: restituisce true
se la tabella contiene esattamente il numero di navi descritto sopra. Controlla anche che tutte le navi inserite siano istanze dei tipi elencati sopra.boolean isVuota()
: restituisce true
se la tabella non contiene navi (p.e., se tutte le navi della tabella sono state affondate).int effettuaSparo(Sparo s)
: restituisce un valore che corrisponde all'esito dello sparo s
. La semantica di questo intero deve essere codificata come segue:
Sarebbe opportuno che questi numeri fossero rappresentati mediante costanti statiche.
static Tabella generaCasualmente(int k)
crea una tabella immodificabile di dimensioni k × k con tutte le navi iniziali posizionate casualmente. Potete assumere k sia sufficientemente grande affinché tutte le navi possano essere posizionate correttamente.
Si raccomanda di implementare un metodo toString()
che stampi opportunamente la tabella; questa rappresentazione deve indicare dove è stato effettuato uno sparo, e dove è presente una nave.
Questa interfaccia deve porre i requisiti di base perché una classe rappresenti un giocatore completo di battaglia navale. Un giocatore deve essere in grado di riempire la propria tabella (cosa che avverrà una sola volta all'inizio del gioco), e inoltre di giocare sulla tabella dell'avversario, decidendo dove sparare e ricevendo gli esiti degli spari.
Sparo prossimoSparo()
deve decidere dove lanciare il colpo sulla tabella avversaria.void risultatoUltimoSparo(int r)
comunica al giocatore l'esito dell'ultimo lancio restituito da prossimoSparo()
, secondo la semantica sopra descritta in effettuaSparo(Sparo s)
.Tabella costruisciTabella(int k)
deve chiedere a questo giocatore di costruire una tabella di dimensioni k × k, inserendovi tutte le navi.Supponiamo che un giocatore venga creato ex novo ad ogni partita. Quindi, la sequenza di mosse di un giocatore viene rappresentata da una sequenza di chiamate a prossimoSparo()
;
dopo ogni chiamata, al giocatore viene comunicato l'esito dello sparo mediante un'invocazione
del metodo risultatoUltimoSparo(r)
che influirà, presumibilmente, sui comportamenti successivi del giocatore.
Questa classe è un implementazione concreta dell'interfaccia Giocatore
, creata per permettere ad un utente di giocare da riga di comando. Avrà un costruttore vuoto e implementerà i metodi come segue:
Sparo prossimoSparo()
stampa, per prima cosa, la Tabella costruita da questo giocatore, in modo che l'utente sappia dove l'avversario ha sparato. Quindi, deve chiedere all'utente di inserire da riga di comando le due coordinate x e y in cui vuole sparare nella tabella avversaria.
void risultatoUltimoSparo(int r)
deve stampare a video, a parole, il risultato dell'ultimo sparo sulla tabella avversaria.
Tabella costruisciTabella(int k)
costruirà la tabella di questo giocatore. Per farlo, deve prima di tutto chiedere all'utente se vuole posizionare le navi casualmente, nel qual caso tutte le navi vengono posizionate casualmente nella tabella. Altrimenti, si scorrono le navi da inserire, e per ognuna si chiede all'utente la posizione in cui vuole inserirla (coordinata x, coordinata y, e se in orizzontale o in verticale).
Questa classe è un implementazione concreta dell'interfaccia Giocatore
, e decide in autonomia che colpi sparare. Avrà un costruttore vuoto e deve implementare tutti i metodi dell'interfaccia, nel modo che preferite.
Questa classe deve contenere tutto il necessario per rappresentare una partita. Il suo costruttore deve accettare due oggetti Giocatore
, a cui deve chiedere per prima cosa di costruire i rispettivi oggetti Tabella
. La dimensione della Tabella è fissata da questa classe a 10. Avute le tabelle, controlla che il loro metodo isInizioLegale()
dia true
e quindi invoca terminaInserimento()
.
Una Partita
deve fornire un metodo gioca()
che agirà così:
Sparo
Sparo
sulla tabella del giocatore B, ottenendo il risultato dello sparo.Ognuna di queste fasi deve stampare a video le mosse effettuate dai due giocatori, e i rispettivi risultati.
Dotate infine questa classe di un metodo main
che costruisca un oggetto Partita
con un GiocatoreInterattivo
e un GiocatoreArtificiale
e chiami il metodo gioca()
.