From 0c1b106da5b38c6c318fc531fe202c1bd5389ae1 Mon Sep 17 00:00:00 2001 From: Bas de Jong Date: Sat, 10 Jan 2026 04:28:12 +0100 Subject: [PATCH] Refactored tournament to use interfaces and builders --- .../framework/networking/server/Server.java | 16 ++- .../server/handlers/MessageHandler.java | 2 +- .../server/tournaments/BasicMatchManager.java | 85 ++++++++++++ .../server/tournaments/BasicScoreManager.java | 30 +++++ .../server/tournaments/BasicTournament.java | 124 ++++-------------- .../server/tournaments/MatchManager.java | 15 +++ .../server/tournaments/ScoreManager.java | 19 +++ .../server/tournaments/Tournament.java | 4 +- .../server/tournaments/TournamentBuilder.java | 39 ++++++ 9 files changed, 230 insertions(+), 104 deletions(-) create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicMatchManager.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicScoreManager.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/MatchManager.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentBuilder.java diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java index 764dc10..245cd8e 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/Server.java +++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java @@ -10,8 +10,7 @@ import org.toop.framework.networking.server.stores.ClientStore; import org.toop.framework.networking.server.stores.SubscriptionStore; import org.toop.framework.networking.server.stores.TurnBasedGameStore; import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore; -import org.toop.framework.networking.server.tournaments.RandomShuffle; -import org.toop.framework.networking.server.tournaments.Tournament; +import org.toop.framework.networking.server.tournaments.*; import org.toop.framework.utils.ImmutablePair; import java.util.*; @@ -222,7 +221,6 @@ public class Server implements GameServer { } if (userInGame) { continue; } - // int first = Math.max(left, right); int second = Math.min(left, right); @@ -267,8 +265,16 @@ public class Server implements GameServer { public void startTournament(Tournament tournament, String gameType) { try { - tournament.init(clientStore.all().toArray(new NettyClient[0]), new RandomShuffle()); - new Thread(() -> tournament.run(gameType)).start(); + var tb = new TournamentBuilder(); + var cTournament = tb.create( + tournament, + onlineUsers(), + this, + new BasicScoreManager(new HashMap<>()), + new BasicMatchManager(), + new RandomShuffle() + ); + new Thread(() -> cTournament.run(gameType)).start(); } catch (IllegalArgumentException e) { getUser("host").send("ERR not enough clients to start a tournament"); } catch (RuntimeException e) { diff --git a/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java b/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java index 7ac5ec1..d42a854 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java +++ b/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java @@ -116,7 +116,7 @@ public class MessageHandler implements Handler { if (!client.name().equalsIgnoreCase("host")) return; if (p.args()[0].equalsIgnoreCase("start") && p.args().length > 1) { - server.startTournament(new BasicTournament(server), p.args()[1]); + server.startTournament(new BasicTournament(), p.args()[1]); } } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicMatchManager.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicMatchManager.java new file mode 100644 index 0000000..29ffdf1 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicMatchManager.java @@ -0,0 +1,85 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.gameFramework.model.game.TurnBasedGame; +import org.toop.framework.networking.server.OnlineGame; +import org.toop.framework.networking.server.Server; +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +public class BasicMatchManager implements MatchManager { + + private final HashMap> matches = new HashMap<>(); // TODO store + private final ArrayList matchOrder = new ArrayList<>(); // TODO store + private int matchIndex = 0; + + public BasicMatchManager() {} + + @Override + public void addClient(NettyClient client) { + matches.putIfAbsent(client, new ArrayList<>()); + } + + @Override + public List getClients() { + return matches.keySet().stream().toList(); + } + + @Override + public void createMatches() { + for (var match : matches.entrySet()) { + for (var matchNoSelf : matches.keySet()) { + if (match.getKey() == matchNoSelf) continue; + + match.getValue().addLast(matchNoSelf); + } + } + + for (var client : matches.entrySet()) { + for (var opponent : client.getValue()) { + matchOrder.addLast(new TournamentMatch(client.getKey(), opponent)); + } + } + } + + @Override + public TournamentMatch next() { + matchIndex++; + if (matchIndex >= matchOrder.size()) return null; + + return matchOrder.get(matchIndex); + } + + @Override + public void run(Server server, ScoreManager scoreManager, String gameType) { + new Thread(() -> { + for (var match : matchOrder) { + final CompletableFuture finished = new CompletableFuture<>(); + + AtomicReference> game = new AtomicReference<>(); + new Thread(() -> game.set(server.startGame(gameType, finished, match.getLeft(), match.getRight()))).start(); // TODO can possibly create a race condition + + finished.join(); + switch (game.get().game().getWinner()) { + case 0 -> scoreManager.addScore(match.getLeft()); + case 1 -> scoreManager.addScore(match.getRight()); + default -> {} + } + + match.getLeft().clearGame(); + match.getRight().clearGame(); + } + + server.endTournament(scoreManager.getScore(), gameType); + }).start(); + } + + @Override + public void shuffle(Shuffler shuffler) { + shuffler.shuffle(matchOrder); + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicScoreManager.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicScoreManager.java new file mode 100644 index 0000000..95a9cde --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicScoreManager.java @@ -0,0 +1,30 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.Map; + +public class BasicScoreManager implements ScoreManager { + + private final Map scores; + + public BasicScoreManager(Map store) { + scores = store; + } + + @Override + public void addClient(NettyClient client) { + scores.putIfAbsent(client, getInitScore()); + } + + @Override + public void addScore(NettyClient client) { + int clientScore = scores.get(client); + scores.put(client, clientScore + getWinPointAmount()); + } + + @Override + public Map getScore() { + return scores; + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournament.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournament.java index b8565be..235cb37 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournament.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournament.java @@ -1,116 +1,48 @@ package org.toop.framework.networking.server.tournaments; -import org.toop.framework.gameFramework.model.game.TurnBasedGame; -import org.toop.framework.networking.server.OnlineGame; import org.toop.framework.networking.server.Server; -import org.toop.framework.networking.server.client.NettyClient; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; public class BasicTournament implements Tournament { - private final int POINTS_FOR_WIN = 1; - private Server server; - private String gameType; - private ArrayList matchList = new ArrayList<>(); - private final HashMap> matches = new HashMap<>(); - private final HashMap score = new HashMap<>(); - private NettyClient[] clients; + private ScoreManager scoreManager; + private MatchManager matchManager; - public BasicTournament(Server server) { - this.server = server; - } + public BasicTournament() {} - @Override - public void init(NettyClient[] clients, Shuffler shuffler) throws IllegalArgumentException { - if (clients.length <= 1) throw new IllegalArgumentException("Not enough clients to initialize a tournament"); - - for (NettyClient client : clients) { - int INIT_SCORE = 0; - - matches.putIfAbsent(client, new ArrayList<>()); - score.putIfAbsent(client, INIT_SCORE); - } - - for (var match : matches.entrySet()) { - for (var matchNoSelf : matches.keySet()) { - if (match.getKey() == matchNoSelf) continue; - - match.getValue().addLast(matchNoSelf); - } - } - - for (var client : matches.entrySet()) { - for (var opponent : client.getValue()) { - matchList.addLast(new TournamentMatch(client.getKey(), opponent)); - } - } - - try { - shuffler.shuffle(matchList); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } - } - - public void addScorePoints(NettyClient client) { - score.put(client, score.get(client) + POINTS_FOR_WIN); + public void init(TournamentBuilder builder) { + server = builder.server; + scoreManager = builder.scoreManager; + matchManager = builder.matchManager; } @Override public boolean run(String gameType) throws RuntimeException { - if (matchList.isEmpty()) throw new RuntimeException("No matches to start a tournament with"); - if (server.gameTypes().stream().noneMatch(e -> e.equalsIgnoreCase(gameType))) return false; - this.gameType = gameType; - new Thread(() -> { - for (var match : matchList) { - final CompletableFuture finished = new CompletableFuture<>(); - - AtomicReference> game = new AtomicReference<>(); - new Thread(() -> game.set(server.startGame(gameType, finished, match.getLeft(), match.getRight()))).start(); // TODO can possibly create a race condition - - finished.join(); - switch (game.get().game().getWinner()) { - case 0 -> addScorePoints(match.getLeft()); - case 1 -> addScorePoints(match.getRight()); - default -> {} - } - - match.getLeft().clearGame(); - match.getRight().clearGame(); - } - - server.endTournament(end(), gameType); - }).start(); + matchManager.run(server, scoreManager, gameType); return true; } - @Override - public HashMap end() { - - for (var match : matchList) { - match.getLeft().clearGame(); // TODO send msg to client - match.getRight().clearGame(); // TODO send msg to client - } - - gameType = null; - matchList = null; - matches.clear(); - - HashMap retScore = new HashMap<>(score); - - score.clear(); - - clients = null; - - return retScore; - } +// @Override +// public HashMap end() { +// +// for (var match : matchList) { +// match.getLeft().clearGame(); // TODO send msg to client +// match.getRight().clearGame(); // TODO send msg to client +// } +// +// gameType = null; +// matchList = null; +// matches.clear(); +// +// HashMap retScore = new HashMap<>(score); +// +// score.clear(); +// +// clients = null; +// +// return retScore; +// } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/MatchManager.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/MatchManager.java new file mode 100644 index 0000000..1f1352f --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/MatchManager.java @@ -0,0 +1,15 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.networking.server.Server; +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.List; + +public interface MatchManager { + void addClient(NettyClient client); + List getClients(); + void createMatches(); + TournamentMatch next(); + void run(Server server, ScoreManager scoreManager, String gameType); + void shuffle(Shuffler shuffler); +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java new file mode 100644 index 0000000..7a56ac3 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java @@ -0,0 +1,19 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.Map; + +public interface ScoreManager { + void addClient(NettyClient client); + void addScore(NettyClient client); + Map getScore(); + + default int getWinPointAmount() { + return 1; + } + + default int getInitScore() { + return 0; + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java index 5a54306..135fe6c 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java @@ -5,7 +5,7 @@ import org.toop.framework.networking.server.client.NettyClient; import java.util.HashMap; public interface Tournament { - void init(NettyClient[] clients, Shuffler shuffler); + void init(TournamentBuilder builder); boolean run(String gameType); - HashMap end(); +// HashMap end(); } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentBuilder.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentBuilder.java new file mode 100644 index 0000000..dfd2ef1 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentBuilder.java @@ -0,0 +1,39 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.networking.server.Server; +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.List; + +public class TournamentBuilder { + public Server server; + public ScoreManager scoreManager; + public MatchManager matchManager; + + public TournamentBuilder() {} + + public Tournament create( + Tournament tournament, + List clients, + Server server, + ScoreManager scoreManager, + MatchManager matchManager, + Shuffler shuffler + ) { + + this.server = server; + this.scoreManager = scoreManager; + this.matchManager = matchManager; + + for (var client : clients) { + matchManager.addClient(client); + scoreManager.addClient(client); + } + + matchManager.createMatches(); + matchManager.shuffle(shuffler); + + tournament.init(this); + return tournament; + } +}