diff --git a/app/src/main/java/game/Game.java b/app/src/main/java/game/Game.java index 9e229e8..6e5d502 100644 --- a/app/src/main/java/game/Game.java +++ b/app/src/main/java/game/Game.java @@ -12,7 +12,7 @@ import sudoku.structure.MultiDoku; public class Game { public static enum GameState { - GameNotStarted, GameGoing, GameEnd + GameNotStarted, GameGoing } private final Map players; @@ -60,7 +60,7 @@ public class Game { } public void stopGame() { - this.gameState = GameState.GameEnd; + this.gameState = GameState.GameNotStarted; } public GameState getGameState() { diff --git a/app/src/main/java/gui/menu/EndGameView.java b/app/src/main/java/gui/menu/EndGameView.java new file mode 100644 index 0000000..409c3f1 --- /dev/null +++ b/app/src/main/java/gui/menu/EndGameView.java @@ -0,0 +1,49 @@ +package gui.menu; + +import game.Player; +import gui.ColorGenerator; +import gui.widget.SudokuRenderer; +import imgui.ImGui; +import imgui.ImVec4; +import sudoku.structure.MultiDoku; + +public class EndGameView extends BaseView { + + private final Player winner; + private float time = 0; + + private static final ImVec4 YELLOW = new ImVec4(1, 1, 0, 1); + + private final SudokuRenderer sudokuRenderer; + + public EndGameView(StateMachine stateMachine, MultiDoku resolved, Player winner) { + super(stateMachine); + this.winner = winner; + this.sudokuRenderer = new SudokuRenderer(resolved); + } + + private ImVec4 getPseudoColor() { + time += ImGui.getIO().getDeltaTime(); + float factor = (float) Math.cos(time); + var color = ColorGenerator.hslToRgb(factor * factor, 0.9f, 0.4f); + return new ImVec4(color.r, color.g, color.b, 1.0f); + } + + private void renderWinText() { + String winText = " a gagné !"; + String text = winner.getPseudo() + winText; + float textWidth = ImGui.calcTextSizeX(text); + ImGui.setCursorPosX(ImGui.getIO().getDisplaySizeX() / 2.0f - textWidth / 2.0f); + ImGui.textColored(getPseudoColor(), winner.getPseudo()); + ImGui.sameLine(); + ImGui.textColored(YELLOW, winText); + } + + @Override + public void render() { + renderWinText(); + this.sudokuRenderer.render(); + renderReturnButton(); + } + +} diff --git a/app/src/main/java/gui/menu/MultiPlayerDokuView.java b/app/src/main/java/gui/menu/MultiPlayerDokuView.java index a072c4d..f9ad32a 100644 --- a/app/src/main/java/gui/menu/MultiPlayerDokuView.java +++ b/app/src/main/java/gui/menu/MultiPlayerDokuView.java @@ -1,6 +1,6 @@ package gui.menu; -import game.Game; +import game.Player; import gui.widget.LeaderboardRenderer; import gui.widget.MultiPlayerCompleteProgress; import gui.widget.SudokuRenderer; @@ -8,7 +8,10 @@ import gui.widget.TimerRenderer; import imgui.ImGui; import network.client.Client; import network.server.Server; +import sudoku.solver.BacktrackingSolver; +import sudoku.solver.Solver; import sudoku.structure.Cell; +import sudoku.structure.MultiDoku; public class MultiPlayerDokuView extends BaseView { @@ -27,10 +30,19 @@ public class MultiPlayerDokuView extends BaseView { this.leaderboardRenderer = new LeaderboardRenderer(client.getGame(), client.getPlayer()); this.sudokuRenderer.onCellChange.connect(this::onCellChange); this.client.onDisconnect.connect(this::onDisconnect); + this.client.onGameEnd.connect(this::onGameEnd); this.timerRenderer = new TimerRenderer(this.client.getGame().getStartTime(), this.client.getGame().getGameDuration()); this.completeProgress = new MultiPlayerCompleteProgress(this.client.getGame()); } + private void onGameEnd(Player winner) { + MultiDoku doku = this.client.getGame().getDoku(); + doku.clearMutableCells(); + Solver solver = new BacktrackingSolver(); + solver.solve(doku); + this.stateMachine.overrideState(new EndGameView(stateMachine, doku, winner)); + } + private void onCellChange(Cell cell) { this.client.sendCellChange(cell); } diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index a175362..bb83800 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -27,6 +27,11 @@ public class StateMachine { menus.add(menu); } + public void overrideState(BaseView menu) { + menus.getLast().cleanResources(); + menus.set(menus.size() - 1, menu); + } + public void popState() { menus.getLast().cleanResources(); menus.pop(); diff --git a/app/src/main/java/gui/widget/MultiPlayerCompleteProgress.java b/app/src/main/java/gui/widget/MultiPlayerCompleteProgress.java index d442459..d5bebee 100644 --- a/app/src/main/java/gui/widget/MultiPlayerCompleteProgress.java +++ b/app/src/main/java/gui/widget/MultiPlayerCompleteProgress.java @@ -19,7 +19,7 @@ public class MultiPlayerCompleteProgress { } public void render() { - Player firstPlayer = game.getLeaderboard().get(0); + Player firstPlayer = game.getLeaderboard().getFirst(); ImGui.setCursorPosX(ImGui.getIO().getDisplaySizeX() / 2.0f - progressSize.x / 2.0f); String progressText = firstPlayer.getPseudo() + " - " + (emptyCellCount - firstPlayer.getRemainingCells()) + "/" + emptyCellCount; this.progressBar.render(progressText, progressSize, 1.0f - firstPlayer.getRemainingCells() / (float) emptyCellCount); diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java index 20bf94b..de7865c 100644 --- a/app/src/main/java/network/client/Client.java +++ b/app/src/main/java/network/client/Client.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.UnknownHostException; import java.util.Random; +import common.ConsumerSignal; import common.Signal; import game.Game; import game.Player; @@ -21,6 +22,7 @@ public class Client { public final Signal onDisconnect = new Signal(); public final Signal onClosed = new Signal(); public final Signal onGameStarted = new Signal(); + public final ConsumerSignal onGameEnd = new ConsumerSignal<>(); Player player; diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index 0d56dc1..71945ff 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -78,8 +78,9 @@ public class ClientConnexion extends Connexion { @Override public void visitPacket(EndGamePacket packet) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + Player winner = this.client.getGame().getLeaderboard().getFirst(); + this.client.getGame().stopGame(); + this.client.onGameEnd.emit(winner); } @Override diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index fcf87be..7c746be 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -8,7 +8,9 @@ import java.util.List; import game.Game; import game.Player; +import game.Game.GameState; import network.protocol.Packet; +import network.protocol.packets.EndGamePacket; import network.protocol.packets.StartGamePacket; import sudoku.io.SudokuSerializer; import sudoku.structure.MultiDoku; @@ -38,7 +40,16 @@ public class Server { } } - public void update() { + private void checkTimer() { + if (getGame() == null || getGame().getGameState() != GameState.GameGoing) + return; + long now = Instant.now().getEpochSecond(); + long end = getGame().getStartTime().getEpochSecond() + getGame().getGameDuration(); + if (now > end) + stopGame(); + } + + private void checkConnexions() { for (var it = connexions.iterator(); it.hasNext();) { ServerConnexion connexion = it.next(); if (!connexion.update()) { @@ -49,6 +60,11 @@ public class Server { } } + public void update() { + checkTimer(); + checkConnexions(); + } + public void stop() { this.acceptThread.cancel(); this.logicThread.cancel(); @@ -78,4 +94,10 @@ public class Server { broadcastPacket(new StartGamePacket(SudokuSerializer.serializeSudoku(doku).toString(), now, gameDuration)); } + public void stopGame() { + // we don't need to specify the winner since it has to be the first + broadcastPacket(new EndGamePacket()); + getGame().stopGame(); + } + } diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index 5f656dd..68de01b 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -153,9 +153,7 @@ public class ServerConnexion extends Connexion { private void checkWin() { if (this.player.getRemainingCells() == 0) { - // we don't need to specify the winner since it has to be the first - this.server.broadcastPacket(new EndGamePacket()); - this.server.getGame().stopGame(); + this.server.stopGame(); } } diff --git a/app/src/main/java/network/server/ServerLogicThread.java b/app/src/main/java/network/server/ServerLogicThread.java index c9b2a4b..d238ca2 100644 --- a/app/src/main/java/network/server/ServerLogicThread.java +++ b/app/src/main/java/network/server/ServerLogicThread.java @@ -19,7 +19,7 @@ public class ServerLogicThread extends Thread { try { Thread.sleep(50); } catch (InterruptedException e) { - // e.printStackTrace(); + e.printStackTrace(); break; } } diff --git a/app/src/main/java/sudoku/structure/MultiDoku.java b/app/src/main/java/sudoku/structure/MultiDoku.java index 569c163..d817eb7 100644 --- a/app/src/main/java/sudoku/structure/MultiDoku.java +++ b/app/src/main/java/sudoku/structure/MultiDoku.java @@ -183,6 +183,15 @@ public class MultiDoku { return emptyCells.get(randomIndex); } + public void clearMutableCells() { + for (Sudoku s : getSubGrids()) { + for (Cell cell : s.getCells()) { + if (cell.isMutable()) + cell.clearCurrentSymbol(); + } + } + } + public MultiDoku clone() { //TODO: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah return SudokuSerializer.deserializeSudoku(SudokuSerializer.serializeSudoku(this));