Battaglia navale

Da Head First Java O'Reilly, leggo il capitolo 5 che tratta la progettazione e lo sviluppo di un primo semplice programma in Java.

Si tratta di una piccola battaglia navale giocata dall'utente contro il computer. Si gioca su una tabella 7x7.
  • setup: tre navi vengono messe sulla tabella.
  • il gioco: si itera finché non ci sono più navi:
    • si chiedono all'utente le coordinate ("C6", "A0", ...)
    • il risultato può essere hit, miss, kill
    • In caso di miss si chiede la prossima mossa.
    • In caso di kill si rimuove la nave, se non ci sono più navi, il gioco termina, altrimenti si chiede la prossima mossa.
    • In caso di hit si rimuove la cella e si chiede la mossa successiva.
  • fine: si valuta il risultato dell'utente.
La prima versione é ancora più semplice: la tabella si riduce ad un array [0, 6], chiamiamo la classe che implementa questa soluzione DotCom.Simple, tale classe avrà un metodo per creare un bersaglio e un metodo per verificare un colpo:
package DotCom;

public class Simple {
private int[] target;
private int hits;

public void setTarget(int [] target) {
this.target = target;
}

public Result check(int x) {
return Result.Miss;
}
}
La classe Result é un enum che può assumere i valori Miss, Hit, Kill:
public enum Result {
Miss, Hit, Kill
}
Scrivo un primo test per l'applicazione:
public class SimpleTest {
//...

@Test
public void testSimple() {
System.out.println("first test");
int[] target = {2,3,4};
Simple instance = new Simple();
instance.setTarget(target);

Result result = instance.check(2);
assertEquals(Result.Hit, result);
}
}
Come atteso il test ritorna errore, ma scriviamo ora una prima implementazione reale del metodo check():
public Result check(int x) {
Result result = Result.Miss;

for(int cell : target) {
if(x == cell) {
result = Result.Hit;
hits++;
break;
}
}

if(hits == target.length) {
result = Result.Kill;
}

System.out.println(result);
return result;
}
Scrivo ora un test più completo che simula quello che sarà il main reale:
@Test
public void fakeSimpleMain() {
System.out.println("fake main");

int guesses = 0;
int base = (int) (Math.random() * 5); // [0,4]
int[] target = {base, base + 1, base + 2};
Simple instance = new Simple();
instance.setTarget(target);

for(int i = 0; i < 7; ++i) {
++guesses;
if(instance.check(i) == Result.Kill) {
assertEquals(guesses, base + 3);
return;
}
}
fail("can't kill");
}
Ma c'é un bug evidente, che viene evidenziato da questo test:
@Test
public void bug1() {
System.out.println("bug1");

int base = (int) (Math.random() * 5); // [0,4]
int[] target = {base, base + 1, base + 2};
Simple instance = new Simple();
instance.setTarget(target);

for(int i = 0; i < 7; ++i) {
if(instance.check(base) == Result.Kill) {
fail("no kill expected");
}
}
}
Ripetendo il colpo sulla prima cella del bersaglio si ottiene, incongruamente, l'affondamento della nave.

Nessun commento:

Posta un commento