diff --git a/src/main/java/net/berack/upo/ai/problem2/Tris.java b/src/main/java/net/berack/upo/ai/problem2/Tris.java index b7d5123..d602611 100644 --- a/src/main/java/net/berack/upo/ai/problem2/Tris.java +++ b/src/main/java/net/berack/upo/ai/problem2/Tris.java @@ -1,5 +1,7 @@ package net.berack.upo.ai.problem2; +import static net.berack.upo.ai.problem2.Tris.Symbol.EMPTY; + import java.util.Arrays; import java.util.Iterator; @@ -9,7 +11,7 @@ import java.util.Iterator; * * @author Berack96 */ -public class Tris implements Iterable { +public class Tris implements Iterable { public static final int LENGTH = 3; /** @@ -31,23 +33,23 @@ public class Tris implements Iterable { } /** - * Possibili stati delle zone + * Possibili simboli delle zone */ - public static enum State { + public static enum Symbol { EMPTY, VALUE_X, VALUE_O } - private State[] tris; - private State currentTurn = State.VALUE_X; + private Symbol[] tris; + private Symbol currentTurn = Symbol.VALUE_X; /** * Crea una nuova istanza del gioco con tutti gli spazi vuoti */ public Tris() { - this.tris = new State[LENGTH * LENGTH]; - Arrays.fill(tris, State.EMPTY); + this.tris = new Symbol[LENGTH * LENGTH]; + Arrays.fill(tris, Symbol.EMPTY); } /** @@ -56,39 +58,49 @@ public class Tris implements Iterable { * @param coord le coordinate in cui il giocatore vuole giocare la sua mossa */ public Tris(Tris current, Coordinate coord) { - Arrays.copyOf(current.tris, current.tris.length); + this.tris = Arrays.copyOf(current.tris, current.tris.length); this.currentTurn = current.currentTurn; this.play(coord.x, coord.y); } + /** + * Indica il valore del simbolo che verrà inserito nella successiva mossa giocata, + * ovvero il simbolo che verrà giocato alla prossima mossa. + * + * @return il simbolo da giocare + */ + public Symbol getNextPlaySymbol() { + return this.currentTurn; + } + /** * Permette di prendere il valore della cella specificata dalle coordinate - * @param x la coordinata x da cui ricevere lo stato - * @param y la coordinata y da cui ricevere lo stato + * @param x la coordinata x da cui ricevere il simbolo + * @param y la coordinata y da cui ricevere il simbolo * @return il valore della cella */ - public State get(int x, int y) { + public Symbol get(int x, int y) { return this.tris[this.index(x, y)]; } /** * Permette di far avanzare il gioco, facendo giocare il turno al giocatore corrente nella cella specificata dalle coordinate. - * Nel caso in cui lo stato scelto dalle coordinate non risulti EMPTY il metodo lancerà una eccezione. + * Nel caso in cui il simbolo scelto dalle coordinate non risulti EMPTY il metodo lancerà una eccezione. * Una volta che si ha un vincitore questo metodo non potrà essere piu chiamato e lancerà una eccezione. * - * @param x la coordinata x in cui mettere lo stato - * @param y la coordinata y in cui mettere lo stato + * @param x la coordinata x in cui mettere il simbolo + * @param y la coordinata y in cui mettere il simbolo * @throws UnsupportedOperationException nel caso in cui si ha già avuto un vincitore */ public void play(int x, int y) { - if(this.haveWinner() != State.EMPTY) throw new UnsupportedOperationException("The game has already finished!"); + if(this.haveWinner() != Symbol.EMPTY) throw new UnsupportedOperationException("The game has already finished!"); if(!isPlayAvailable(x, y)) throw new IllegalArgumentException("The state to modify must be Empty!"); this.tris[this.index(x, y)] = this.currentTurn; this.currentTurn = switch(this.currentTurn) { - case VALUE_X -> State.VALUE_O; - case VALUE_O -> State.VALUE_X; - default -> State.EMPTY; + case VALUE_X -> Symbol.VALUE_O; + case VALUE_O -> Symbol.VALUE_X; + default -> Symbol.EMPTY; }; } @@ -102,7 +114,7 @@ public class Tris implements Iterable { * @return vero se la mossa può essere giocata, altrimenti falso */ public boolean isPlayAvailable(int x, int y) { - return this.tris[this.index(x, y)] == State.EMPTY; + return this.tris[this.index(x, y)] == Symbol.EMPTY; } /** @@ -114,9 +126,11 @@ public class Tris implements Iterable { * @return un array di coordinate disponibili per giocare. */ public Coordinate[] availablePlays() { + if(this.haveWinner() != EMPTY) return new Coordinate[0]; + var count = 0; for(var i = 0; i < this.tris.length; i++) - if(this.tris[i] == State.EMPTY) + if(this.tris[i] == Symbol.EMPTY) count += 1; var res = new Coordinate[count]; @@ -134,31 +148,31 @@ public class Tris implements Iterable { * Indica se si ha un vincitore e restituisce chi ha vinto. * @return EMPTY se non c'è ancora un vincitore, altrimenti restituisci il vincitore */ - public State haveWinner() { + public Symbol haveWinner() { // top left corner -> horizontal and vertical var state = this.tris[0]; - if(state != State.EMPTY) { + if(state != Symbol.EMPTY) { if(this.tris[1] == state && this.tris[2] == state) return state; if(this.tris[3] == state && this.tris[6] == state) return state; } // bottom right corner -> horizontal and vertical state = this.tris[8]; - if(state != State.EMPTY) { + if(state != Symbol.EMPTY) { if(this.tris[7] == state && this.tris[6] == state) return state; if(this.tris[5] == state && this.tris[2] == state) return state; } // central -> diagonals, horizontal and vertical state = this.tris[4]; - if(state != State.EMPTY) { + if(state != Symbol.EMPTY) { if(this.tris[0] == state && this.tris[8] == state) return state; if(this.tris[6] == state && this.tris[2] == state) return state; if(this.tris[3] == state && this.tris[5] == state) return state; if(this.tris[1] == state && this.tris[7] == state) return state; } - return State.EMPTY; + return Symbol.EMPTY; } /** @@ -176,11 +190,30 @@ public class Tris implements Iterable { } @Override - public Iterator iterator() { - return new Iterator() { + public String toString() { + var builder = new StringBuilder(); + for(var y = 0; y < LENGTH; y++) { + if(y > 0) builder.append("\n-----\n"); + + for(var x = 0; x < LENGTH; x++) { + if(x > 0) builder.append('|'); + builder.append(switch(this.tris[this.index(x, y)]) { + case VALUE_O -> 'O'; + case VALUE_X -> 'X'; + default -> ' '; + }); + } + } + + return builder.toString(); + } + + @Override + public Iterator iterator() { + return new Iterator() { int current = 0; @Override public boolean hasNext() { return current < tris.length; } - @Override public State next() { return tris[current++]; } + @Override public Symbol next() { return tris[current++]; } }; } } diff --git a/src/test/java/net/berack/upo/ai/problem2/TestTris.java b/src/test/java/net/berack/upo/ai/problem2/TestTris.java index 219e6af..affaf59 100644 --- a/src/test/java/net/berack/upo/ai/problem2/TestTris.java +++ b/src/test/java/net/berack/upo/ai/problem2/TestTris.java @@ -2,16 +2,16 @@ package net.berack.upo.ai.problem2; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; -import static net.berack.upo.ai.problem2.Tris.State.*; +import static net.berack.upo.ai.problem2.Tris.Symbol.*; import org.junit.jupiter.api.Test; -import net.berack.upo.ai.problem2.Tris.State; public class TestTris { @@ -21,13 +21,25 @@ public class TestTris { for(var state : tris) assertEquals(EMPTY, state); } + @Test + public void testContructor2() { + var tris = new Tris(); + tris.play(0, 0); + + var move = tris.availablePlays()[0]; + var second = new Tris(tris, move); + + assertFalse(second.isPlayAvailable(move.x, move.y)); + assertEquals(VALUE_O, second.get(move.x, move.y)); + } + @Test public void testPlay() { var tris = new Tris(); tris.play(0, 0); var i = 0; - var states = new Tris.State[] {VALUE_X, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY}; + var states = new Tris.Symbol[] {VALUE_X, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY}; for(var state : tris) assertEquals(states[i++], state); tris.play(2, 2); @@ -76,6 +88,8 @@ public class TestTris { var curr = actions[i]; tris.play(curr.x, curr.y); } + + assertEquals(0, tris.availablePlays().length, "The game is over, there aren't any moves left"); } @Test @@ -114,47 +128,47 @@ public class TestTris { // horizontal 1 line X var tris = new Tris(); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,0); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,1); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(0,0); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,2); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(2,0); - assertTrue(tris.haveWinner() == State.VALUE_X); + assertTrue(tris.haveWinner() == VALUE_X); // diagonal \ O tris = new Tris(); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(2,1); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,1); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(2,0); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(2,2); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,2); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(0,0); - assertTrue(tris.haveWinner() == State.VALUE_O); + assertTrue(tris.haveWinner() == VALUE_O); // vertical 2 column X tris = new Tris(); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,0); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(0,2); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,1); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(0,1); - assertTrue(tris.haveWinner() == State.EMPTY); + assertTrue(tris.haveWinner() == EMPTY); tris.play(1,2); - assertTrue(tris.haveWinner() == State.VALUE_X); + assertTrue(tris.haveWinner() == VALUE_X); } }