diff --git a/src/main/java/org/toop/ConsoleGui.java b/src/main/java/org/toop/ConsoleGui.java index 9be17fc..203568c 100644 --- a/src/main/java/org/toop/ConsoleGui.java +++ b/src/main/java/org/toop/ConsoleGui.java @@ -5,11 +5,10 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.toop.eventbus.*; import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; -import org.toop.game.*; import org.toop.game.tictactoe.*; +import org.toop.game.tictactoe.ai.MinMaxTicTacToe; public class ConsoleGui { @@ -147,12 +146,12 @@ public class ConsoleGui { Player current = game.getCurrentPlayer(); int move = -1; - if (ai1 != null && current.name() == ai1 || ai2 != null && current.name() == ai2) { + if (ai1 != null && current.getName() == ai1 || ai2 != null && current.getName() == ai2) { move = ai.findBestMove(game); } else { System.out.printf( "%s's (%c) turn. Please choose an empty cell between 0-8: ", - current.name(), current.move()); + current.getName(), current.getSymbol()); String input = scanner.nextLine(); try { @@ -180,7 +179,7 @@ public class ConsoleGui { case WIN: { - System.out.printf("%s has won the game.\n", current.name()); + System.out.printf("%s has won the game.\n", current.getName()); keepRunning = false; break; } @@ -197,7 +196,7 @@ public class ConsoleGui { new Events.ServerEvents.SendCommand( connectionId, "gameid " + ticTacToeGameId, - "player " + current.name(), + "player " + current.getName(), "MOVE", String.valueOf(move))); diff --git a/src/main/java/org/toop/game/Player.java b/src/main/java/org/toop/game/Player.java deleted file mode 100644 index 97c3d69..0000000 --- a/src/main/java/org/toop/game/Player.java +++ /dev/null @@ -1,3 +0,0 @@ -package org.toop.game; - -public record Player(String name, char move) {} diff --git a/src/main/java/org/toop/game/GameBase.java b/src/main/java/org/toop/game/tictactoe/GameBase.java similarity index 96% rename from src/main/java/org/toop/game/GameBase.java rename to src/main/java/org/toop/game/tictactoe/GameBase.java index 099a70d..ff0aa91 100644 --- a/src/main/java/org/toop/game/GameBase.java +++ b/src/main/java/org/toop/game/tictactoe/GameBase.java @@ -1,4 +1,4 @@ -package org.toop.game; +package org.toop.game.tictactoe; public abstract class GameBase { public enum State { diff --git a/src/main/java/org/toop/game/tictactoe/Player.java b/src/main/java/org/toop/game/tictactoe/Player.java new file mode 100644 index 0000000..e9c520d --- /dev/null +++ b/src/main/java/org/toop/game/tictactoe/Player.java @@ -0,0 +1,21 @@ +package org.toop.game.tictactoe; + +public class Player { + + String name; + char symbol; + + Player(String name, char symbol) { + this.name = name; + this.symbol = symbol; + } + + public String getName() { + return this.name; + } + + public char getSymbol() { + return this.symbol; + } + +} diff --git a/src/main/java/org/toop/game/tictactoe/TicTacToe.java b/src/main/java/org/toop/game/tictactoe/TicTacToe.java index d1f54d5..83d7e9b 100644 --- a/src/main/java/org/toop/game/tictactoe/TicTacToe.java +++ b/src/main/java/org/toop/game/tictactoe/TicTacToe.java @@ -6,7 +6,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.toop.backend.tictactoe.ParsedCommand; import org.toop.backend.tictactoe.TicTacToeServerCommand; -import org.toop.game.*; public class TicTacToe extends GameBase implements Runnable { @@ -98,7 +97,7 @@ public class TicTacToe extends GameBase implements Runnable { if (state != State.INVALID) { // Tell all players who made a move and what move was made // TODO: What is the reaction of the game? WIN, DRAW etc? - String player = getCurrentPlayer().name(); + String player = getCurrentPlayer().getName(); addSendToQueue( "SVR GAME MOVE {PLAYER: \"" + player @@ -152,7 +151,7 @@ public class TicTacToe extends GameBase implements Runnable { return State.INVALID; } - grid[index] = getCurrentPlayer().move(); + grid[index] = getCurrentPlayer().getSymbol(); movesLeft--; if (checkWin()) { @@ -214,7 +213,7 @@ public class TicTacToe extends GameBase implements Runnable { /** This method copies the board, mainly for AI use. */ public TicTacToe copyBoard() { - TicTacToe clone = new TicTacToe(players[0].name(), players[1].name()); + TicTacToe clone = new TicTacToe(players[0].getName(), players[1].getName()); System.arraycopy(this.grid, 0, clone.grid, 0, this.grid.length); clone.movesLeft = this.movesLeft; clone.currentPlayer = this.currentPlayer; diff --git a/src/main/java/org/toop/game/tictactoe/ai/MinMaxTicTacToe.java b/src/main/java/org/toop/game/tictactoe/ai/MinMaxTicTacToe.java index b3b96b6..a1b3b8c 100644 --- a/src/main/java/org/toop/game/tictactoe/ai/MinMaxTicTacToe.java +++ b/src/main/java/org/toop/game/tictactoe/ai/MinMaxTicTacToe.java @@ -2,7 +2,7 @@ package org.toop.game.tictactoe.ai; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.toop.game.*; +import org.toop.game.tictactoe.GameBase; import org.toop.game.tictactoe.TicTacToe; public class MinMaxTicTacToe { diff --git a/src/test/java/org/toop/game/tictactoe/GameBaseTest.java b/src/test/java/org/toop/game/tictactoe/GameBaseTest.java new file mode 100644 index 0000000..4b70e8d --- /dev/null +++ b/src/test/java/org/toop/game/tictactoe/GameBaseTest.java @@ -0,0 +1,82 @@ +package org.toop.game.tictactoe; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class GameBaseTest { + + private static class TestGame extends GameBase { + public TestGame(int size, Player p1, Player p2) { + super(size, p1, p2); + } + + @Override + public State play(int index) { + if (!isInside(index)) return State.INVALID; + grid[index] = getCurrentPlayer().getSymbol(); + // Just alternate players for testing + currentPlayer = (currentPlayer + 1) % 2; + return State.NORMAL; + } + } + + private GameBase game; + private Player player1; + private Player player2; + + @BeforeEach + void setUp() { + player1 = new Player("A", 'X'); + player2 = new Player("B", 'O'); + game = new TestGame(3, player1, player2); + } + + @Test + void testConstructor_initializesGridAndPlayers() { + assertEquals(3, game.getSize()); + assertEquals(9, game.getGrid().length); + + for (char c : game.getGrid()) { + assertEquals(GameBase.EMPTY, c); + } + + assertEquals(player1, game.getPlayers()[0]); + assertEquals(player2, game.getPlayers()[1]); + assertEquals(player1, game.getCurrentPlayer()); + } + + @Test + void testIsInside_returnsTrueForValidIndices() { + for (int i = 0; i < 9; i++) { + assertTrue(game.isInside(i)); + } + } + + @Test + void testIsInside_returnsFalseForInvalidIndices() { + assertFalse(game.isInside(-1)); + assertFalse(game.isInside(9)); + assertFalse(game.isInside(100)); + } + + @Test + void testPlay_alternatesPlayersAndMarksGrid() { + // First move + assertEquals(GameBase.State.NORMAL, game.play(0)); + assertEquals('X', game.getGrid()[0]); + assertEquals(player2, game.getCurrentPlayer()); + + // Second move + assertEquals(GameBase.State.NORMAL, game.play(1)); + assertEquals('O', game.getGrid()[1]); + assertEquals(player1, game.getCurrentPlayer()); + } + + @Test + void testPlay_invalidIndexReturnsInvalid() { + assertEquals(GameBase.State.INVALID, game.play(-1)); + assertEquals(GameBase.State.INVALID, game.play(9)); + } +} \ No newline at end of file diff --git a/src/test/java/org/toop/game/tictactoe/ai/MinMaxTicTacToeTest.java b/src/test/java/org/toop/game/tictactoe/ai/MinMaxTicTacToeTest.java index a8beaf3..098ede9 100644 --- a/src/test/java/org/toop/game/tictactoe/ai/MinMaxTicTacToeTest.java +++ b/src/test/java/org/toop/game/tictactoe/ai/MinMaxTicTacToeTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.toop.game.GameBase; +import org.toop.game.tictactoe.GameBase; import org.toop.game.tictactoe.TicTacToe; /** Unit tests for MinMaxTicTacToe AI. */