Formatting

This commit is contained in:
Bas de Jong
2025-10-07 19:47:45 +02:00
parent 783cfd22e1
commit 3c385e27b0
50 changed files with 2017 additions and 1749 deletions

View File

@@ -3,34 +3,37 @@ package org.toop.game;
import java.util.Arrays;
public abstract class Game {
public enum State {
NORMAL, DRAW, WIN,
}
public enum State {
NORMAL,
DRAW,
WIN,
}
public record Move(int position, char value) {}
public record Move(int position, char value) {}
public static final char EMPTY = (char)0;
public static final char EMPTY = (char) 0;
public final int rowSize;
public final int columnSize;
public final char[] board;
public final int rowSize;
public final int columnSize;
public final char[] board;
protected Game(int rowSize, int columnSize) {
assert rowSize > 0 && columnSize > 0;
protected Game(int rowSize, int columnSize) {
assert rowSize > 0 && columnSize > 0;
this.rowSize = rowSize;
this.columnSize = columnSize;
this.rowSize = rowSize;
this.columnSize = columnSize;
board = new char[rowSize * columnSize];
Arrays.fill(board, EMPTY);
}
board = new char[rowSize * columnSize];
Arrays.fill(board, EMPTY);
}
protected Game(Game other) {
rowSize = other.rowSize;
columnSize = other.columnSize;
board = Arrays.copyOf(other.board, other.board.length);
}
protected Game(Game other) {
rowSize = other.rowSize;
columnSize = other.columnSize;
board = Arrays.copyOf(other.board, other.board.length);
}
public abstract Move[] getLegalMoves();
public abstract State play(Move move);
}
public abstract Move[] getLegalMoves();
public abstract State play(Move move);
}

View File

@@ -1,25 +1,27 @@
package org.toop.game;
public abstract class TurnBasedGame extends Game {
public final int turns;
public final int turns;
protected int currentTurn;
protected int currentTurn;
protected TurnBasedGame(int rowSize, int columnSize, int turns) {
super(rowSize, columnSize);
protected TurnBasedGame(int rowSize, int columnSize, int turns) {
super(rowSize, columnSize);
assert turns >= 2;
this.turns = turns;
}
}
protected TurnBasedGame(TurnBasedGame other) {
super(other);
turns = other.turns;
currentTurn = other.currentTurn;
}
protected TurnBasedGame(TurnBasedGame other) {
super(other);
turns = other.turns;
currentTurn = other.currentTurn;
}
protected void nextTurn() {
currentTurn = (currentTurn + 1) % turns;
}
protected void nextTurn() {
currentTurn = (currentTurn + 1) % turns;
}
public int getCurrentTurn() { return currentTurn; }
}
public int getCurrentTurn() {
return currentTurn;
}
}

View File

@@ -3,17 +3,17 @@ package org.toop.game.othello;
import org.toop.game.TurnBasedGame;
public final class Othello extends TurnBasedGame {
Othello() {
super(8, 8, 2);
}
Othello() {
super(8, 8, 2);
}
@Override
public Move[] getLegalMoves() {
return new Move[0];
}
@Override
public Move[] getLegalMoves() {
return new Move[0];
}
@Override
public State play(Move move) {
return null;
}
}
@Override
public State play(Move move) {
return null;
}
}

View File

@@ -4,8 +4,8 @@ import org.toop.game.AI;
import org.toop.game.Game;
public final class OthelloAI extends AI<Othello> {
@Override
public Game.Move findBestMove(Othello game, int depth) {
return null;
}
@Override
public Game.Move findBestMove(Othello game, int depth) {
return null;
}
}

View File

@@ -1,8 +1,7 @@
package org.toop.game.tictactoe;
import org.toop.game.TurnBasedGame;
import java.util.ArrayList;
import org.toop.game.TurnBasedGame;
public final class TicTacToe extends TurnBasedGame {
private int movesLeft;
@@ -19,8 +18,8 @@ public final class TicTacToe extends TurnBasedGame {
@Override
public Move[] getLegalMoves() {
final ArrayList<Move> legalMoves = new ArrayList<>();
final char currentValue = getCurrentValue();
final ArrayList<Move> legalMoves = new ArrayList<>();
final char currentValue = getCurrentValue();
for (int i = 0; i < board.length; i++) {
if (board[i] == EMPTY) {
@@ -44,12 +43,12 @@ public final class TicTacToe extends TurnBasedGame {
return State.WIN;
}
nextTurn();
nextTurn();
if (movesLeft <= 2) {
if (movesLeft <= 0 || checkForEarlyDraw(this)) {
return State.DRAW;
}
if (movesLeft <= 0 || checkForEarlyDraw(this)) {
return State.DRAW;
}
}
return State.NORMAL;
@@ -60,7 +59,9 @@ public final class TicTacToe extends TurnBasedGame {
for (int i = 0; i < 3; i++) {
final int index = i * 3;
if (board[index] != EMPTY && board[index] == board[index + 1] && board[index] == board[index + 2]) {
if (board[index] != EMPTY
&& board[index] == board[index + 1]
&& board[index] == board[index + 2]) {
return true;
}
}
@@ -83,7 +84,7 @@ public final class TicTacToe extends TurnBasedGame {
private boolean checkForEarlyDraw(TicTacToe game) {
for (final Move move : game.getLegalMoves()) {
final TicTacToe copy = new TicTacToe(game);
final TicTacToe copy = new TicTacToe(game);
if (copy.play(move) == State.WIN || !checkForEarlyDraw(copy)) {
return false;
@@ -93,7 +94,7 @@ public final class TicTacToe extends TurnBasedGame {
return true;
}
private char getCurrentValue() {
return currentTurn == 0? 'X' : 'O';
}
}
private char getCurrentValue() {
return currentTurn == 0 ? 'X' : 'O';
}
}

View File

@@ -1,83 +1,81 @@
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.*;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.toop.game.Game;
class TicTacToeAITest {
private TicTacToe game;
private TicTacToeAI ai;
private TicTacToe game;
private TicTacToeAI ai;
@BeforeEach
void setup() {
game = new TicTacToe();
ai = new TicTacToeAI();
}
@BeforeEach
void setup() {
game = new TicTacToe();
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'));
@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);
final Game.Move move = ai.findBestMove(game, 1);
assertNotNull(move);
assertEquals('X', move.value());
assertEquals(2, move.position());
}
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'));
@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);
final Game.Move move = ai.findBestMove(game, 1);
assertNotNull(move);
assertEquals('O', move.value());
assertEquals(8, move.position());
}
assertNotNull(move);
assertEquals('O', move.value());
assertEquals(8, move.position());
}
@Test
void testBestMove_preferCornerOnEmpty() {
final Game.Move move = ai.findBestMove(game, 0);
@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()));
}
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'));
@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);
final Game.Move move = ai.findBestMove(game, game.getLegalMoves().length);
assertNotNull(move);
assertEquals('O', move.value());
assertEquals(2, move.position());
}
}
assertNotNull(move);
assertEquals('O', move.value());
assertEquals(2, move.position());
}
}