diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index c9385ee..05ab3bb 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -211,7 +211,7 @@ public final class Server { Player[] players = new Player[2]; - players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(100), user); + players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(200000), user); players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { diff --git a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java index a4c5ac5..e3eeab2 100644 --- a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java +++ b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java @@ -1,31 +1,39 @@ package org.toop.framework.game.gameThreads; -import org.toop.framework.eventbus.EventFlow; import org.toop.framework.gameFramework.GameState; import org.toop.framework.gameFramework.model.game.PlayResult; import org.toop.framework.gameFramework.model.game.TurnBasedGame; import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour; import org.toop.framework.gameFramework.model.player.Player; -import org.toop.framework.gameFramework.view.GUIEvents; import org.toop.framework.utils.ImmutablePair; import org.toop.framework.utils.Pair; +import java.time.Duration; +import java.util.concurrent.*; import java.util.function.Consumer; -import static org.toop.framework.gameFramework.GameState.TURN_SKIPPED; -import static org.toop.framework.gameFramework.GameState.WIN; - public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Runnable { private final Consumer> onPlayerMove; private final Consumer> onGameEnd; + + private final ExecutorService moveExecutor = Executors.newSingleThreadExecutor(); + + private final Duration timeOut; /** * Creates a new base behaviour for the specified game. * * @param game the turn-based game to control */ - public ServerThreadBehaviour(TurnBasedGame game, Consumer> onPlayerMove, Consumer> onGameEnd) { + public ServerThreadBehaviour( + TurnBasedGame game, + Consumer> onPlayerMove, + Consumer> onGameEnd, + Duration timeOut + ) { this.onPlayerMove = onPlayerMove; this.onGameEnd = onGameEnd; + this.timeOut = timeOut; super(game); } @@ -59,23 +67,42 @@ public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Ru public void run() { while (isRunning.get()) { Player currentPlayer = game.getPlayer(game.getCurrentTurn()); - long move = currentPlayer.getMove(game.deepCopy()); - PlayResult result = game.play(move); - GameState state = result.state(); - notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(move))); + Future move = moveExecutor.submit(() -> currentPlayer.getMove(game.deepCopy())); - switch (state) { - case WIN, DRAW -> { - isRunning.set(false); - notifyGameEnd(new ImmutablePair<>(state, game.getWinner())); - } - case NORMAL, TURN_SKIPPED -> { /* continue normally */ } - default -> { - logger.error("Unexpected state {}", state); - isRunning.set(false); - throw new RuntimeException("Unknown state: " + state); + PlayResult result; + try { + long moveResult = move.get(timeOut.toMillis(), TimeUnit.MILLISECONDS); + result = game.play(moveResult); + + GameState state = result.state(); + notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(moveResult))); + + switch (state) { + case WIN, DRAW -> { + isRunning.set(false); + moveExecutor.shutdown(); + notifyGameEnd(new ImmutablePair<>(state, game.getWinner())); + } + case NORMAL, TURN_SKIPPED -> { /* continue normally */ } + default -> { + logger.error("Unexpected state {}", state); + isRunning.set(false); + moveExecutor.shutdown(); + throw new RuntimeException("Unknown state: " + state); + } } + + } catch (InterruptedException | ExecutionException e) { + isRunning.set(false); + notifyGameEnd(new ImmutablePair<>(GameState.DRAW, 0)); + moveExecutor.shutdown(); + return; + } catch (TimeoutException e) { + isRunning.set(false); + notifyGameEnd(new ImmutablePair<>(GameState.WIN, 1+game.getWinner()%2)); + moveExecutor.shutdown(); + return; } } } diff --git a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java index 610e609..4fbcf1b 100644 --- a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java +++ b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java @@ -29,13 +29,8 @@ public class ServerPlayer extends AbstractPlayer { @Override public long determineMove(TurnBasedGame game) { lastMove = new CompletableFuture<>(); - System.out.println("Sending yourturn"); - client.send("SVR GAME YOURTURN {TURNMESSAGE: \"\"}\n"); - try { - return lastMove.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - return 0; - } + + client.send("SVR GAME YOURTURN {TURNMESSAGE: \"\"}"); + return lastMove.join(); } } diff --git a/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java index 2e9ec32..ffbb935 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java +++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java @@ -5,7 +5,7 @@ import org.toop.framework.gameFramework.GameState; import org.toop.framework.gameFramework.model.game.TurnBasedGame; import org.toop.framework.networking.server.client.NettyClient; -import java.util.ArrayList; +import java.time.Duration; import java.util.Arrays; import java.util.concurrent.CompletableFuture; @@ -19,12 +19,13 @@ public class OnlineTurnBasedGame implements OnlineGame { private final CompletableFuture resultFuture; - public OnlineTurnBasedGame(NettyClient[] admins, TurnBasedGame game, CompletableFuture resultFuture, NettyClient... clients) { + public OnlineTurnBasedGame(NettyClient[] admins, TurnBasedGame game, CompletableFuture resultFuture, Duration timeOut, NettyClient... clients) { this.game = game; this.gameThread = new ServerThreadBehaviour( game, (pair) -> notifyMoveMade(pair.getLeft(), pair.getRight()), - (pair) -> notifyGameEnd(pair.getLeft(), pair.getRight()) + (pair) -> notifyGameEnd(pair.getLeft(), pair.getRight()), + timeOut ); this.resultFuture = resultFuture; this.clients = clients; @@ -42,17 +43,15 @@ public class OnlineTurnBasedGame implements OnlineGame { private void notifyGameEnd(GameState state, int winner) { if (state == GameState.DRAW) { - Arrays.stream(admins).forEach(a -> a.send( - String.format("SVR GAME END") - )); + Arrays.stream(admins).forEach(a -> a.send("SVR GAME END")); for (NettyClient client : clients) { - client.send(String.format("SVR GAME DRAW {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}")); + client.send("SVR GAME DRAW {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}"); } } else { Arrays.stream(admins).forEach(a -> a.send("SVR GAME END")); - clients[winner].send(String.format("SVR GAME WIN {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}")); - clients[(winner+1)%2].send(String.format("SVR GAME LOSS {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}")); + clients[winner].send("SVR GAME WIN {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}"); + clients[(winner+1)%2].send("SVR GAME LOSS {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"\"}"); } // Remove game from clients 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 5300ce8..0b82943 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 @@ -145,6 +145,7 @@ public class Server implements GameServer { getAdmins().toArray(NettyClient[]::new), gameTypesStore.create(gameType), gameResult, + turnTime, clients ); @@ -166,6 +167,7 @@ public class Server implements GameServer { clients[0].name(), gameType, clients[0].name())); + game.start(); return grfReturn; } catch (Exception e) {