More adaptable scoring system

This commit is contained in:
Bas de Jong
2026-01-12 12:04:29 +01:00
parent 7ce000c795
commit 848d257b9c
16 changed files with 302 additions and 62 deletions

View File

@@ -11,6 +11,7 @@ import org.toop.app.widget.popup.ErrorPopup;
import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.popup.SendChallengePopup;
import org.toop.app.widget.view.ServerView; import org.toop.app.widget.view.ServerView;
import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.game.players.ArtificialPlayer;
import org.toop.framework.game.players.OnlinePlayer; import org.toop.framework.game.players.OnlinePlayer;
import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.controller.GameController;
import org.toop.framework.eventbus.GlobalEventBus; 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.connection.types.NetworkingConnector;
import org.toop.framework.networking.server.gateway.NettyGatewayServer; import org.toop.framework.networking.server.gateway.NettyGatewayServer;
import org.toop.framework.game.players.LocalPlayer; import org.toop.framework.game.players.LocalPlayer;
import org.toop.game.players.ai.MCTSAI3;
import org.toop.local.AppContext; import org.toop.local.AppContext;
import java.util.Arrays; import java.util.Arrays;
@@ -208,7 +210,8 @@ public final class Server {
information.players[opponentStartingTurn].name = response.opponent(); information.players[opponentStartingTurn].name = response.opponent();
Player[] players = new Player[2]; Player[] players = new Player[2];
players[userStartingTurn] = new LocalPlayer(user);
players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(100), user);
players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); players[opponentStartingTurn] = new OnlinePlayer(response.opponent());
switch (type) { switch (type) {
@@ -244,7 +247,8 @@ public final class Server {
private void handleTournamentResult(NetworkEvents.TournamentResultResponse response) { private void handleTournamentResult(NetworkEvents.TournamentResultResponse response) {
IO.println(response.gameType()); IO.println(response.gameType());
IO.println(Arrays.toString(response.names())); 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) { private void handleReceivedMove(NetworkEvents.GameMoveResponse response) {

View File

@@ -65,7 +65,7 @@ public class NetworkEvents extends EventsBase {
public record GameResultResponse(long clientId, String condition) public record GameResultResponse(long clientId, String condition)
implements GenericEvent {} 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<Integer[]> scores)
implements GenericEvent {} implements GenericEvent {}
/** Indicates that a game move has been processed or received. */ /** Indicates that a game move has been processed or received. */

View File

@@ -3,7 +3,9 @@ package org.toop.framework.networking.connection.handlers;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.regex.MatchResult; import java.util.regex.MatchResult;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -117,10 +119,13 @@ public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter {
} }
private void resultsHandler(String rec) { private void resultsHandler(String rec) {
// TODO all of this
IO.println(rec); IO.println(rec);
String gameTypeRaw = extract(rec, "GAMETYPE"); String gameTypeRaw = extract(rec, "GAMETYPE");
String usersRaw = extract(rec, "USERS"); String usersRaw = extract(rec, "USERS");
String scoreTypesRaw = extract(rec, "SCORETYPES");
String scoresRaw = extract(rec, "SCORES"); String scoresRaw = extract(rec, "SCORES");
if (usersRaw == null) return; if (usersRaw == null) return;
@@ -134,16 +139,32 @@ public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter {
users = new String[]{}; 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 == null) return;
if (scoresRaw.length() > 2) { if (scoresRaw.length() > 2) {
Integer[] scores = Arrays.stream(scoresRaw.substring(1, scoresRaw.length() - 1).split(",")) List<Integer[]> scores = Arrays.stream(
.map(String::trim) scoresRaw.substring(1, scoresRaw.length() - 1) // remove outer []
.map(Integer::parseInt) .split("\\],\\[")
.toArray(Integer[]::new); )
.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 { } else {
eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, new Integer[]{})); eventBus.post(new NetworkEvents.TournamentResultResponse(this.connectionId, gameTypeRaw, users, scoreTypes, new ArrayList<>()));
} }
} }

View File

@@ -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.TurnBasedGameStore;
import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore; import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore;
import org.toop.framework.networking.server.tournaments.*; import org.toop.framework.networking.server.tournaments.*;
import org.toop.framework.networking.server.tournaments.matchmakers.RoundRobinMatchMaker; import org.toop.framework.networking.server.tournaments.matchmakers.DoubleRoundRobinMatchMaker;
import org.toop.framework.networking.server.tournaments.scoresystems.BasicScoreSystem; import org.toop.framework.networking.server.tournaments.scoresystems.*;
import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem;
import org.toop.framework.networking.server.tournaments.shufflers.RandomShuffle;
import org.toop.framework.utils.ImmutablePair; import org.toop.framework.utils.ImmutablePair;
import java.util.*; import java.util.*;
@@ -298,38 +296,57 @@ public class Server implements GameServer<TurnBasedGame, NettyClient, Long> {
Tournament tournament = new Tournament.Builder() Tournament tournament = new Tournament.Builder()
.matchExecutor(this::startGame) .matchExecutor(this::startGame)
.tournamentRunner(new AsyncTournamentRunner()) .tournamentRunner(new AsyncTournamentRunner())
.matchMaker(new RoundRobinMatchMaker()) .matchMaker(new DoubleRoundRobinMatchMaker())
.scoreSystem(new BasicScoreSystem()) .addScoreSystem(new MatchCountScoreSystem())
.addScoreSystem(new WinCountScoreSystem())
.addScoreSystem(new DrawCountScoreSystem())
.addScoreSystem(new LoseCountScoreSystem())
.resultBroadcaster(this::endTournament) .resultBroadcaster(this::endTournament)
.turnTimeout(Duration.ofSeconds(10)) .turnTimeout(Duration.ofSeconds(10))
.addPlayers(tournamentUsers.toArray(NettyClient[]::new)) .addPlayers(tournamentUsers.toArray(NettyClient[]::new))
.addAdmins(admins.toArray(NettyClient[]::new)) .addAdmins(admins.toArray(NettyClient[]::new))
.addMatchShuffler(new RandomShuffle())
.build(); .build();
new Thread(() -> tournament.run(gameType)).start(); new Thread(() -> tournament.run(gameType)).start();
} }
public void endTournament(IntegerScoreSystem score) { public void endTournament(List<IntegerScoreSystem> systems) {
if (systems.isEmpty()) return;
List<String> u = new ArrayList<>(); Map<String, List<ImmutablePair<String, Integer>>> combined = new HashMap<>();
List<Integer> s = new ArrayList<>();
for (var entry : score.getScore().entrySet()) { for (var system : systems) {
u.add(entry.getKey().name()); for (var player : system.getScore().keySet()) {
s.add(entry.getValue()); combined.putIfAbsent(player.name(), new ArrayList<>());
combined.get(player.name()).addLast(new ImmutablePair<>(system.scoreName(), system.getScore().get(player)));
}
}
List<String> names = new ArrayList<>();
List<String> systemNames = new ArrayList<>();
List<List<Integer>> 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(); Gson gson = new Gson();
String users = gson.toJson(u); String namesJson = gson.toJson(names);
String scores = gson.toJson(s); String systemNamesJson = gson.toJson(systemNames);
String scoresJson = gson.toJson(scores);
String msg = String.format( 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 "none", // TODO gametype
users, namesJson,
scores systemNamesJson,
scoresJson
); );
for (var user : onlineUsers()) { for (var user : onlineUsers()) {

View File

@@ -16,7 +16,7 @@ public class AsyncTournamentRunner implements TournamentRunner {
public void run( public void run(
MatchExecutor matchRunner, MatchExecutor matchRunner,
MatchMaker matchMaker, MatchMaker matchMaker,
IntegerScoreSystem scoreSystem, List<IntegerScoreSystem> scoreSystems,
ResultBroadcaster<IntegerScoreSystem> broadcaster, ResultBroadcaster<IntegerScoreSystem> broadcaster,
Duration turnTime, Duration turnTime,
String gameType String gameType
@@ -56,7 +56,7 @@ public class AsyncTournamentRunner implements TournamentRunner {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
GameResultFuture game = matchRunner.submit(gameType, turnTime, a, b); GameResultFuture game = matchRunner.submit(gameType, turnTime, a, b);
scoreSystem.result(match, game.result().join()); scoreSystems.forEach(s -> s.result(match, game.result().join()));
} finally { } finally {
a.clearGame(); a.clearGame();
b.clearGame(); b.clearGame();
@@ -73,7 +73,7 @@ public class AsyncTournamentRunner implements TournamentRunner {
Thread.sleep(10); // Safety Thread.sleep(10); // Safety
} }
broadcaster.broadcast(scoreSystem); broadcaster.broadcast(scoreSystems);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();

View File

@@ -6,6 +6,7 @@ import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker;
import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem; import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem;
import java.time.Duration; import java.time.Duration;
import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
public class BasicTournamentRunner implements TournamentRunner { public class BasicTournamentRunner implements TournamentRunner {
@@ -13,7 +14,7 @@ public class BasicTournamentRunner implements TournamentRunner {
public void run( public void run(
MatchExecutor matchExecutor, MatchExecutor matchExecutor,
MatchMaker matchMaker, MatchMaker matchMaker,
IntegerScoreSystem scoreSystem, List<IntegerScoreSystem> scoreSystems,
ResultBroadcaster<IntegerScoreSystem> broadcaster, ResultBroadcaster<IntegerScoreSystem> broadcaster,
Duration turnTime, Duration turnTime,
String gameType String gameType
@@ -24,13 +25,13 @@ public class BasicTournamentRunner implements TournamentRunner {
for (TournamentMatch match : matchMaker) { for (TournamentMatch match : matchMaker) {
// Play game and await the results // Play game and await the results
GameResultFuture game = matchExecutor.submit(gameType, turnTime, match.getClient0(), match.getClient1()); 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.getClient0().clearGame();
match.getClient1().clearGame(); match.getClient1().clearGame();
} }
broadcaster.broadcast(scoreSystem); broadcaster.broadcast(scoreSystems);
}); });
} finally { } finally {
threadPool.shutdown(); threadPool.shutdown();

View File

@@ -2,7 +2,9 @@ package org.toop.framework.networking.server.tournaments;
import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem; import org.toop.framework.networking.server.tournaments.scoresystems.ScoreSystem;
import java.util.List;
@FunctionalInterface @FunctionalInterface
public interface ResultBroadcaster<T extends ScoreSystem<?, ?, ?>> { public interface ResultBroadcaster<T extends ScoreSystem<?, ?, ?>> {
void broadcast(T scoreSystem); void broadcast(List<T> scoreSystem);
} }

View File

@@ -7,13 +7,15 @@ import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScor
import org.toop.framework.networking.server.tournaments.shufflers.Shuffler; import org.toop.framework.networking.server.tournaments.shufflers.Shuffler;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Objects; import java.util.Objects;
public class Tournament { public class Tournament {
private final MatchExecutor matchExecutor; private final MatchExecutor matchExecutor;
private final IntegerScoreSystem scoreSystem; private final List<IntegerScoreSystem> scoreSystems;
private final TournamentRunner tournamentRunner; private final TournamentRunner tournamentRunner;
private final MatchMaker matchMaker; private final MatchMaker matchMaker;
private final ResultBroadcaster<IntegerScoreSystem> broadcaster; private final ResultBroadcaster<IntegerScoreSystem> broadcaster;
@@ -23,7 +25,7 @@ public class Tournament {
private Tournament(Tournament.Builder builder) { private Tournament(Tournament.Builder builder) {
matchExecutor = builder.matchExecutor; matchExecutor = builder.matchExecutor;
scoreSystem = builder.scoreSystem; scoreSystems = builder.scoreSystems;
tournamentRunner = builder.tournamentRunner; tournamentRunner = builder.tournamentRunner;
matchMaker = builder.matchMaker; matchMaker = builder.matchMaker;
broadcaster = builder.broadcaster; broadcaster = builder.broadcaster;
@@ -36,18 +38,18 @@ public class Tournament {
Arrays.stream(players).forEach(e -> { Arrays.stream(players).forEach(e -> {
matchMaker.addPlayer(e); matchMaker.addPlayer(e);
scoreSystem.addPlayer(e); scoreSystems.forEach(k -> k.addPlayer(e));
}); });
if (shuffler != null) matchMaker.shuffle(shuffler); 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 { public static class Builder {
private MatchExecutor matchExecutor; private MatchExecutor matchExecutor;
private IntegerScoreSystem scoreSystem; private List<IntegerScoreSystem> scoreSystems = new ArrayList<>();
private TournamentRunner tournamentRunner; private TournamentRunner tournamentRunner;
private MatchMaker matchMaker; private MatchMaker matchMaker;
private ResultBroadcaster<IntegerScoreSystem> broadcaster; private ResultBroadcaster<IntegerScoreSystem> broadcaster;
@@ -62,8 +64,8 @@ public class Tournament {
return this; return this;
} }
public Builder scoreSystem(IntegerScoreSystem scoreSystem) { public Builder addScoreSystem(IntegerScoreSystem scoreSystem) {
this.scoreSystem = scoreSystem; this.scoreSystems.addLast(scoreSystem);
return this; return this;
} }
@@ -109,7 +111,6 @@ public class Tournament {
public Tournament build() { public Tournament build() {
Objects.requireNonNull(matchExecutor, "matchExecutor"); Objects.requireNonNull(matchExecutor, "matchExecutor");
Objects.requireNonNull(scoreSystem, "scoreSystem");
Objects.requireNonNull(tournamentRunner, "tournamentRunner"); Objects.requireNonNull(tournamentRunner, "tournamentRunner");
Objects.requireNonNull(matchMaker, "matchMaker"); Objects.requireNonNull(matchMaker, "matchMaker");
Objects.requireNonNull(broadcaster, "resultBroadcaster"); // TODO is not always necessary and needs to be more generic, not just at the end Objects.requireNonNull(broadcaster, "resultBroadcaster"); // TODO is not always necessary and needs to be more generic, not just at the end

View File

@@ -5,8 +5,9 @@ import org.toop.framework.networking.server.tournaments.matchmakers.MatchMaker;
import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem; import org.toop.framework.networking.server.tournaments.scoresystems.IntegerScoreSystem;
import java.time.Duration; import java.time.Duration;
import java.util.List;
public interface TournamentRunner { public interface TournamentRunner {
void run(MatchExecutor matchExecutor, MatchMaker matchMaker, IntegerScoreSystem scoreSystem, void run(MatchExecutor matchExecutor, MatchMaker matchMaker, List<IntegerScoreSystem> scoreSystems,
ResultBroadcaster<IntegerScoreSystem> broadcaster, Duration turnTime, String gameType); ResultBroadcaster<IntegerScoreSystem> broadcaster, Duration turnTime, String gameType);
} }

View File

@@ -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<NettyClient> 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<NettyClient> getPlayers() {
return players;
}
@Override
public Iterator<TournamentMatch> 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;
}
}
}
}
};
}
}

View File

@@ -37,7 +37,6 @@ public class RoundRobinMatchMaker implements MatchMaker {
private int i = 0; private int i = 0;
private int j = 1; private int j = 1;
private boolean reverse = false;
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@@ -55,26 +54,13 @@ public class RoundRobinMatchMaker implements MatchMaker {
NettyClient home = players.get(i); NettyClient home = players.get(i);
NettyClient away = players.get(j); NettyClient away = players.get(j);
TournamentMatch match = reverse ? new TournamentMatch(away, home) : new TournamentMatch(home, away);
advance();
return match;
}
private void advance() {
j++; j++;
if (j >= players.size()) { if (j >= players.size()) {
i++; i++;
j = i + 1; j = i + 1;
if (i >= players.size() - 1) {
if (!reverse) {
reverse = true;
i = 0;
j = 1;
}
}
} }
return new TournamentMatch(home, away);
} }
}; };
} }

View File

@@ -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<NettyClient, Integer> 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<NettyClient, Integer> getScore() {
return scores;
}
}

View File

@@ -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<NettyClient, Integer> 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<NettyClient, Integer> getScore() {
return scores;
}
}

View File

@@ -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<NettyClient, Integer> 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<NettyClient, Integer> getScore() {
return scores;
}
}

View File

@@ -3,6 +3,7 @@ package org.toop.framework.networking.server.tournaments.scoresystems;
import java.util.Map; import java.util.Map;
public interface ScoreSystem<MATCHTYPE, SCORETYPE, USERTYPE> { public interface ScoreSystem<MATCHTYPE, SCORETYPE, USERTYPE> {
String scoreName();
void addPlayer(USERTYPE user); void addPlayer(USERTYPE user);
void result(MATCHTYPE match, SCORETYPE result); void result(MATCHTYPE match, SCORETYPE result);
Map<USERTYPE, SCORETYPE> getScore(); Map<USERTYPE, SCORETYPE> getScore();

View File

@@ -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.client.NettyClient;
import org.toop.framework.networking.server.tournaments.TournamentMatch; import org.toop.framework.networking.server.tournaments.TournamentMatch;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class BasicScoreSystem implements IntegerScoreSystem { public class WinCountScoreSystem implements IntegerScoreSystem {
private final Map<NettyClient, Integer> scores = new ConcurrentHashMap<>(); private final Map<NettyClient, Integer> scores = new ConcurrentHashMap<>();
private final int INIT_SCORE = 0; private final int INIT_SCORE = 0;
private final int WIN_POINTS = 1; 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 @Override
public void addPlayer(NettyClient user) { public void addPlayer(NettyClient user) {