From 9e3ee7625415a5a7960b45155c2aec53fcdcd345 Mon Sep 17 00:00:00 2001 From: lieght Date: Fri, 19 Sep 2025 19:17:52 +0200 Subject: [PATCH] Added AI and made the options of adding those AI's actually work. --- .../toop/frontend/UI/LocalGameSelector.java | 15 +++- .../toop/frontend/games/LocalTicTacToe.java | 68 +++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/toop/frontend/UI/LocalGameSelector.java b/src/main/java/org/toop/frontend/UI/LocalGameSelector.java index a5c1bad..c601bbc 100644 --- a/src/main/java/org/toop/frontend/UI/LocalGameSelector.java +++ b/src/main/java/org/toop/frontend/UI/LocalGameSelector.java @@ -66,7 +66,20 @@ public class LocalGameSelector extends JFrame { String playerTypes = (String) playerTypeSelectionBox.getSelectedItem(); String selectedGame = (String) gameSelectionComboBox.getSelectedItem(); - LocalTicTacToe lttt = new LocalTicTacToe(true, "127.0.0.1", "5001"); + LocalTicTacToe lttt = null; + + if (playerTypes.equals("Player vs Player")) { + logger.info("Player vs Player"); + lttt = new LocalTicTacToe(true, "127.0.0.1", "5001"); + } else { + if (playerTypes.equals("Player vs AI")) { + logger.info("Player vs AI"); + lttt = new LocalTicTacToe(true, "127.0.0.1", "5001", new boolean[] { false, true }); + } else { + logger.info("AI vs Player"); + lttt = new LocalTicTacToe(true, "127.0.0.1", "5001", new boolean[] { true, false }); + } + } if ("Tic Tac Toe".equalsIgnoreCase(selectedGame)) { if (tttBoard == null) { diff --git a/src/main/java/org/toop/frontend/games/LocalTicTacToe.java b/src/main/java/org/toop/frontend/games/LocalTicTacToe.java index 64fd46b..d3d4f27 100644 --- a/src/main/java/org/toop/frontend/games/LocalTicTacToe.java +++ b/src/main/java/org/toop/frontend/games/LocalTicTacToe.java @@ -4,12 +4,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.toop.eventbus.Events; import org.toop.eventbus.GlobalEventBus; +import org.toop.game.tictactoe.MinMaxTicTacToe; +import org.toop.game.tictactoe.TicTacToe; import java.util.concurrent.*; /** * A representation of a local tic-tac-toe game. * Calls are made to a server for information about current game state. + * MOST OF THIS CODE IS TRASH, THROW IT OUT OF THE WINDOW AFTER DEMO. */ public class LocalTicTacToe { // TODO: Implement runnable private static final Logger logger = LogManager.getLogger(LocalTicTacToe.class); @@ -17,11 +20,26 @@ public class LocalTicTacToe { // TODO: Implement runnable private final ExecutorService executor = Executors.newSingleThreadExecutor(); private final BlockingQueue receivedQueue = new LinkedBlockingQueue<>(); - Object receivedMessageListener; + private final Object receivedMessageListener; - volatile String gameId; - volatile String connectionId; - volatile String serverId; + private volatile String gameId; + private final String connectionId; + private final String serverId; + + private final TicTacToe ticTacToe = new TicTacToe("A", "B"); + + private boolean isGameWithAi = false; + + /** + * + * @return Returns a boolean where True: a game with AI, false: A game without AI's + */ + public boolean isGameWithAi() { + return this.isGameWithAi; + } + + + private MinMaxTicTacToe[] aiPlayers = new MinMaxTicTacToe[2]; /** * Is either 1 or 2. @@ -64,6 +82,32 @@ public class LocalTicTacToe { // TODO: Implement runnable this.executor.submit(this::gameThread); } + /** + * + * @param isLocalServer If the server is hosted locally. + * @param ip The IP of the server to connect to. + * @param port The port of the server to connect to. + * @param aiPlayers boolean[firstPlayerIsAI, SecondPlayerIsAI] + */ + public LocalTicTacToe(boolean isLocalServer, String ip, String port, boolean[] aiPlayers) { + this.receivedMessageListener = GlobalEventBus.subscribe(Events.ServerEvents.ReceivedMessage.class, this::receiveMessageAction); + GlobalEventBus.register(this.receivedMessageListener); + + // TODO: Is blocking + if (isLocalServer) { this.serverId = this.createServer(port); } + else { this.serverId = null; } // TODO: What if null? + this.connectionId = this.createConnection(ip, port); + this.createGame(ip, port); + + if (aiPlayers != null) { + this.isGameWithAi = true; + if (aiPlayers[0]) { this.aiPlayers[0] = new MinMaxTicTacToe(); } + if (aiPlayers[1]) { this.aiPlayers[1] = new MinMaxTicTacToe(); } + } + + this.executor.submit(this::gameThread); + } + private String createServer(String port) { CompletableFuture serverIdFuture = new CompletableFuture<>(); GlobalEventBus.post(new Events.ServerEvents.StartServerRequest(port, "tictactoe", serverIdFuture)); @@ -129,6 +173,16 @@ public class LocalTicTacToe { // TODO: Implement runnable boolean running = true; while (running) { try { + if (isGameWithAi) { + if (aiPlayers[playersTurn - 1] != null) { + logger.info("{}, AI's turn", playersTurn); + int move = aiPlayers[playersTurn - 1].findBestMove(ticTacToe); + logger.info("{}, move {}", playersTurn, move); + ticTacToe.play(move); + this.move(move); + } + } + String rec = this.receivedQueue.take(); if (rec.equalsIgnoreCase("ok")) {continue;} else if (rec.equalsIgnoreCase("svr game yourturn")) { @@ -141,6 +195,7 @@ public class LocalTicTacToe { // TODO: Implement runnable } else if (rec.equalsIgnoreCase("svr game win")) { endListeners(); + running = false; } } catch (InterruptedException e) { @@ -152,6 +207,10 @@ public class LocalTicTacToe { // TODO: Implement runnable } + public char[] getCurrentBoard() { + return ticTacToe.getGrid(); + } + /** * End the current game. */ @@ -163,6 +222,7 @@ public class LocalTicTacToe { // TODO: Implement runnable * @param index The move to make. */ public void move(int index) { + this.ticTacToe.play(index); // TODO Right now no server check if valid. sendCommand("gameid", this.gameId, "player", "test", "move", String.valueOf(index)); }