diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 655cfae..e0e273b 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,7 +2,7 @@ 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 245cd8e..fa0e910 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 @@ -11,6 +11,8 @@ 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.*; +import org.toop.framework.networking.server.tournaments.matchmakers.RoundRobinMatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.BasicScoreSystem; import org.toop.framework.utils.ImmutablePair; import java.util.*; @@ -263,18 +265,15 @@ public class Server implements GameServer { return true; } - public void startTournament(Tournament tournament, String gameType) { + public void startTournament(String gameType) { + Tournament tournament = new BasicTournament(new TournamentBuilder( + this, + new BasicTournamentRunner(), + new RoundRobinMatchMaker(onlineUsers()), + new BasicScoreSystem(onlineUsers()) + )); try { - 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(); + new Thread(() -> tournament.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 d42a854..bc5a6c5 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 @@ -5,7 +5,7 @@ import org.toop.framework.networking.server.OnlineTurnBasedGame; import org.toop.framework.networking.server.Server; import org.toop.framework.networking.server.client.Client; import org.toop.framework.networking.server.parsing.ParsedMessage; -import org.toop.framework.networking.server.tournaments.BasicTournament; +import org.toop.framework.networking.server.tournaments.*; import org.toop.framework.utils.Utils; public class MessageHandler implements Handler { @@ -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(), p.args()[1]); + server.startTournament(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 deleted file mode 100644 index 29ffdf1..0000000 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicMatchManager.java +++ /dev/null @@ -1,85 +0,0 @@ -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 deleted file mode 100644 index 95a9cde..0000000 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicScoreManager.java +++ /dev/null @@ -1,30 +0,0 @@ -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 235cb37..50db018 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,48 +1,29 @@ package org.toop.framework.networking.server.tournaments; import org.toop.framework.networking.server.Server; +import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; public class BasicTournament implements Tournament { - private Server server; + private final Server server; - private ScoreManager scoreManager; - private MatchManager matchManager; + private final ScoreSystem scoreSystem; + private final TournamentRunner tournamentRunner; + private final MatchMaker matchMaker; - public BasicTournament() {} - - public void init(TournamentBuilder builder) { + public BasicTournament(TournamentBuilder builder) { server = builder.server; - scoreManager = builder.scoreManager; - matchManager = builder.matchManager; + scoreSystem = builder.scoreSystem; + tournamentRunner = builder.tournamentRunner; + matchMaker = builder.matchMaker; } @Override public boolean run(String gameType) throws RuntimeException { if (server.gameTypes().stream().noneMatch(e -> e.equalsIgnoreCase(gameType))) return false; - matchManager.run(server, scoreManager, gameType); + tournamentRunner.run(server, matchMaker, scoreSystem, 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; -// } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournamentRunner.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournamentRunner.java new file mode 100644 index 0000000..47341fa --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/BasicTournamentRunner.java @@ -0,0 +1,46 @@ +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.tournaments.matchmakers.MatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; + +import java.util.concurrent.*; + +public class BasicTournamentRunner implements TournamentRunner { + + public BasicTournamentRunner() {} + + @Override + public void run(Server server, MatchMaker matchMaker, ScoreSystem scoreSystem, String gameType) { + ExecutorService threadPool = Executors.newSingleThreadExecutor(); + try { + threadPool.execute(() -> { + for (var match : matchMaker) { + final CompletableFuture finished = new CompletableFuture<>(); + + // Play game and await the results + OnlineGame game = server.startGame(gameType, finished, match.getClient0(), match.getClient1()); // TODO can possibly create a race condition + finished.join(); + // End + + // Get result and calculate new score + switch (game.game().getWinner()) { + case 0 -> scoreSystem.addScore(match.getClient0()); + case 1 -> scoreSystem.addScore(match.getClient1()); + default -> { + } + } + + match.getClient0().clearGame(); + match.getClient1().clearGame(); + } + + server.endTournament(scoreSystem.getScore(), gameType); + }); + } finally { + threadPool.shutdown(); + } + } +} 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 deleted file mode 100644 index 1f1352f..0000000 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/MatchManager.java +++ /dev/null @@ -1,15 +0,0 @@ -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/Tournament.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/Tournament.java index 135fe6c..12d588a 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(TournamentBuilder builder); +// void init(TournamentBuilder builder); boolean run(String gameType); // 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 index dfd2ef1..cf52d76 100644 --- 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 @@ -1,39 +1,24 @@ 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; +import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; public class TournamentBuilder { public Server server; - public ScoreManager scoreManager; - public MatchManager matchManager; + public ScoreSystem scoreSystem; + public TournamentRunner tournamentRunner; + public MatchMaker matchMaker; - public TournamentBuilder() {} - - public Tournament create( - Tournament tournament, - List clients, + public TournamentBuilder( Server server, - ScoreManager scoreManager, - MatchManager matchManager, - Shuffler shuffler + TournamentRunner tournamentRunner, + MatchMaker matchMaker, + ScoreSystem scoreSystem ) { - 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; + this.tournamentRunner = tournamentRunner; + this.matchMaker = matchMaker; + this.scoreSystem = scoreSystem; } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentMatch.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentMatch.java index 7f2067d..ab703e7 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentMatch.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentMatch.java @@ -7,4 +7,12 @@ public class TournamentMatch extends ImmutablePair { public TournamentMatch(NettyClient a, NettyClient b) { super(a, b); } + + NettyClient getClient0() { + return getLeft(); + } + + NettyClient getClient1() { + return getRight(); + } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentRunner.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentRunner.java new file mode 100644 index 0000000..fe0e9cb --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/TournamentRunner.java @@ -0,0 +1,9 @@ +package org.toop.framework.networking.server.tournaments; + +import org.toop.framework.networking.server.Server; +import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; + +public interface TournamentRunner { + void run(Server server, MatchMaker matchMaker, ScoreSystem scoreSystem, String gameType); +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/MatchMaker.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/MatchMaker.java new file mode 100644 index 0000000..e61d387 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/MatchMaker.java @@ -0,0 +1,5 @@ +package org.toop.framework.networking.server.tournaments.matchmakers; + +import org.toop.framework.networking.server.tournaments.TournamentMatch; + +public interface MatchMaker extends Iterable {} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/RoundRobinMatchMaker.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/RoundRobinMatchMaker.java new file mode 100644 index 0000000..be38af7 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/RoundRobinMatchMaker.java @@ -0,0 +1,65 @@ +package org.toop.framework.networking.server.tournaments.matchmakers; + +import org.toop.framework.networking.server.client.NettyClient; +import org.toop.framework.networking.server.tournaments.TournamentMatch; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public class RoundRobinMatchMaker implements MatchMaker { + + private final List players; + + public RoundRobinMatchMaker(List players) { + this.players = players; + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + + private int i = 0; + private int j = 1; + private boolean reverse = false; + + @Override + public boolean hasNext() { + return players.size() > 1 + && i < players.size() - 1 + && j < players.size(); + } + + @Override + public TournamentMatch next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + NettyClient home = players.get(i); + NettyClient away = players.get(j); + + TournamentMatch match = reverse ? new TournamentMatch(away, home) : new TournamentMatch(home, away); + + advance(); + return match; + } + + private void advance() { + j++; + if (j >= players.size()) { + i++; + j = i + 1; + + if (i >= players.size() - 1) { + if (!reverse) { + reverse = true; + i = 0; + j = 1; + } + } + } + } + }; + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/BasicScoreSystem.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/BasicScoreSystem.java new file mode 100644 index 0000000..75625c3 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/BasicScoreSystem.java @@ -0,0 +1,29 @@ +package org.toop.framework.networking.server.tournaments.scoresystems; + +import org.toop.framework.networking.server.client.NettyClient; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BasicScoreSystem implements ScoreSystem { + + private final Map scores = new HashMap<>(); + + public BasicScoreSystem(List store) { + for (NettyClient c : store) { + scores.putIfAbsent(c, 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/ScoreManager.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java similarity index 69% rename from framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java rename to framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java index 7a56ac3..a33ba2b 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/ScoreManager.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java @@ -1,11 +1,10 @@ -package org.toop.framework.networking.server.tournaments; +package org.toop.framework.networking.server.tournaments.scoresystems; import org.toop.framework.networking.server.client.NettyClient; import java.util.Map; -public interface ScoreManager { - void addClient(NettyClient client); +public interface ScoreSystem { void addScore(NettyClient client); Map getScore(); diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/RandomShuffle.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/RandomShuffle.java similarity index 88% rename from framework/src/main/java/org/toop/framework/networking/server/tournaments/RandomShuffle.java rename to framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/RandomShuffle.java index cdfe5ed..5d40833 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/RandomShuffle.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/RandomShuffle.java @@ -1,4 +1,4 @@ -package org.toop.framework.networking.server.tournaments; +package org.toop.framework.networking.server.tournaments.shufflers; import java.util.List; import java.util.Random; diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/Shuffler.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/Shuffler.java similarity index 59% rename from framework/src/main/java/org/toop/framework/networking/server/tournaments/Shuffler.java rename to framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/Shuffler.java index 844fb0e..9f1acf2 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/Shuffler.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/shufflers/Shuffler.java @@ -1,4 +1,4 @@ -package org.toop.framework.networking.server.tournaments; +package org.toop.framework.networking.server.tournaments.shufflers; import java.util.List;