From 848d257b9cbc429bc93cdc2608213fd28eb3b8e1 Mon Sep 17 00:00:00 2001 From: Bas de Jong Date: Mon, 12 Jan 2026 12:04:29 +0100 Subject: [PATCH] More adaptable scoring system --- app/src/main/java/org/toop/app/Server.java | 8 +- .../connection/events/NetworkEvents.java | 2 +- .../handlers/NetworkingGameClientHandler.java | 33 ++++++-- .../framework/networking/server/Server.java | 53 +++++++----- .../tournaments/AsyncTournamentRunner.java | 6 +- .../tournaments/BasicTournamentRunner.java | 7 +- .../server/tournaments/ResultBroadcaster.java | 4 +- .../server/tournaments/Tournament.java | 17 ++-- .../server/tournaments/TournamentRunner.java | 3 +- .../DoubleRoundRobinMatchMaker.java | 81 +++++++++++++++++++ .../matchmakers/RoundRobinMatchMaker.java | 18 +---- .../scoresystems/DrawCountScoreSystem.java | 43 ++++++++++ .../scoresystems/LoseCountScoreSystem.java | 41 ++++++++++ .../scoresystems/MatchCountScoreSystem.java | 37 +++++++++ .../tournaments/scoresystems/ScoreSystem.java | 1 + ...reSystem.java => WinCountScoreSystem.java} | 10 ++- 16 files changed, 302 insertions(+), 62 deletions(-) create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/DoubleRoundRobinMatchMaker.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/DrawCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/LoseCountScoreSystem.java create mode 100644 framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/MatchCountScoreSystem.java rename framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/{BasicScoreSystem.java => WinCountScoreSystem.java} (83%) diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index 796af3b..c9385ee 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -11,6 +11,7 @@ import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.view.ServerView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.game.players.ArtificialPlayer; import org.toop.framework.game.players.OnlinePlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.eventbus.GlobalEventBus; @@ -20,6 +21,7 @@ import org.toop.framework.networking.connection.events.NetworkEvents; import org.toop.framework.networking.connection.types.NetworkingConnector; import org.toop.framework.networking.server.gateway.NettyGatewayServer; import org.toop.framework.game.players.LocalPlayer; +import org.toop.game.players.ai.MCTSAI3; import org.toop.local.AppContext; import java.util.Arrays; @@ -208,7 +210,8 @@ public final class Server { information.players[opponentStartingTurn].name = response.opponent(); Player[] players = new Player[2]; - players[userStartingTurn] = new LocalPlayer(user); + + players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(100), user); players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { @@ -244,7 +247,8 @@ public final class Server { private void handleTournamentResult(NetworkEvents.TournamentResultResponse response) { IO.println(response.gameType()); IO.println(Arrays.toString(response.names())); - IO.println(Arrays.toString(response.scores())); + IO.println(Arrays.toString(response.scoreTypes())); + IO.println(Arrays.toString(response.scores().toArray())); } private void handleReceivedMove(NetworkEvents.GameMoveResponse response) { diff --git a/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java index da07798..c45a71c 100644 --- a/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java +++ b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java @@ -65,7 +65,7 @@ public class NetworkEvents extends EventsBase { public record GameResultResponse(long clientId, String condition) implements GenericEvent {} - public record TournamentResultResponse(long clientId, String gameType, String[] names, Integer[] scores) + public record TournamentResultResponse(long clientId, String gameType, String[] names, String[] scoreTypes, List scores) implements GenericEvent {} /** Indicates that a game move has been processed or received. */ diff --git a/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java b/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java index 9f6a02f..787ee53 100644 --- a/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java +++ b/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java @@ -3,7 +3,9 @@ package org.toop.framework.networking.connection.handlers; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -117,10 +119,13 @@ public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter { } private void resultsHandler(String rec) { + // TODO all of this + IO.println(rec); String gameTypeRaw = extract(rec, "GAMETYPE"); String usersRaw = extract(rec, "USERS"); + String scoreTypesRaw = extract(rec, "SCORETYPES"); String scoresRaw = extract(rec, "SCORES"); if (usersRaw == null) return; @@ -134,16 +139,32 @@ public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter { users = new String[]{}; } + String[] scoreTypes; + if (scoreTypesRaw.length() > 2) { + scoreTypes = Arrays.stream(scoreTypesRaw.substring(1, usersRaw.length() - 1).split(",")) + .map(s -> s.trim().replace("\"", "")) + .toArray(String[]::new); + } else { + scoreTypes = new String[]{}; + } + if (scoresRaw == null) return; if (scoresRaw.length() > 2) { - Integer[] scores = Arrays.stream(scoresRaw.substring(1, scoresRaw.length() - 1).split(",")) - .map(String::trim) - .map(Integer::parseInt) - .toArray(Integer[]::new); + List scores = Arrays.stream( + scoresRaw.substring(1, scoresRaw.length() - 1) // remove outer [] + .split("\\],\\[") + ) + .map(part -> part.replace("[", "").replace("]", "")) + .map(part -> Arrays.stream(part.split(",")) + .map(String::trim) + .map(Integer::parseInt) + .toArray(Integer[]::new) + ) + .toList(); - eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, scores)); + eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, scoreTypes, scores)); } else { - eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, new Integer[]{})); + eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, scoreTypes, new ArrayList<>())); } } 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 c47afe4..5300ce8 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,10 +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.networking.server.tournaments.scoresystems.IntegerScoreSystem; -import org.toop.framework.networking.server.tournaments.shufflers.RandomShuffle; +import org.toop.framework.networking.server.tournaments.matchmakers.DoubleRoundRobinMatchMaker; +import org.toop.framework.networking.server.tournaments.scoresystems.*; import org.toop.framework.utils.ImmutablePair; import java.util.*; @@ -298,38 +296,57 @@ public class Server implements GameServer { Tournament tournament = new Tournament.Builder() .matchExecutor(this::startGame) .tournamentRunner(new AsyncTournamentRunner()) - .matchMaker(new RoundRobinMatchMaker()) - .scoreSystem(new BasicScoreSystem()) + .matchMaker(new DoubleRoundRobinMatchMaker()) + .addScoreSystem(new MatchCountScoreSystem()) + .addScoreSystem(new WinCountScoreSystem()) + .addScoreSystem(new DrawCountScoreSystem()) + .addScoreSystem(new LoseCountScoreSystem()) .resultBroadcaster(this::endTournament) .turnTimeout(Duration.ofSeconds(10)) .addPlayers(tournamentUsers.toArray(NettyClient[]::new)) .addAdmins(admins.toArray(NettyClient[]::new)) - .addMatchShuffler(new RandomShuffle()) .build(); new Thread(() -> tournament.run(gameType)).start(); } - public void endTournament(IntegerScoreSystem score) { + public void endTournament(List systems) { + if (systems.isEmpty()) return; - List u = new ArrayList<>(); - List s = new ArrayList<>(); + Map>> combined = new HashMap<>(); - for (var entry : score.getScore().entrySet()) { - u.add(entry.getKey().name()); - s.add(entry.getValue()); + for (var system : systems) { + for (var player : system.getScore().keySet()) { + combined.putIfAbsent(player.name(), new ArrayList<>()); + combined.get(player.name()).addLast(new ImmutablePair<>(system.scoreName(), system.getScore().get(player))); + } + } + + List names = new ArrayList<>(); + List systemNames = new ArrayList<>(); + List> scores = new ArrayList<>(); + + for (var player : combined.entrySet()) { + names.addLast(player.getKey()); + scores.addLast(new ArrayList<>()); + for (var system : player.getValue()) { + if (!systemNames.contains(system.getLeft())) systemNames.addLast(system.getLeft()); + scores.getLast().addLast(system.getRight()); + } } Gson gson = new Gson(); - String users = gson.toJson(u); - String scores = gson.toJson(s); + String namesJson = gson.toJson(names); + String systemNamesJson = gson.toJson(systemNames); + String scoresJson = gson.toJson(scores); String msg = String.format( - "SVR RESULTS {GAMETYPE: \"%s\", USERS: %s, SCORES: %s, TOURNAMENT: 1}", + "SVR RESULTS {GAMETYPE: \"%s\", USERS: %s, SCORETYPES: %s, SCORES: %s, TOURNAMENT: 1}", "none", // TODO gametype - users, - scores + namesJson, + systemNamesJson, + scoresJson ); for (var user : onlineUsers()) { diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/AsyncTournamentRunner.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/AsyncTournamentRunner.java index ebeded5..4eeda6b 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/AsyncTournamentRunner.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/AsyncTournamentRunner.java @@ -16,7 +16,7 @@ public class AsyncTournamentRunner implements TournamentRunner { public void run( MatchExecutor matchRunner, MatchMaker matchMaker, - IntegerScoreSystem scoreSystem, + List scoreSystems, ResultBroadcaster broadcaster, Duration turnTime, String gameType @@ -56,7 +56,7 @@ public class AsyncTournamentRunner implements TournamentRunner { CompletableFuture.runAsync(() -> { try { GameResultFuture game = matchRunner.submit(gameType, turnTime, a, b); - scoreSystem.result(match, game.result().join()); + scoreSystems.forEach(s -> s.result(match, game.result().join())); } finally { a.clearGame(); b.clearGame(); @@ -73,7 +73,7 @@ public class AsyncTournamentRunner implements TournamentRunner { Thread.sleep(10); // Safety } - broadcaster.broadcast(scoreSystem); + broadcaster.broadcast(scoreSystems); } catch (InterruptedException e) { Thread.currentThread().interrupt(); 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 index d1ca4fa..11609a9 100644 --- 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 @@ -6,6 +6,7 @@ import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker; import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem; import java.time.Duration; +import java.util.List; import java.util.concurrent.*; public class BasicTournamentRunner implements TournamentRunner { @@ -13,7 +14,7 @@ public class BasicTournamentRunner implements TournamentRunner { public void run( MatchExecutor matchExecutor, MatchMaker matchMaker, - IntegerScoreSystem scoreSystem, + List scoreSystems, ResultBroadcaster broadcaster, Duration turnTime, String gameType @@ -24,13 +25,13 @@ public class BasicTournamentRunner implements TournamentRunner { for (TournamentMatch match : matchMaker) { // Play game and await the results GameResultFuture game = matchExecutor.submit(gameType, turnTime, match.getClient0(), match.getClient1()); - scoreSystem.result(match, game.result().join()); + scoreSystems.forEach(e -> e.result(match, game.result().join())); match.getClient0().clearGame(); match.getClient1().clearGame(); } - broadcaster.broadcast(scoreSystem); + broadcaster.broadcast(scoreSystems); }); } finally { threadPool.shutdown(); diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/ResultBroadcaster.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/ResultBroadcaster.java index e0aa1e9..22a60a4 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/ResultBroadcaster.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/ResultBroadcaster.java @@ -2,7 +2,9 @@ package org.toop.framework.networking.server.tournaments; import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; +import java.util.List; + @FunctionalInterface public interface ResultBroadcaster> { - void broadcast(T scoreSystem); + void broadcast(List scoreSystem); } 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 541fce1..31732d5 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 @@ -7,13 +7,15 @@ import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScor import org.toop.framework.networking.server.tournaments.shufflers.Shuffler; import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Objects; public class Tournament { private final MatchExecutor matchExecutor; - private final IntegerScoreSystem scoreSystem; + private final List scoreSystems; private final TournamentRunner tournamentRunner; private final MatchMaker matchMaker; private final ResultBroadcaster broadcaster; @@ -23,7 +25,7 @@ public class Tournament { private Tournament(Tournament.Builder builder) { matchExecutor = builder.matchExecutor; - scoreSystem = builder.scoreSystem; + scoreSystems = builder.scoreSystems; tournamentRunner = builder.tournamentRunner; matchMaker = builder.matchMaker; broadcaster = builder.broadcaster; @@ -36,18 +38,18 @@ public class Tournament { Arrays.stream(players).forEach(e -> { matchMaker.addPlayer(e); - scoreSystem.addPlayer(e); + scoreSystems.forEach(k -> k.addPlayer(e)); }); if (shuffler != null) matchMaker.shuffle(shuffler); - tournamentRunner.run(matchExecutor, matchMaker, scoreSystem, broadcaster, turnTime, gameType); + tournamentRunner.run(matchExecutor, matchMaker, scoreSystems, broadcaster, turnTime, gameType); } public static class Builder { private MatchExecutor matchExecutor; - private IntegerScoreSystem scoreSystem; + private List scoreSystems = new ArrayList<>(); private TournamentRunner tournamentRunner; private MatchMaker matchMaker; private ResultBroadcaster broadcaster; @@ -62,8 +64,8 @@ public class Tournament { return this; } - public Builder scoreSystem(IntegerScoreSystem scoreSystem) { - this.scoreSystem = scoreSystem; + public Builder addScoreSystem(IntegerScoreSystem scoreSystem) { + this.scoreSystems.addLast(scoreSystem); return this; } @@ -109,7 +111,6 @@ public class Tournament { public Tournament build() { Objects.requireNonNull(matchExecutor, "matchExecutor"); - Objects.requireNonNull(scoreSystem, "scoreSystem"); Objects.requireNonNull(tournamentRunner, "tournamentRunner"); Objects.requireNonNull(matchMaker, "matchMaker"); Objects.requireNonNull(broadcaster, "resultBroadcaster"); // TODO is not always necessary and needs to be more generic, not just at the end 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 index ffd430e..078e91d 100644 --- 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 @@ -5,8 +5,9 @@ import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker; import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem; import java.time.Duration; +import java.util.List; public interface TournamentRunner { - void run(MatchExecutor matchExecutor, MatchMaker matchMaker, IntegerScoreSystem scoreSystem, + void run(MatchExecutor matchExecutor, MatchMaker matchMaker, List scoreSystems, ResultBroadcaster broadcaster, Duration turnTime, String gameType); } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/DoubleRoundRobinMatchMaker.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/DoubleRoundRobinMatchMaker.java new file mode 100644 index 0000000..de55d38 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/DoubleRoundRobinMatchMaker.java @@ -0,0 +1,81 @@ +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 org.toop.framework.networking.server.tournaments.shufflers.Shuffler; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public class DoubleRoundRobinMatchMaker implements MatchMaker { + + private final List players = new ArrayList<>(); + + public DoubleRoundRobinMatchMaker() {} // TODO let user decide store type + + @Override + public void addPlayer(NettyClient player) { + players.addLast(player); + } + + @Override + public void shuffle(Shuffler shuffler) { + if (players.size() < 2) return; + shuffler.shuffle(players); + } + + @Override + public List getPlayers() { + return 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/matchmakers/RoundRobinMatchMaker.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/matchmakers/RoundRobinMatchMaker.java index 0bea9e9..07ffbc8 100644 --- 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 @@ -37,7 +37,6 @@ public class RoundRobinMatchMaker implements MatchMaker { private int i = 0; private int j = 1; - private boolean reverse = false; @Override public boolean hasNext() { @@ -55,26 +54,13 @@ public class RoundRobinMatchMaker implements MatchMaker { 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; - } - } } + + return new TournamentMatch(home, away); } }; } diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/DrawCountScoreSystem.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/DrawCountScoreSystem.java new file mode 100644 index 0000000..0937dd8 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/DrawCountScoreSystem.java @@ -0,0 +1,43 @@ +package org.toop.framework.networking.server.tournaments.scoresystems; + +import org.toop.framework.networking.server.client.NettyClient; +import org.toop.framework.networking.server.tournaments.TournamentMatch; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class DrawCountScoreSystem implements IntegerScoreSystem { + + private final Map scores = new ConcurrentHashMap<>(); + private final int INIT_SCORE = 0; + private final int WIN_POINTS = 1; + + public DrawCountScoreSystem() {} // TODO let user decide store type + + @Override + public String scoreName() { + return "draws"; + } + + @Override + public void addPlayer(NettyClient user) { + scores.putIfAbsent(user, INIT_SCORE); + } + + @Override + public void result(TournamentMatch match, Integer result) { + switch (result) { + case 0, 1 -> {} + case -1 -> { + scores.merge(match.getClient0(), WIN_POINTS, Integer::sum); + scores.merge(match.getClient1(), WIN_POINTS, Integer::sum); + } + default -> throw new IllegalArgumentException("Unknown result: " + result); + } + } + + @Override + public Map getScore() { + return scores; + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/LoseCountScoreSystem.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/LoseCountScoreSystem.java new file mode 100644 index 0000000..c01381a --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/LoseCountScoreSystem.java @@ -0,0 +1,41 @@ +package org.toop.framework.networking.server.tournaments.scoresystems; + +import org.toop.framework.networking.server.client.NettyClient; +import org.toop.framework.networking.server.tournaments.TournamentMatch; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class LoseCountScoreSystem implements IntegerScoreSystem { + + private final Map scores = new ConcurrentHashMap<>(); + private final int INIT_SCORE = 0; + private final int WIN_POINTS = 1; + + public LoseCountScoreSystem() {} // TODO let user decide store type + + @Override + public String scoreName() { + return "loses"; + } + + @Override + public void addPlayer(NettyClient user) { + scores.putIfAbsent(user, INIT_SCORE); + } + + @Override + public void result(TournamentMatch match, Integer result) { + switch (result) { + case 0 -> scores.merge(match.getClient1(), WIN_POINTS, Integer::sum); + case 1 -> scores.merge(match.getClient0(), WIN_POINTS, Integer::sum); + case -1 -> {} // Draw + default -> throw new IllegalArgumentException("Unknown result: " + result); + } + } + + @Override + public Map getScore() { + return scores; + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/MatchCountScoreSystem.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/MatchCountScoreSystem.java new file mode 100644 index 0000000..c47938e --- /dev/null +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/MatchCountScoreSystem.java @@ -0,0 +1,37 @@ +package org.toop.framework.networking.server.tournaments.scoresystems; + +import org.toop.framework.networking.server.client.NettyClient; +import org.toop.framework.networking.server.tournaments.TournamentMatch; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MatchCountScoreSystem implements IntegerScoreSystem { + + private final Map scores = new ConcurrentHashMap<>(); + private final int INIT_SCORE = 0; + private final int WIN_POINTS = 1; + + public MatchCountScoreSystem() {} // TODO let user decide store type + + @Override + public String scoreName() { + return "matches"; + } + + @Override + public void addPlayer(NettyClient user) { + scores.putIfAbsent(user, INIT_SCORE); + } + + @Override + public void result(TournamentMatch match, Integer result) { + scores.merge(match.getClient0(), WIN_POINTS, Integer::sum); + scores.merge(match.getClient1(), WIN_POINTS, Integer::sum); + } + + @Override + public Map getScore() { + return scores; + } +} diff --git a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java index 8a8a453..c7f0233 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java +++ b/framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/ScoreSystem.java @@ -3,6 +3,7 @@ package org.toop.framework.networking.server.tournaments.scoresystems; import java.util.Map; public interface ScoreSystem { + String scoreName(); void addPlayer(USERTYPE user); void result(MATCHTYPE match, SCORETYPE result); Map getScore(); 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/WinCountScoreSystem.java similarity index 83% rename from framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/BasicScoreSystem.java rename to framework/src/main/java/org/toop/framework/networking/server/tournaments/scoresystems/WinCountScoreSystem.java index 78b56ec..6659f3b 100644 --- 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/WinCountScoreSystem.java @@ -3,17 +3,21 @@ package org.toop.framework.networking.server.tournaments.scoresystems; import org.toop.framework.networking.server.client.NettyClient; import org.toop.framework.networking.server.tournaments.TournamentMatch; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class BasicScoreSystem implements IntegerScoreSystem { +public class WinCountScoreSystem implements IntegerScoreSystem { private final Map scores = new ConcurrentHashMap<>(); private final int INIT_SCORE = 0; private final int WIN_POINTS = 1; - public BasicScoreSystem() {} // TODO let user decide store type + public WinCountScoreSystem() {} // TODO let user decide store type + + @Override + public String scoreName() { + return "wins"; + } @Override public void addPlayer(NettyClient user) {