mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
refactored game
This commit is contained in:
48
game/src/test/java/org/toop/game/PlayerTest.java
Normal file
48
game/src/test/java/org/toop/game/PlayerTest.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package org.toop.game;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class PlayerTest {
|
||||
private Player playerA;
|
||||
private Player playerB;
|
||||
private Player playerC;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
playerA = new Player("test A", 'x', 'Z', 'i');
|
||||
playerB = new Player("test B", 'O', (char)12, (char)-34, 's');
|
||||
playerC = new Player("test C", (char)9, '9', (char)-9, '0', 'X', 'O');
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNameGetter_returnsTrueForValidName() {
|
||||
assertEquals("test A", playerA.name());
|
||||
assertEquals("test B", playerB.name());
|
||||
assertEquals("test C", playerC.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValuesGetter_returnsTrueForValidValues() {
|
||||
final char[] valuesA = playerA.values();
|
||||
assertEquals('x', valuesA[0]);
|
||||
assertEquals('Z', valuesA[1]);
|
||||
assertEquals('i', valuesA[2]);
|
||||
|
||||
final char[] valuesB = playerB.values();
|
||||
assertEquals('O', valuesB[0]);
|
||||
assertEquals(12, valuesB[1]);
|
||||
assertEquals((char)-34, valuesB[2]);
|
||||
assertEquals('s', valuesB[3]);
|
||||
|
||||
final char[] valuesC = playerC.values();
|
||||
assertEquals((char)9, valuesC[0]);
|
||||
assertEquals('9', valuesC[1]);
|
||||
assertEquals((char)-9, valuesC[2]);
|
||||
assertEquals('0', valuesC[3]);
|
||||
assertEquals('X', valuesC[4]);
|
||||
assertEquals('O', valuesC[5]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.toop.game.tictactoe;
|
||||
|
||||
import org.toop.game.Game;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TicTacToeAITest {
|
||||
private TicTacToe game;
|
||||
private TicTacToeAI ai;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
game = new TicTacToe("AI", "AI");
|
||||
ai = new TicTacToeAI();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMove_returnWinningMoveWithDepth1() {
|
||||
// X X -
|
||||
// O O -
|
||||
// - - -
|
||||
game.play(new Game.Move(0, 'X'));
|
||||
game.play(new Game.Move(3, 'O'));
|
||||
game.play(new Game.Move(1, 'X'));
|
||||
game.play(new Game.Move(4, 'O'));
|
||||
|
||||
final Game.Move move = ai.findBestMove(game, 1);
|
||||
|
||||
assertNotNull(move);
|
||||
assertEquals('X', move.value());
|
||||
assertEquals(2, move.position());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMove_blockOpponentWinDepth1() {
|
||||
// - - -
|
||||
// O - -
|
||||
// X X -
|
||||
game.play(new Game.Move(6, 'X'));
|
||||
game.play(new Game.Move(3, 'O'));
|
||||
game.play(new Game.Move(7, 'X'));
|
||||
|
||||
final Game.Move move = ai.findBestMove(game, 1);
|
||||
|
||||
assertNotNull(move);
|
||||
assertEquals('O', move.value());
|
||||
assertEquals(8, move.position());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMove_preferCornerOnEmpty() {
|
||||
final Game.Move move = ai.findBestMove(game, 0);
|
||||
|
||||
assertNotNull(move);
|
||||
assertEquals('X', move.value());
|
||||
assertTrue(Set.of(0, 2, 6, 8).contains(move.position()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMove_findBestMoveDraw() {
|
||||
// O X -
|
||||
// - O X
|
||||
// X O X
|
||||
game.play(new Game.Move(1, 'X'));
|
||||
game.play(new Game.Move(0, 'O'));
|
||||
game.play(new Game.Move(5, 'X'));
|
||||
game.play(new Game.Move(4, 'O'));
|
||||
game.play(new Game.Move(6, 'X'));
|
||||
game.play(new Game.Move(7, 'O'));
|
||||
game.play(new Game.Move(8, 'X'));
|
||||
|
||||
final Game.Move move = ai.findBestMove(game, game.getLegalMoves().length);
|
||||
|
||||
assertNotNull(move);
|
||||
assertEquals('O', move.value());
|
||||
assertEquals(2, move.position());
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package java.org.toop.tictactoe;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.toop.game.GameBase;
|
||||
import org.toop.game.Player;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.toop.game.tictactoe;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.toop.game.Player;
|
||||
|
||||
class PlayerTest {
|
||||
|
||||
private Player playerA;
|
||||
private Player playerB;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
playerA = new Player("testA", 'X');
|
||||
playerB = new Player("testB", 'O');
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNameGetter_returnsTrueForValidName() {
|
||||
assertEquals("testA", playerA.getName());
|
||||
assertEquals("testB", playerB.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSymbolGetter_returnsTrueForValidSymbol() {
|
||||
assertEquals('X', playerA.getSymbol());
|
||||
assertEquals('O', playerB.getSymbol());
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package org.toop.game.tictactoe.ai;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.toop.game.GameBase;
|
||||
import org.toop.tictactoe.TicTacToe;
|
||||
|
||||
/** Unit tests for MinMaxTicTacToe AI. */
|
||||
public class MinMaxTicTacToeTest {
|
||||
|
||||
private MinMaxTicTacToe ai;
|
||||
private TicTacToe game;
|
||||
|
||||
@BeforeEach // called before every test is done to make it work
|
||||
void setUp() {
|
||||
ai = new MinMaxTicTacToe();
|
||||
game = new TicTacToe("AI", "Human");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMoveWinningMoveAvailable() {
|
||||
// Setup board where AI can win immediately
|
||||
// X = AI, O = player
|
||||
// X | X | .
|
||||
// O | O | .
|
||||
// . | . | .
|
||||
game.grid =
|
||||
new char[] {
|
||||
'X',
|
||||
'X',
|
||||
GameBase.EMPTY,
|
||||
'O',
|
||||
'O',
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY
|
||||
};
|
||||
game.movesLeft = 4;
|
||||
|
||||
int bestMove = ai.findBestMove(game);
|
||||
|
||||
// Ai is expected to place at index 2 to win
|
||||
assertEquals(2, bestMove);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMoveBlocksOpponentWin() {
|
||||
// Setup board where player could win next turn
|
||||
// O | O | .
|
||||
// X | . | .
|
||||
// . | . | .
|
||||
game.grid =
|
||||
new char[] {
|
||||
'O',
|
||||
'O',
|
||||
GameBase.EMPTY,
|
||||
'X',
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY
|
||||
};
|
||||
|
||||
int bestMove = ai.findBestMove(game);
|
||||
|
||||
// AI block at index 2 to continue the game
|
||||
assertEquals(2, bestMove);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBestMoveCornerPreferredOnEmptyBoard() {
|
||||
// On empty board, center (index 4) is strongest
|
||||
int bestMove = ai.findBestMove(game);
|
||||
|
||||
assertTrue(Set.of(0, 2, 6, 8).contains(bestMove));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoMinimaxScoresWinPositive() {
|
||||
// Simulate a game state where AI has already won
|
||||
TicTacToe copy = game.copyBoard();
|
||||
copy.grid =
|
||||
new char[] {
|
||||
'X',
|
||||
'X',
|
||||
'X',
|
||||
'O',
|
||||
'O',
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY
|
||||
};
|
||||
|
||||
int score = ai.doMinimax(copy, 5, false);
|
||||
|
||||
assertTrue(score > 0, "AI win should yield positive score");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoMinimaxScoresLossNegative() {
|
||||
// Simulate a game state where human has already won
|
||||
TicTacToe copy = game.copyBoard();
|
||||
copy.grid =
|
||||
new char[] {
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'X',
|
||||
'X',
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY,
|
||||
GameBase.EMPTY
|
||||
};
|
||||
|
||||
int score = ai.doMinimax(copy, 5, true);
|
||||
|
||||
assertTrue(score < 0, "Human win should yield negative score");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoMinimaxDrawReturnsZero() {
|
||||
// Simulate a draw position
|
||||
TicTacToe copy = game.copyBoard();
|
||||
copy.grid =
|
||||
new char[] {
|
||||
'X', 'O', 'X',
|
||||
'X', 'O', 'O',
|
||||
'O', 'X', 'X'
|
||||
};
|
||||
|
||||
int score = ai.doMinimax(copy, 0, true);
|
||||
|
||||
assertEquals(0, score, "Draw should return 0 score");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user