Refactored TicTacToe game to be able to run multiple instances on a server

This commit is contained in:
Bas de Jong
2025-09-16 17:27:17 +02:00
parent 3afd718d91
commit 5e3ba40bed
6 changed files with 75 additions and 39 deletions

View File

@@ -90,6 +90,8 @@ public class Events implements IEvents {
public record ServerStarted(String uuid, String port) {}
public record StartTicTacToeGame(String id, String port) {}
/**
*
* Triggers starting a server connection.

View File

@@ -29,6 +29,7 @@ public class ServerManager {
GlobalEventBus.subscribeAndRegister(Events.ServerEvents.StartServerRequest.class, this::handleStartServerRequest);
GlobalEventBus.subscribeAndRegister(Events.ServerEvents.StartServer.class, this::handleStartServer);
GlobalEventBus.subscribeAndRegister(Events.ServerEvents.ForceCloseAllServers.class, _ -> shutdownAll());
GlobalEventBus.subscribeAndRegister(Events.ServerEvents.StartTicTacToeGame.class, this::handleStartTicTacToeGameOnAServer);
}
private String startServer(String port) {
@@ -56,6 +57,20 @@ public class ServerManager {
));
}
private void handleStartTicTacToeGameOnAServer(Events.ServerEvents.StartTicTacToeGame event) {
TcpServer serverThing = this.servers.get(event.id());
if (serverThing != null) {
try {
serverThing.runGame();
logger.info("Started game on server {}", event.id());
}
catch (Exception e) {
logger.info("Could not start game on server {}", event.id());
}
}
}
private void getAllServers(Events.ServerEvents.RequestsAllServers request) {
ArrayList<TcpServer> a = new ArrayList<>(this.servers.values());
request.future().complete(a.toString());

View File

@@ -5,7 +5,6 @@ import org.apache.logging.log4j.Logger;
import java.io.*;
import java.net.*;
import java.sql.Time;
import java.util.concurrent.*;
import static java.lang.Thread.sleep;
@@ -49,6 +48,16 @@ public class TcpServer implements Runnable {
}
}
public void runGame() {}
protected String sendServerMessage() {
try { return sendQueue.poll(this.WAIT_TIME, TimeUnit.MILLISECONDS); }
catch (InterruptedException e) {
logger.error("Interrupted", e);
return null;
}
}
protected String getNewestCommand() {
try { return receivedQueue.poll(this.WAIT_TIME, TimeUnit.MILLISECONDS); }
catch (InterruptedException e) {

View File

@@ -6,17 +6,18 @@ import org.toop.server.backend.TcpServer;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class TicTacToeServer extends TcpServer {
private TicTacToe game;
/**
* Map of gameId -> Game instances
*/
private final Map<String, TicTacToe> games = new ConcurrentHashMap<>();
public TicTacToeServer(int port, String playerA, String playerB) throws IOException {
public TicTacToeServer(int port) throws IOException {
super(port);
this.game = new TicTacToe(playerA, playerB);
}
@Override
@@ -29,13 +30,32 @@ public class TicTacToeServer extends TcpServer {
logger.info("Connected to client: {}", clientSocket.getInetAddress());
new Thread(() -> this.startWorkers(clientSocket)).start();
new Thread(() -> this.gameThread()).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void newGame(String playerA, String playerB) {
String gameId = UUID.randomUUID().toString();
TicTacToe game = new TicTacToe(playerA, playerB);
this.games.put(gameId, game);
logger.info("Created a new game: {}. {} vs {}", gameId, playerA, playerB);
}
public void runGame(String gameId) {
TicTacToe game = this.games.get(gameId);
game.run();
logger.info("Running game: {}, players: {}", gameId, game.getPlayers());
}
public void endGame(String gameId) {
TicTacToe game = this.games.get(gameId);
this.games.remove(gameId);
logger.info("Removed game: {}", gameId);
// TODO: Multithreading, close game in a graceful matter, etc.
}
private static class ParsedCommand {
public TicTacToeServerCommand command;
public ArrayList<Object> arguments;
@@ -121,17 +141,4 @@ public class TicTacToeServer extends TcpServer {
return null;
}
private void gameThread() {
while (true) {
String command = getNewestCommand();
command = this.parseCommand(command).toString();
if (command == null) { continue; }
// TODO: Game
}
}
}

View File

@@ -4,10 +4,12 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.Main;
public class TicTacToe extends GameBase {
public int moveCount;
public class TicTacToe extends GameBase implements Runnable {
private static final Logger logger = LogManager.getLogger(TicTacToe.class);
public int moveCount;
public Thread gameThread;
public TicTacToe(String player1, String player2) {
super(3); // 3x3 Grid
players = new Player[2];
@@ -17,6 +19,23 @@ public class TicTacToe extends GameBase {
moveCount = 0;
}
@Override
public void run() {
this.gameThread = new Thread(this::gameThread);
this.gameThread.start();
}
private void gameThread() {
while (true) {
String command = getNewestCommand();
command = this.parseCommand(command).toString();
if (command == null) { continue; }
// TODO: Game
}
}
@Override
public boolean validateMove(int index) {
if (index < 0 || index > (size * size - 1)) {