Battaglia navale migliorata

Proseguo la lettura di Head First Java O'Reilly, capitolo 6.

Si era creata una prima versione semplificata del programma di battaglia navale, ora introduciamo cambiamenti per rendere l'applicazione più aderente alle specifiche iniziali.

Per prima cosa creo un nuovo enumeratore che definisce le celle disponibili nel tavoliere della battaglia navale:

package DotCom;

public enum Coord {
A1, A2, A3, A4, A5, A6, A7,
B1, B2, B3, B4, B5, B6, B7,
C1, C2, C3, C4, C5, C6, C7,
D1, D2, D3, D4, D5, D6, D7,
E1, E2, E3, E4, E5, E6, E7,
F1, F2, F3, F4, F5, F6, F7,
G1, G2, G3, G4, G5, G6, G7,
}
Creiamo poi la classe Buster che gestisce le navi sul tavoliere:

package DotCom;

import java.util.ArrayList;

public class Buster {

private ArrayList<Ship> ships = new ArrayList<Ship>();
private int guesses = 0;

public void add(Ship ship) {
ships.add(ship);
}

/**
*
* @param c where to shoot
* @return true if all ships are destroyed
*/
public boolean shoot(Coord c) {
guesses++;

System.out.println("[" + c + "] " + Result.Miss);
return false;
}

public int getGuesses() {
return guesses;
}
}

Le navi da colpire vengono passate all'istanza di Buster per mezzo del metodo add() che semplicemente aggiunge la nave alla lista privata. L'algoritmo per la creazione di una nave nel tavoliere é non banale, fra l'altro occorre evitare che due navi si sovrappongano, e aldilà dello scopo dell'esempio. Ce le dobbiamo costruire a mano e fare attenzione a costruirle in modo coerente.

Il metodo shoot() ha al momento una implementazione minimale, lo completo più avanti. Deve funzionare in questo modo:
  • accetta in input la coordinata del nostro colpo;
  • incrementa il contatore dei colpi sparati;
  • verifica se il colpo ha successo o meno e, se anche l'ultima nave é stata affondata, si ritorna true (parte ancora da implementare);
  • se il colpo é andato a vuoto lo si comunica all'utente prima di tornare false.

Abbiamo poi un getter per la variabile di istanza guesses, che tiene sotto controllo il numero di tentativi fatti.

Aggiungo un nuovo test, che utilizza Buster:

@Test
public void testShip() {
System.out.println("test a ship");

Buster buster = new Buster();

ArrayList<Coord> t1 = new ArrayList<Coord>();
t1.add(Coord.A1);
t1.add(Coord.B1);
t1.add(Coord.C1);
buster.add(new Ship("Endeavour", t1));

for(Coord c : Coord.values()) {
if(buster.shoot(c)) {
int guesses = buster.getGuesses();
assertEquals(Coord.C1.ordinal() + 1, guesses);
return;
}
}

fail("ship still floating");
}

Naturalmente fallisce, data l'implementazione che ho dato a shoot(), ma ora ne completo il codice in questo modo:

public boolean shoot(Coord c) {
guesses++;

for (Ship ship : ships) {
switch (ship.check(c)) {
case Hit:
System.out.print("[" + c + "] " + ship.getName() + ": ");
System.out.println(Result.Hit);

return false;
case Kill:
System.out.print("[" + c + "] " + ship.getName() + ": ");
System.out.println("Destroyed!");

ships.remove(ship);
return ships.isEmpty();
}
}

System.out.println("[" + c + "] " + Result.Miss);
return false;
}

Si cicla sulle navi presenti nella lista di Buster. Se check() riporta che la nave é stata colpita (ma non affondata) si segnala la cosa e si ritorna false, se la nave é affondata viene tolta dalla lista e si ritorna true se la lista é ora vuota.
Se nessuno di questi due casi sono verificati su nessuna delle navi in lista, allora segnaliamo che il colpo é andato a vuoto.

Il test viene passato correttamente, ne aggiungiamo un altro per verificare quello che sarebbe l'uso reale dell'applicativo:

@Test
public void testThreeShip() {
System.out.println("test three ships");

Buster buster = new Buster();

ArrayList<Coord> t1 = new ArrayList<Coord>();
t1.add(Coord.A1);
t1.add(Coord.B1);
t1.add(Coord.C1);
buster.add(new Ship("Endeavour", t1));

ArrayList<Coord> t2 = new ArrayList<Coord>();
t2.add(Coord.B3);
t2.add(Coord.B4);
t2.add(Coord.B5);
buster.add(new Ship("Enterprise", t2));

ArrayList<Coord> t3 = new ArrayList<Coord>();
t3.add(Coord.D1);
t3.add(Coord.D2);
t3.add(Coord.D3);
buster.add(new Ship("Beagle", t3));

for(Coord c : Coord.values()) {
if(buster.shoot(c)) {
int guesses = buster.getGuesses();
assertEquals(Coord.D3.ordinal() + 1, guesses);
return;
}
}

fail("ship still floating");
}

Nessun commento:

Posta un commento