diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 655cfae..1448990 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,9 +1,591 @@ \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index 00f91cc..9df2e2d 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -1,8 +1,8 @@ package org.toop.app; -import org.toop.app.game.Connect4Game; -import org.toop.app.game.ReversiGame; -import org.toop.app.game.TicTacToeGame; +import org.toop.app.game.Connect4GameThread; +import org.toop.app.game.ReversiGameThread; +import org.toop.app.game.TicTacToeGameThread; import org.toop.app.widget.WidgetContainer; import org.toop.app.widget.popup.ChallengePopup; import org.toop.app.widget.popup.ErrorPopup; @@ -131,11 +131,11 @@ public final class Server { switch (type) { case TICTACTOE -> - new TicTacToeGame(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); + new TicTacToeGameThread(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); case REVERSI -> - new ReversiGame(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); + new ReversiGameThread(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); case CONNECT4 -> - new Connect4Game(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); + new Connect4GameThread(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable); default -> new ErrorPopup("Unsupported game type."); } } diff --git a/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java b/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java index c17dafd..913bb62 100644 --- a/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java +++ b/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java @@ -6,6 +6,6 @@ import java.util.function.Consumer; public class Connect4Canvas extends GameCanvas { public Connect4Canvas(Color color, int width, int height, Consumer onCellClicked) { - super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked,null); + super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/canvas/GameCanvas.java b/app/src/main/java/org/toop/app/canvas/GameCanvas.java index f8f6d70..7342f5b 100644 --- a/app/src/main/java/org/toop/app/canvas/GameCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/GameCanvas.java @@ -35,8 +35,9 @@ public abstract class GameCanvas { protected final boolean edges; protected final Cell[] cells; + protected Cell currentCell; - protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer onCellClicked, Consumer newCellEntered) { + protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer onCellClicked) { canvas = new Canvas(width, height); graphics = canvas.getGraphicsContext2D(); @@ -53,6 +54,7 @@ public abstract class GameCanvas { this.edges = edges; cells = new Cell[rowSize * columnSize]; + currentCell = null; final float cellWidth = ((float) width - gapSize * rowSize - gapSize) / rowSize; final float cellHeight = ((float) height - gapSize * columnSize - gapSize) / columnSize; @@ -82,12 +84,24 @@ public abstract class GameCanvas { } }); - - - render(); } + public void setOnCellEntered(Consumer onCellEntered) { + canvas.setOnMouseMoved(event -> { + final int column = (int) ((event.getX() / this.width) * rowSize); + final int row = (int) ((event.getY() / this.height) * columnSize); + + final Cell cell = cells[column + row * rowSize]; + + if (currentCell != cell && cell.isInside(event.getX(), event.getY())) { + event.consume(); + currentCell = cell; + onCellEntered.accept(column + row * rowSize); + } + }); + } + private void render() { graphics.setFill(backgroundColor); graphics.fillRect(0, 0, width, height); diff --git a/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java index c1b24f7..53d0b7d 100644 --- a/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java @@ -7,61 +7,38 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; public final class ReversiCanvas extends GameCanvas { - private Move[] currentlyHighlightedMoves = null; - public ReversiCanvas(Color color, int width, int height, Consumer onCellClicked, Consumer newCellEntered) { - super(color, new Color(0f,0.4f,0.2f,1f), width, height, 8, 8, 5, true, onCellClicked, newCellEntered); + private Move[] currentlyHighlightedMoves = null; + + public ReversiCanvas(Color color, int width, int height, Consumer onCellClicked) { + super(color, new Color(0f, 0.4f, 0.2f, 1f), width, height, 8, 8, 5, true, onCellClicked); drawStartingDots(); - - final AtomicReference lastHoveredCell = new AtomicReference<>(null); - - canvas.setOnMouseMoved(event -> { - double mouseX = event.getX(); - double mouseY = event.getY(); - int cellId = -1; - - Cell hovered = null; - for (Cell cell : cells) { - if (cell.isInside(mouseX, mouseY)) { - hovered = cell; - cellId = turnCoordsIntoCellId(mouseX, mouseY); - break; - } - } - - Cell previous = lastHoveredCell.get(); - - if (hovered != previous) { - lastHoveredCell.set(hovered); - newCellEntered.accept(cellId); - } - }); } - public void setCurrentlyHighlightedMovesNull() { - currentlyHighlightedMoves = null; - } + public void setCurrentlyHighlightedMovesNull() { + currentlyHighlightedMoves = null; + } - public void drawHighlightDots(Move[] moves){ - if (currentlyHighlightedMoves != null){ - for (final Move move : currentlyHighlightedMoves){ - Color color = move.value() == 'W'? Color.BLACK: Color.WHITE; - drawInnerDot(color, move.position(), true); - } - } - currentlyHighlightedMoves = moves; - if (moves != null) { - for (Move move : moves) { - Color color = move.value() == 'B' ? Color.BLACK : Color.WHITE; - drawInnerDot(color, move.position(), false); - } - } - } + public void drawHighlightDots(Move[] moves) { + if (currentlyHighlightedMoves != null) { + for (final Move move : currentlyHighlightedMoves) { + Color color = move.value() == 'W' ? Color.BLACK : Color.WHITE; + drawInnerDot(color, move.position(), true); + } + } + currentlyHighlightedMoves = moves; + if (moves != null) { + for (Move move : moves) { + Color color = move.value() == 'B' ? Color.BLACK : Color.WHITE; + drawInnerDot(color, move.position(), false); + } + } + } - private int turnCoordsIntoCellId(double x, double y) { - final int column = (int) ((x / this.width) * rowSize); - final int row = (int) ((y / this.height) * columnSize); - return column + row * rowSize; - } + private int turnCoordsIntoCellId(double x, double y) { + final int column = (int) ((x / this.width) * rowSize); + final int row = (int) ((y / this.height) * columnSize); + return column + row * rowSize; + } public void drawStartingDots() { drawDot(Color.BLACK, 28); @@ -71,16 +48,14 @@ public final class ReversiCanvas extends GameCanvas { } public void drawLegalPosition(int cell, char player) { + Color innerColor; - Color innerColor; - if (player == 'B') { - innerColor = new Color(0.0f, 0.0f, 0.0f, 0.6f); - } - else { - innerColor = new Color(1.0f, 1.0f, 1.0f, 0.75f); - } - drawInnerDot(innerColor, cell,false); - public void drawLegalPosition(Color color, int cell) { - drawDot(new Color(color.getRed(), color.getGreen(), color.getBlue(), 0.25), cell); + if (player == 'B') { + innerColor = new Color(0.0f, 0.0f, 0.0f, 0.6f); + } else { + innerColor = new Color(1.0f, 1.0f, 1.0f, 0.75f); + } + + drawInnerDot(innerColor, cell, false); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java index 890eb39..d7ccbc8 100644 --- a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java @@ -6,7 +6,7 @@ import java.util.function.Consumer; public final class TicTacToeCanvas extends GameCanvas { public TicTacToeCanvas(Color color, int width, int height, Consumer onCellClicked) { - super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null); + super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked); } public void drawX(Color color, int cell) { diff --git a/app/src/main/java/org/toop/app/game/BaseGameThread.java b/app/src/main/java/org/toop/app/game/BaseGameThread.java index f9178da..11b9076 100644 --- a/app/src/main/java/org/toop/app/game/BaseGameThread.java +++ b/app/src/main/java/org/toop/app/game/BaseGameThread.java @@ -6,6 +6,7 @@ import org.toop.app.widget.view.GameView; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.networking.events.NetworkEvents; import org.toop.game.Game; +import org.toop.game.records.Move; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -18,7 +19,7 @@ public abstract class BaseGameThread { protected final GameInformation information; protected final int myTurn; protected final Runnable onGameOver; - protected final BlockingQueue moveQueue; + protected final BlockingQueue moveQueue; protected final TGame game; protected final TAI ai; @@ -27,6 +28,7 @@ public abstract class BaseGameThread { protected final TCanvas canvas; protected final AtomicBoolean isRunning = new AtomicBoolean(true); + protected final AtomicBoolean isPaused = new AtomicBoolean(false); protected BaseGameThread( GameInformation information, @@ -76,7 +78,7 @@ public abstract class BaseGameThread { } private void onCellClicked(int cell) { - if (!isRunning.get()) return; + if (!isRunning.get() || isPaused.get()) return; final int currentTurn = getCurrentTurn(); if (!information.players[currentTurn].isHuman) return; @@ -84,8 +86,9 @@ public abstract class BaseGameThread { final char value = getSymbolForTurn(currentTurn); try { - moveQueue.put(new Game.Move(cell, value)); - } catch (InterruptedException _) {} + moveQueue.put(new Move(cell, value)); + } catch (InterruptedException _) { + } } protected void gameOver() { @@ -110,10 +113,13 @@ public abstract class BaseGameThread { protected abstract void addCanvasToPrimary(); protected abstract int getCurrentTurn(); + protected abstract char getSymbolForTurn(int turn); + protected abstract String getNameForTurn(int turn); protected abstract void onMoveResponse(NetworkEvents.GameMoveResponse response); + protected abstract void onYourTurnResponse(NetworkEvents.YourTurnResponse response); protected abstract void localGameThread(); diff --git a/app/src/main/java/org/toop/app/game/Connect4Game.java b/app/src/main/java/org/toop/app/game/Connect4Game.java deleted file mode 100644 index 76bd13e..0000000 --- a/app/src/main/java/org/toop/app/game/Connect4Game.java +++ /dev/null @@ -1,275 +0,0 @@ -package org.toop.app.game; - -import javafx.geometry.Pos; -import javafx.scene.paint.Color; -import org.toop.app.App; -import org.toop.app.GameInformation; -import org.toop.app.canvas.Connect4Canvas; -import org.toop.app.view.ViewStack; -import org.toop.app.view.views.GameView; -import org.toop.app.view.views.LocalMultiplayerView; -import org.toop.framework.eventbus.EventFlow; -import org.toop.framework.networking.events.NetworkEvents; -import org.toop.game.Connect4.Connect4; -import org.toop.game.Connect4.Connect4AI; -import org.toop.game.enumerators.GameState; -import org.toop.game.records.Move; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -public class Connect4Game { - private final GameInformation information; - - private final int myTurn; - private Runnable onGameOver; - private final BlockingQueue moveQueue; - - private final Connect4 game; - private final Connect4AI ai; - private final int columnSize = 7; - private final int rowSize = 6; - - private final GameView view; - private final Connect4Canvas canvas; - - private final AtomicBoolean isRunning; - - public Connect4Game(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer onMessage, Runnable onGameOver) { - this.information = information; - this.myTurn = myTurn; - this.onGameOver = onGameOver; - moveQueue = new LinkedBlockingQueue(); - - - game = new Connect4(); - ai = new Connect4AI(); - - isRunning = new AtomicBoolean(true); - - if (onForfeit == null || onExit == null) { - view = new GameView(null, () -> { - isRunning.set(false); - ViewStack.push(new LocalMultiplayerView(information)); - }, null); - } else { - view = new GameView(onForfeit, () -> { - isRunning.set(false); - onExit.run(); - }, onMessage); - } - - canvas = new Connect4Canvas(Color.GRAY, - (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, - (cell) -> { - if (onForfeit == null || onExit == null) { - if (information.players[game.getCurrentTurn()].isHuman) { - final char value = game.getCurrentTurn() == 0? 'X' : 'O'; - - try { - moveQueue.put(new Move(cell%columnSize, value)); - } catch (InterruptedException _) {} - } - } else { - if (information.players[0].isHuman) { - final char value = myTurn == 0? 'X' : 'O'; - - try { - moveQueue.put(new Move(cell%columnSize, value)); - } catch (InterruptedException _) {} - } - } - }); - - view.add(Pos.CENTER, canvas.getCanvas()); - ViewStack.push(view); - - if (onForfeit == null || onExit == null) { - new Thread(this::localGameThread).start(); - setGameLabels(information.players[0].isHuman); - } else { - new EventFlow() - .listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse) - .listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse) - .listen(NetworkEvents.ReceivedMessage.class, this::onReceivedMessage); - - setGameLabels(myTurn == 0); - } - updateCanvas(); - } - - public Connect4Game(GameInformation information) { - this(information, 0, null, null, null, null); - } - private void localGameThread() { - while (isRunning.get()) { - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "RED" : "BLUE"; - final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount(); - - view.nextPlayer(information.players[currentTurn].isHuman, - information.players[currentTurn].name, - currentValue, - information.players[nextTurn].name); - - Move move = null; - - if (information.players[currentTurn].isHuman) { - try { - final Move wants = moveQueue.take(); - final Move[] legalMoves = game.getLegalMoves(); - - for (final Move legalMove : legalMoves) { - if (legalMove.position() == wants.position() && - legalMove.value() == wants.value()) { - move = wants; - break; - } - } - } catch (InterruptedException _) {} - } else { - final long start = System.currentTimeMillis(); - - move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty); - - if (information.players[currentTurn].computerThinkTime > 0) { - final long elapsedTime = System.currentTimeMillis() - start; - final long sleepTime = Math.abs(information.players[currentTurn].computerThinkTime * 1000L - elapsedTime); - - try { - Thread.sleep((long)(sleepTime * Math.random())); - } catch (InterruptedException _) {} - } - } - - if (move == null) { - continue; - } - - final GameState state = game.play(move); - updateCanvas(); -/* - if (move.value() == 'X') { - canvas.drawX(Color.INDIANRED, move.position()); - } else if (move.value() == 'O') { - canvas.drawO(Color.ROYALBLUE, move.position()); - } -*/ - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - view.gameOver(true, information.players[currentTurn].name); - } else if (state == GameState.DRAW) { - view.gameOver(false, ""); - } - - isRunning.set(false); - } - } - } - - private void onMoveResponse(NetworkEvents.GameMoveResponse response) { - if (!isRunning.get()) { - return; - } - - char playerChar; - - if (response.player().equalsIgnoreCase(information.players[0].name)) { - playerChar = myTurn == 0? 'X' : 'O'; - } else { - playerChar = myTurn == 0? 'O' : 'X'; - } - - final Move move = new Move(Integer.parseInt(response.move()), playerChar); - final GameState state = game.play(move); - - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - if (response.player().equalsIgnoreCase(information.players[0].name)) { - view.gameOver(true, information.players[0].name); - gameOver(); - } else { - view.gameOver(false, information.players[1].name); - gameOver(); - } - } else if (state == GameState.DRAW) { - view.gameOver(false, ""); - gameOver(); - } - } - - if (move.value() == 'X') { - canvas.drawDot(Color.INDIANRED, move.position()); - } else if (move.value() == 'O') { - canvas.drawDot(Color.ROYALBLUE, move.position()); - } - - updateCanvas(); - setGameLabels(game.getCurrentTurn() == myTurn); - } - - private void gameOver() { - if (onGameOver == null){ - return; - } - isRunning.set(false); - onGameOver.run(); - } - - private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) { - - if (!isRunning.get()) { - return; - } - - moveQueue.clear(); - - int position = -1; - - if (information.players[0].isHuman) { - try { - position = moveQueue.take().position(); - } catch (InterruptedException _) {} - } else { - final Move move = ai.findBestMove(game, information.players[0].computerDifficulty); - - assert move != null; - position = move.position(); - } - - new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short)position)) - .postEvent(); - } - - private void onReceivedMessage(NetworkEvents.ReceivedMessage msg) { - if (!isRunning.get()) { - return; - } - - view.updateChat(msg.message()); - } - - private void updateCanvas() { - canvas.clearAll(); - - for (int i = 0; i < game.getBoard().length; i++) { - if (game.getBoard()[i] == 'X') { - canvas.drawDot(Color.RED, i); - } else if (game.getBoard()[i] == 'O') { - canvas.drawDot(Color.BLUE, i); - } - } - } - - private void setGameLabels(boolean isMe) { - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "RED" : "BLUE"; - - view.nextPlayer(isMe, - information.players[isMe? 0 : 1].name, - currentValue, - information.players[isMe? 1 : 0].name); - } -} diff --git a/app/src/main/java/org/toop/app/game/Connect4GameThread.java b/app/src/main/java/org/toop/app/game/Connect4GameThread.java new file mode 100644 index 0000000..a0d4174 --- /dev/null +++ b/app/src/main/java/org/toop/app/game/Connect4GameThread.java @@ -0,0 +1,188 @@ +package org.toop.app.game; + +import javafx.geometry.Pos; +import javafx.scene.paint.Color; +import org.toop.app.App; +import org.toop.app.GameInformation; +import org.toop.app.canvas.Connect4Canvas; +import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.networking.events.NetworkEvents; +import org.toop.game.Connect4.Connect4; +import org.toop.game.Connect4.Connect4AI; +import org.toop.game.enumerators.GameState; +import org.toop.game.records.Move; + +import java.util.function.Consumer; + +public final class Connect4GameThread extends BaseGameThread { + private static final int COLS = 7; + + public Connect4GameThread( + GameInformation info, + int myTurn, + Runnable onForfeit, + Runnable onExit, + Consumer onMessage, + Runnable onGameOver + ) { + super( + info, + myTurn, + onForfeit, + onExit, + onMessage, + onGameOver, + Connect4::new, + Connect4AI::new, + clickHandler -> new Connect4Canvas( + Color.GRAY, + (App.getHeight() / 4) * 3, + (App.getHeight() / 4) * 3, + cell -> clickHandler.accept(cell % COLS) + ) + ); + } + + public Connect4GameThread(GameInformation info) { + this(info, 0, null, null, null, null); + } + + @Override + protected void addCanvasToPrimary() { + primary.add(Pos.CENTER, canvas.getCanvas()); + } + + @Override + protected int getCurrentTurn() { + return game.getCurrentTurn(); + } + + @Override + protected char getSymbolForTurn(int turn) { + return turn == 0 ? 'X' : 'O'; + } + + @Override + protected String getNameForTurn(int turn) { + return turn == 0 ? "RED" : "BLUE"; + } + + private void drawMove(Move move) { + if (move.value() == 'X') + canvas.drawDot(Color.RED, move.position()); + else + canvas.drawDot(Color.BLUE, move.position()); + } + + @Override + protected void onMoveResponse(NetworkEvents.GameMoveResponse response) { + if (!isRunning.get()) return; + + char symbol = + response.player().equalsIgnoreCase(information.players[0].name) + ? (myTurn == 0 ? 'X' : 'O') + : (myTurn == 0 ? 'O' : 'X'); + + final Move move = new Move(Integer.parseInt(response.move()), symbol); + final GameState state = game.play(move); + + drawMove(move); + updateCanvas(); + + if (state != GameState.NORMAL) { + if (state == GameState.WIN) { + boolean p0 = response.player().equalsIgnoreCase(information.players[0].name); + primary.gameOver(p0, information.players[p0 ? 0 : 1].name); + gameOver(); + } else if (state == GameState.DRAW) { + primary.gameOver(false, ""); + gameOver(); + } + } + + setGameLabels(game.getCurrentTurn() == myTurn); + } + + @Override + protected void onYourTurnResponse(NetworkEvents.YourTurnResponse response) { + if (!isRunning.get()) return; + + moveQueue.clear(); + int col = -1; + + if (information.players[0].isHuman) { + try { + col = moveQueue.take().position(); + } catch (InterruptedException _) { + } + } else { + final Move move = ai.findBestMove(game, information.players[0].computerDifficulty); + assert move != null; + col = move.position(); + } + + new EventFlow() + .addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short) col)) + .postEvent(); + } + + @Override + protected void localGameThread() { + while (isRunning.get()) { + final int current = game.getCurrentTurn(); + setGameLabels(current == myTurn); + + Move move = null; + + if (information.players[current].isHuman) { + try { + final Move wants = moveQueue.take(); + for (final Move legal : game.getLegalMoves()) { + if (legal.position() == wants.position() && + legal.value() == wants.value()) { + move = wants; + break; + } + } + } catch (InterruptedException _) { + } + } else { + final long start = System.currentTimeMillis(); + move = ai.findBestMove(game, information.players[current].computerDifficulty); + + if (information.players[current].computerThinkTime > 0) { + long elapsed = System.currentTimeMillis() - start; + long sleep = information.players[current].computerThinkTime * 1000L - elapsed; + try { + Thread.sleep((long) (sleep * Math.random())); + } catch (InterruptedException _) { + } + } + } + + if (move == null) continue; + + GameState state = game.play(move); + drawMove(move); + updateCanvas(); + + if (state != GameState.NORMAL) { + if (state == GameState.WIN) + primary.gameOver(information.players[current].isHuman, information.players[current].name); + else if (state == GameState.DRAW) + primary.gameOver(false, ""); + isRunning.set(false); + } + } + } + + private void updateCanvas() { + canvas.clearAll(); + + for (int i = 0; i < game.getBoard().length; i++) { + char c = game.getBoard()[i]; + if (c == 'X') canvas.drawDot(Color.RED, i); + else if (c == 'O') canvas.drawDot(Color.BLUE, i); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/game/ReversiGame.java b/app/src/main/java/org/toop/app/game/ReversiGame.java deleted file mode 100644 index a65805e..0000000 --- a/app/src/main/java/org/toop/app/game/ReversiGame.java +++ /dev/null @@ -1,327 +0,0 @@ -package org.toop.app.game; - -import javafx.animation.SequentialTransition; -import org.toop.app.App; -import org.toop.app.GameInformation; -import org.toop.app.canvas.ReversiCanvas; -import org.toop.app.widget.WidgetContainer; -import org.toop.app.widget.view.GameView; -import org.toop.framework.eventbus.EventFlow; -import org.toop.framework.networking.events.NetworkEvents; -import org.toop.game.enumerators.GameState; -import org.toop.game.records.Move; -import org.toop.game.reversi.Reversi; -import org.toop.game.reversi.ReversiAI; - -import javafx.geometry.Pos; -import javafx.scene.paint.Color; - -import java.awt.*; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -public final class ReversiGame { - private final GameInformation information; - - private final int myTurn; - private final Runnable onGameOver; - private final BlockingQueue moveQueue; - private Runnable onGameOver; - private final BlockingQueue moveQueue; - - private final Reversi game; - private final ReversiAI ai; - - private final GameView primary; - private final ReversiCanvas canvas; - - private final AtomicBoolean isRunning; - private final AtomicBoolean isPaused; - - public ReversiGame(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer onMessage, Runnable onGameOver) { - this.information = information; - - this.myTurn = myTurn; - this.onGameOver = onGameOver; - moveQueue = new LinkedBlockingQueue<>(); - - game = new Reversi(); - ai = new ReversiAI(); - - isRunning = new AtomicBoolean(true); - isPaused = new AtomicBoolean(false); - - if (onForfeit == null || onExit == null) { - primary = new GameView(null, () -> { - isRunning.set(false); - WidgetContainer.getCurrentView().transitionPrevious(); - }, null); - } else { - primary = new GameView(onForfeit, () -> { - isRunning.set(false); - onExit.run(); - }, onMessage); - } - - canvas = new ReversiCanvas(Color.BLACK, - (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, - (cell) -> { - if (onForfeit == null || onExit == null) { - if (information.players[game.getCurrentTurn()].isHuman) { - final char value = game.getCurrentTurn() == 0? 'B' : 'W'; - - try { - moveQueue.put(new Move(cell, value)); - } catch (InterruptedException _) {} - } - } else { - if (information.players[0].isHuman) { - final char value = myTurn == 0? 'B' : 'W'; - - try { - moveQueue.put(new Move(cell, value)); - } catch (InterruptedException _) {} - } - } - },this::highlightCells); - - - - primary.add(Pos.CENTER, canvas.getCanvas()); - WidgetContainer.getCurrentView().transitionNext(primary); - - if (onForfeit == null || onExit == null) { - new Thread(this::localGameThread).start(); - setGameLabels(information.players[0].isHuman); - } else { - new EventFlow() - .listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse) - .listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse); - - setGameLabels(myTurn == 0); - } - - updateCanvas(false); - } - - public ReversiGame(GameInformation information) { - this(information, 0, null, null, null,null); - } - - private void localGameThread() { - while (isRunning.get()) { - if (isPaused.get()) { - try { - Thread.sleep(200); - } catch (InterruptedException _) {} - - continue; - } - - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "BLACK" : "WHITE"; - final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount(); - - primary.nextPlayer(information.players[currentTurn].isHuman, - information.players[currentTurn].name, - currentValue, - information.players[nextTurn].name); - - Move move = null; - - if (information.players[currentTurn].isHuman) { - try { - final Move wants = moveQueue.take(); - final Move[] legalMoves = game.getLegalMoves(); - - for (final Move legalMove : legalMoves) { - if (legalMove.position() == wants.position() && - legalMove.value() == wants.value()) { - move = wants; - break; - } - } - } catch (InterruptedException _) {} - } else { - final long start = System.currentTimeMillis(); - - move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty); - - if (information.players[currentTurn].computerThinkTime > 0) { - final long elapsedTime = System.currentTimeMillis() - start; - final long sleepTime = information.players[currentTurn].computerThinkTime * 1000L - elapsedTime; - - try { - Thread.sleep((long) (sleepTime * Math.random())); - } catch (InterruptedException _) {} - } - } - - if (move == null) { - continue; - } - - canvas.setCurrentlyHighlightedMovesNull(); - final GameState state = game.play(move); - updateCanvas(true); - - if (state != Game.State.NORMAL) { - if (state == Game.State.WIN) { - primary.gameOver(true, information.players[currentTurn].name); - } else if (state == Game.State.DRAW) { - primary.gameOver(false, ""); - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - view.gameOver(true, information.players[currentTurn].name); - } else if (state == GameState.DRAW) { - view.gameOver(false, ""); - } - - isRunning.set(false); - } - } - } - - private void onMoveResponse(NetworkEvents.GameMoveResponse response) { - if (!isRunning.get()) { - return; - } - - char playerChar; - - if (response.player().equalsIgnoreCase(information.players[0].name)) { - playerChar = myTurn == 0? 'B' : 'W'; - } else { - playerChar = myTurn == 0? 'W' : 'B'; - } - - final Move move = new Move(Integer.parseInt(response.move()), playerChar); - final GameState state = game.play(move); - - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - if (response.player().equalsIgnoreCase(information.players[0].name)) { - primary.gameOver(true, information.players[0].name); - gameOver(); - } else { - primary.gameOver(false, information.players[1].name); - gameOver(); - } - } else if (state == GameState.DRAW) { - view.gameOver(false, ""); - game.play(move); - } - } - - updateCanvas(false); - setGameLabels(game.getCurrentTurn() == myTurn); - } - - private void gameOver() { - if (onGameOver == null){ - return; - } - isRunning.set(false); - onGameOver.run(); - } - - private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) { - if (!isRunning.get()) { - return; - } - - moveQueue.clear(); - - int position = -1; - - if (information.players[0].isHuman) { - try { - position = moveQueue.take().position(); - } catch (InterruptedException _) {} - } else { - final Move move = ai.findBestMove(game, information.players[0].computerDifficulty); - - assert move != null; - position = move.position(); - } - - new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short) position)) - .postEvent(); - } - - private void updateCanvas(boolean animate) { - // Todo: this is very inefficient. still very fast but if the grid is bigger it might cause issues. improve. - canvas.clearAll(); - - for (int i = 0; i < game.getBoard().length; i++) { - if (game.getBoard()[i] == 'B') { - canvas.drawDot(Color.BLACK, i); - } else if (game.getBoard()[i] == 'W') { - canvas.drawDot(Color.WHITE, i); - } - } - - final Move[] flipped = game.getMostRecentlyFlippedPieces(); - - final SequentialTransition animation = new SequentialTransition(); - isPaused.set(true); - - final Color fromColor = game.getCurrentPlayer() == 'W'? Color.WHITE : Color.BLACK; - final Color toColor = game.getCurrentPlayer() == 'W'? Color.BLACK : Color.WHITE; - - if (animate && flipped != null) { - for (final Move flip : flipped) { - canvas.clear(flip.position()); - canvas.drawDot(fromColor, flip.position()); - animation.getChildren().addFirst(canvas.flipDot(fromColor, toColor, flip.position())); - } - } - - animation.setOnFinished(_ -> { - isPaused.set(false); - - final Move[] legalMoves = game.getLegalMoves(); - - for (final Move legalMove : legalMoves) { - canvas.drawLegalPosition(legalMove.position(), game.getCurrentPlayer()); - for (final Game.Move legalMove : legalMoves) { - canvas.drawLegalPosition(fromColor, legalMove.position()); - } - }); - - animation.play(); - } - - private void setGameLabels(boolean isMe) { - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "BLACK" : "WHITE"; - - primary.nextPlayer(isMe, - information.players[isMe? 0 : 1].name, - currentValue, - information.players[isMe? 1 : 0].name); - } - - private void highlightCells(int cellEntered) { - Move[] legalMoves = game.getLegalMoves(); - boolean isLegalMove = false; - for (Move move : legalMoves) { - if (move.position() == cellEntered){ - isLegalMove = true; - break; - } - } - - if (cellEntered >= 0){ - Move[] moves = null; - if (isLegalMove) { - moves = game.getFlipsForPotentialMove( - new Point(cellEntered%game.getColumnSize(),cellEntered/game.getRowSize()), - game.getCurrentPlayer()); - } - canvas.drawHighlightDots(moves); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/game/ReversiGameThread.java b/app/src/main/java/org/toop/app/game/ReversiGameThread.java new file mode 100644 index 0000000..05c1706 --- /dev/null +++ b/app/src/main/java/org/toop/app/game/ReversiGameThread.java @@ -0,0 +1,241 @@ +package org.toop.app.game; + +import javafx.animation.SequentialTransition; +import javafx.geometry.Pos; +import javafx.scene.paint.Color; +import org.toop.app.App; +import org.toop.app.GameInformation; +import org.toop.app.canvas.ReversiCanvas; +import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.networking.events.NetworkEvents; +import org.toop.game.enumerators.GameState; +import org.toop.game.records.Move; +import org.toop.game.reversi.Reversi; +import org.toop.game.reversi.ReversiAI; + +import java.awt.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +public final class ReversiGameThread extends BaseGameThread { + public ReversiGameThread(GameInformation info, int myTurn, + Runnable onForfeit, Runnable onExit, Consumer onMessage, Runnable onGameOver) { + super(info, myTurn, onForfeit, onExit, onMessage, onGameOver, + Reversi::new, + ReversiAI::new, + clickHandler -> new ReversiCanvas( + Color.BLACK, + (App.getHeight() / 4) * 3, + (App.getHeight() / 4) * 3, + clickHandler + ) + ); + + canvas.setOnCellEntered(this::highlightCells); + } + + public ReversiGameThread(GameInformation info) { + this(info, 0, null, null, null, null); + } + + @Override + protected void addCanvasToPrimary() { + primary.add(Pos.CENTER, canvas.getCanvas()); + } + + @Override + protected int getCurrentTurn() { + return game.getCurrentTurn(); + } + + @Override + protected char getSymbolForTurn(int turn) { + return turn == 0 ? 'B' : 'W'; + } + + @Override + protected String getNameForTurn(int turn) { + return turn == 0 ? "BLACK" : "WHITE"; + } + + private void drawMove(Move move) { + if (move.value() == 'B') canvas.drawDot(Color.BLACK, move.position()); + else canvas.drawDot(Color.WHITE, move.position()); + } + + @Override + protected void onMoveResponse(NetworkEvents.GameMoveResponse response) { + if (!isRunning.get()) return; + + char playerChar = + response.player().equalsIgnoreCase(information.players[0].name) + ? (myTurn == 0 ? 'B' : 'W') + : (myTurn == 0 ? 'W' : 'B'); + + final Move move = new Move(Integer.parseInt(response.move()), playerChar); + final GameState state = game.play(move); + + updateCanvas(true); + + if (state != GameState.NORMAL) { + if (state == GameState.WIN) { + boolean p0 = response.player().equalsIgnoreCase(information.players[0].name); + primary.gameOver(p0, information.players[p0 ? 0 : 1].name); + gameOver(); + } else if (state == GameState.DRAW) { + primary.gameOver(false, ""); + gameOver(); + } + } + + setGameLabels(game.getCurrentTurn() == myTurn); + } + + @Override + protected void onYourTurnResponse(NetworkEvents.YourTurnResponse response) { + if (!isRunning.get()) return; + + moveQueue.clear(); + int position = -1; + + if (information.players[0].isHuman) { + try { + position = moveQueue.take().position(); + } catch (InterruptedException _) { + } + } else { + final Move move = ai.findBestMove(game, information.players[0].computerDifficulty); + assert move != null; + position = move.position(); + } + + new EventFlow() + .addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short) position)) + .postEvent(); + } + + @Override + protected void localGameThread() { + while (isRunning.get()) { + if (isPaused.get()) { + try { + Thread.sleep(200); + } catch (InterruptedException _) {} + + continue; + } + + final int currentTurn = game.getCurrentTurn(); + setGameLabels(currentTurn == myTurn); + + Move move = null; + + if (information.players[currentTurn].isHuman) { + try { + final Move wants = moveQueue.take(); + final Move[] legalMoves = game.getLegalMoves(); + + for (final Move legalMove : legalMoves) { + if (legalMove.position() == wants.position() && + legalMove.value() == wants.value()) { + move = wants; + break; + } + } + } catch (InterruptedException _) { + } + + } else { + long start = System.currentTimeMillis(); + move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty); + + if (information.players[currentTurn].computerThinkTime > 0) { + long elapsed = System.currentTimeMillis() - start; + long sleep = information.players[currentTurn].computerThinkTime * 1000L - elapsed; + + try { + Thread.sleep((long) (sleep * Math.random())); + } catch (InterruptedException _) { + } + } + } + + if (move == null) continue; + + GameState state = game.play(move); + updateCanvas(true); + + if (state != GameState.NORMAL) { + if (state == GameState.WIN) { + primary.gameOver(information.players[currentTurn].isHuman, + information.players[currentTurn].name); + } else if (state == GameState.DRAW) { + primary.gameOver(false, ""); + } + + isRunning.set(false); + } + } + } + + private void updateCanvas(boolean animate) { + canvas.clearAll(); + + for (int i = 0; i < game.getBoard().length; i++) { + char c = game.getBoard()[i]; + if (c == 'B') canvas.drawDot(Color.BLACK, i); + else if (c == 'W') canvas.drawDot(Color.WHITE, i); + } + + final Move[] flipped = game.getMostRecentlyFlippedPieces(); + + final SequentialTransition anim = new SequentialTransition(); + isPaused.set(true); + + final Color from = game.getCurrentPlayer() == 'W' ? Color.WHITE : Color.BLACK; + final Color to = game.getCurrentPlayer() == 'W' ? Color.BLACK : Color.WHITE; + + if (animate && flipped != null) { + for (final Move flip : flipped) { + canvas.clear(flip.position()); + canvas.drawDot(from, flip.position()); + anim.getChildren().addFirst(canvas.flipDot(from, to, flip.position())); + } + } + + anim.setOnFinished(_ -> { + isPaused.set(false); + + for (final Move m : game.getLegalMoves()) { + canvas.drawLegalPosition(m.position(), game.getCurrentPlayer()); + } + }); + + anim.play(); + } + + private void highlightCells(int cell) { + Move[] legal = game.getLegalMoves(); + boolean isLegal = false; + + for (Move m : legal) { + if (m.position() == cell) { + isLegal = true; + break; + } + } + + if (cell >= 0) { + Move[] flips = null; + + if (isLegal) { + flips = game.getFlipsForPotentialMove( + new Point(cell % game.getColumnSize(), cell / game.getRowSize()), + game.getCurrentPlayer() + ); + } + + canvas.drawHighlightDots(flips); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/game/TicTacToeGame.java b/app/src/main/java/org/toop/app/game/TicTacToeGame.java deleted file mode 100644 index 84fc237..0000000 --- a/app/src/main/java/org/toop/app/game/TicTacToeGame.java +++ /dev/null @@ -1,250 +0,0 @@ -package org.toop.app.game; - -import org.toop.app.App; -import org.toop.app.GameInformation; -import org.toop.app.canvas.TicTacToeCanvas; -import org.toop.app.widget.WidgetContainer; -import org.toop.app.widget.view.GameView; -import org.toop.framework.eventbus.EventFlow; -import org.toop.framework.networking.events.NetworkEvents; -import org.toop.game.enumerators.GameState; -import org.toop.game.records.Move; -import org.toop.game.tictactoe.TicTacToe; -import org.toop.game.tictactoe.TicTacToeAI; - -import javafx.geometry.Pos; -import javafx.scene.paint.Color; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -public final class TicTacToeGame { - private final GameInformation information; - - private final int myTurn; - private Runnable onGameOver; - private final BlockingQueue moveQueue; - - private final TicTacToe game; - private final TicTacToeAI ai; - - private final GameView primary; - private final TicTacToeCanvas canvas; - - private final AtomicBoolean isRunning; - - public TicTacToeGame(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer onMessage, Runnable onGameOver) { - this.information = information; - - this.myTurn = myTurn; - this.onGameOver = onGameOver; - moveQueue = new LinkedBlockingQueue(); - - game = new TicTacToe(); - ai = new TicTacToeAI(); - - isRunning = new AtomicBoolean(true); - - if (onForfeit == null || onExit == null) { - primary = new GameView(null, () -> { - isRunning.set(false); - WidgetContainer.getCurrentView().transitionPrevious(); - }, null); - } else { - primary = new GameView(onForfeit, () -> { - isRunning.set(false); - onExit.run(); - }, onMessage); - } - - canvas = new TicTacToeCanvas(Color.GRAY, - (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, - (cell) -> { - if (onForfeit == null || onExit == null) { - if (information.players[game.getCurrentTurn()].isHuman) { - final char value = game.getCurrentTurn() == 0? 'X' : 'O'; - - try { - moveQueue.put(new Move(cell, value)); - } catch (InterruptedException _) {} - } - } else { - if (information.players[0].isHuman) { - final char value = myTurn == 0? 'X' : 'O'; - - try { - moveQueue.put(new Move(cell, value)); - } catch (InterruptedException _) {} - } - } - }); - - primary.add(Pos.CENTER, canvas.getCanvas()); - WidgetContainer.getCurrentView().transitionNext(primary); - - if (onForfeit == null || onExit == null) { - new Thread(this::localGameThread).start(); - } else { - new EventFlow() - .listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse) - .listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse); - - setGameLabels(myTurn == 0); - } - } - - public TicTacToeGame(GameInformation information) { - this(information, 0, null, null, null, null); - } - - private void localGameThread() { - while (isRunning.get()) { - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "X" : "O"; - final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount(); - - primary.nextPlayer(information.players[currentTurn].isHuman, - information.players[currentTurn].name, - currentValue, - information.players[nextTurn].name); - - Move move = null; - - if (information.players[currentTurn].isHuman) { - try { - final Move wants = moveQueue.take(); - final Move[] legalMoves = game.getLegalMoves(); - - for (final Move legalMove : legalMoves) { - if (legalMove.position() == wants.position() && - legalMove.value() == wants.value()) { - move = wants; - break; - } - } - } catch (InterruptedException _) {} - } else { - final long start = System.currentTimeMillis(); - - move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty); - - if (information.players[currentTurn].computerThinkTime > 0) { - final long elapsedTime = System.currentTimeMillis() - start; - final long sleepTime = information.players[currentTurn].computerThinkTime * 1000L - elapsedTime; - - try { - Thread.sleep((long)(sleepTime * Math.random())); - } catch (InterruptedException _) {} - } - } - - if (move == null) { - continue; - } - - final GameState state = game.play(move); - - if (move.value() == 'X') { - canvas.drawX(Color.INDIANRED, move.position()); - } else if (move.value() == 'O') { - canvas.drawO(Color.ROYALBLUE, move.position()); - } - - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - primary.gameOver(true, information.players[currentTurn].name); - } else if (state == GameState.DRAW) { - primary.gameOver(false, ""); - } - - isRunning.set(false); - } - } - } - - private void onMoveResponse(NetworkEvents.GameMoveResponse response) { - if (!isRunning.get()) { - return; - } - - char playerChar; - - if (response.player().equalsIgnoreCase(information.players[0].name)) { - playerChar = myTurn == 0? 'X' : 'O'; - } else { - playerChar = myTurn == 0? 'O' : 'X'; - } - - final Move move = new Move(Integer.parseInt(response.move()), playerChar); - final GameState state = game.play(move); - - if (state != GameState.NORMAL) { - if (state == GameState.WIN) { - if (response.player().equalsIgnoreCase(information.players[0].name)) { - primary.gameOver(true, information.players[0].name); - gameOver(); - } else { - primary.gameOver(false, information.players[1].name); - gameOver(); - } - } else if (state == GameState.DRAW) { - if(game.getLegalMoves().length == 0) { //only return draw in online multiplayer if the game is actually over. - primary.gameOver(false, ""); - gameOver(); - } - } - } - - if (move.value() == 'X') { - canvas.drawX(Color.RED, move.position()); - } else if (move.value() == 'O') { - canvas.drawO(Color.BLUE, move.position()); - } - - setGameLabels(game.getCurrentTurn() == myTurn); - } - - private void gameOver() { - if (onGameOver == null){ - return; - } - isRunning.set(false); - onGameOver.run(); - } - - private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) { - if (!isRunning.get()) { - return; - } - - moveQueue.clear(); - - int position = -1; - - if (information.players[0].isHuman) { - try { - position = moveQueue.take().position(); - } catch (InterruptedException _) {} - } else { - final Move move; - move = ai.findBestMove(game, information.players[0].computerDifficulty); - assert move != null; - position = move.position(); - } - - new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short)position)) - .postEvent(); - } - - private void setGameLabels(boolean isMe) { - final int currentTurn = game.getCurrentTurn(); - final String currentValue = currentTurn == 0? "X" : "O"; - - primary.nextPlayer(isMe, - information.players[isMe? 0 : 1].name, - currentValue, - information.players[isMe? 1 : 0].name); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/game/TicTacToeGameThread.java b/app/src/main/java/org/toop/app/game/TicTacToeGameThread.java index a71bf07..cf0db79 100644 --- a/app/src/main/java/org/toop/app/game/TicTacToeGameThread.java +++ b/app/src/main/java/org/toop/app/game/TicTacToeGameThread.java @@ -1,19 +1,19 @@ package org.toop.app.game; +import javafx.geometry.Pos; +import javafx.scene.paint.Color; import org.toop.app.App; import org.toop.app.GameInformation; import org.toop.app.canvas.TicTacToeCanvas; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.networking.events.NetworkEvents; -import org.toop.game.Game; +import org.toop.game.enumerators.GameState; +import org.toop.game.records.Move; import org.toop.game.tictactoe.TicTacToe; import org.toop.game.tictactoe.TicTacToeAI; import java.util.function.Consumer; -import javafx.geometry.Pos; -import javafx.scene.paint.Color; - public final class TicTacToeGameThread extends BaseGameThread { public TicTacToeGameThread(GameInformation info, int myTurn, Runnable onForfeit, Runnable onExit, Consumer onMessage, Runnable onGameOver) { super(info, myTurn, onForfeit, onExit, onMessage, onGameOver, @@ -47,7 +47,7 @@ public final class TicTacToeGameThread extends BaseGameThread nodeMap; - - protected View(boolean mainView, String cssClass) { - this.mainView = mainView; - - view = new StackPane(); - view.getStyleClass().add(cssClass); - - nodeMap = new HashMap(); - } - - public void add(Pos position, Node node) { - assert node != null; - - StackPane.setAlignment(node, position); - view.getChildren().add(node); - } - - protected Region hspacer() { - final Region hspacer = new Region(); - hspacer.getStyleClass().add("hspacer"); - - return hspacer; - } - - protected Region vspacer() { - final Region vspacer = new Region(); - vspacer.getStyleClass().add("vspacer"); - - return vspacer; - } - - protected ScrollPane fit(String identifier, String cssClass, Node node) { - assert node != null; - - final ScrollPane fit = new ScrollPane(node); - fit.getStyleClass().add(cssClass); - - fit.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); - fit.setFitToWidth(true); - fit.setFitToHeight(true); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, fit); - } - - return fit; - } - - protected ScrollPane fit(String identifier, Node node) { - return fit(identifier, "fit", node); - } - - protected ScrollPane fit(Node node) { - return fit("", node); - } - - protected HBox hbox(String identifier, String cssClass, Node... nodes) { - assert !nodeMap.containsKey(identifier); - - final HBox hbox = new HBox(); - hbox.getStyleClass().add(cssClass); - hbox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); - - for (final Node node : nodes) { - if (node != null) { - hbox.getChildren().add(node); - } - } - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, hbox); - } - - return hbox; - } - - protected HBox hbox(String identifier, Node... nodes) { - return hbox(identifier, "container", nodes); - } - - protected HBox hbox(Node... nodes) { - return hbox("", nodes); - } - - protected HBox hboxFill(String identifier, String cssClass, Node... nodes) { - final HBox hbox = hbox(identifier, cssClass, nodes); - - for (final Node node : hbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxHeight(Double.MAX_VALUE); - } - } - - return hbox; - } - - protected HBox hboxFill(String identifier, Node... nodes) { - final HBox hbox = hbox(identifier, nodes); - - for (final Node node : hbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxHeight(Double.MAX_VALUE); - } - } - - return hbox; - } - - protected HBox hboxFill(Node... nodes) { - final HBox hbox = hbox(nodes); - - for (final Node node : hbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxHeight(Double.MAX_VALUE); - } - } - - return hbox; - } - - protected VBox vbox(String identifier, String cssClass, Node... nodes) { - assert !nodeMap.containsKey(identifier); - - final VBox vbox = new VBox(); - vbox.getStyleClass().add(cssClass); - vbox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); - - for (final Node node : nodes) { - if (node != null) { - vbox.getChildren().add(node); - } - } - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, vbox); - } - - return vbox; - } - - protected VBox vbox(String identifier, Node... nodes) { - return vbox(identifier, "container", nodes); - } - - protected VBox vbox(Node... nodes) { - return vbox("", nodes); - } - - protected VBox vboxFill(String identifier, String cssClass, Node... nodes) { - final VBox vbox = vbox(identifier, cssClass, nodes); - - for (final Node node : vbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxWidth(Double.MAX_VALUE); - } - } - - return vbox; - } - - protected VBox vboxFill(String identifier, Node... nodes) { - final VBox vbox = vbox(identifier, nodes); - - for (final Node node : vbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxWidth(Double.MAX_VALUE); - } - } - - return vbox; - } - - protected VBox vboxFill(Node... nodes) { - final VBox vbox = vbox(nodes); - - for (final Node node : vbox.getChildren()) { - if (node instanceof Region) { - ((Region)node).setMaxWidth(Double.MAX_VALUE); - } - } - - return vbox; - } - - protected Separator separator(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final Separator separator = new Separator(); - separator.getStyleClass().add(cssClass); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, separator); - } - - return separator; - } - - protected Separator separator(String identifier) { - return separator(identifier, "separator"); - } - - protected Separator separator() { - return separator(""); - } - - protected Text header(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final Text header = new Text(); - header.getStyleClass().add(cssClass); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, header); - } - - return header; - } - - protected Text header(String identifier) { - return header(identifier, "header"); - } - - protected Text header() { - return header(""); - } - - protected Text text(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final Text text = new Text(); - text.getStyleClass().add(cssClass); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, text); - } - - return text; - } - - protected Text text(String identifier) { - return text(identifier, "text"); - } - - protected Text text() { - return text(""); - } - - protected Button button(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final Button button = new Button(); - button.getStyleClass().add(cssClass); - - button.setOnMouseClicked(_ -> { - new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent(); - }); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, button); - } - - return button; - } - - protected Button button(String identifier) { - return button(identifier, "button"); - } - - protected Button button() { - return button(""); - } - - protected Slider slider(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final Slider slider = new Slider(); - slider.getStyleClass().add(cssClass); - - slider.setMinorTickCount(0); - slider.setMajorTickUnit(1); - slider.setBlockIncrement(1); - - slider.setSnapToTicks(true); - slider.setShowTickLabels(true); - - slider.setOnMouseClicked(_ -> { - new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent(); - }); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, slider); - } - - return slider; - } - - protected Slider slider(String identifier) { - return slider(identifier, "slider"); - } - - protected Slider slider() { - return slider(""); - } - - protected TextField input(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final TextField input = new TextField(); - input.getStyleClass().add(cssClass); - - input.setOnMouseClicked(_ -> { - new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent(); - }); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, input); - } - - return input; - } - - protected TextField input(String identifier) { - return input(identifier, "input"); - } - - protected TextField input() { - return input(""); - } - - protected ComboBox combobox(String identifier, String cssClass) { - assert !nodeMap.containsKey(identifier); - - final ComboBox combobox = new ComboBox(); - combobox.getStyleClass().add(cssClass); - - combobox.setOnMouseClicked(_ -> { - new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent(); - }); - - if (!identifier.isEmpty()) { - nodeMap.put(identifier, combobox); - } - - return combobox; - } - - protected ComboBox combobox(String identifier) { - return combobox(identifier, "combo-box"); - } - - protected ComboBox combobox() { - return combobox(""); - } - - @SuppressWarnings("unchecked") - protected T get(String identifier) { - assert nodeMap.containsKey(identifier); - return (T) nodeMap.get(identifier); - } - - protected void clear() { - view.getChildren().clear(); - nodeMap.clear(); - } - - public boolean isMainView() { return mainView; } - public Region getView() { return view; } - - public abstract void setup(); - public void cleanup() { - clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/ViewStack.java b/app/src/main/java/org/toop/app/view/ViewStack.java deleted file mode 100644 index 20d0ff3..0000000 --- a/app/src/main/java/org/toop/app/view/ViewStack.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.toop.app.view; - -import javafx.application.Platform; -import javafx.scene.Scene; -import javafx.scene.layout.StackPane; - -import java.util.Stack; - -public final class ViewStack { - private static boolean setup = false; - - private static StackPane root; - - private static View active; - private static Stack stack; - - public static void setup(Scene scene) { - assert scene != null; - - if (setup) { - return; - } - - root = new StackPane(); - - active = null; - stack = new Stack(); - - scene.setRoot(root); - - setup = true; - } - - public static void cleanup() { - assert setup; - - final var count = stack.size(); - - for (int i = 0; i < count; i++) { - pop(); - } - - if (active != null) { - active.cleanup(); - } - - setup = false; - } - - public static void reload() { - assert setup; - - for (final var view : stack) { - view.cleanup(); - } - - if (active != null) { - active.cleanup(); - active.setup(); - } - - for (final var view : stack) { - view.setup(); - } - } - - public static void push(View view) { - assert setup; - assert view != null; - - if (view.isMainView()) { - Platform.runLater(() -> { - if (active != null) { - root.getChildren().removeFirst(); - active.cleanup(); - } - - root.getChildren().addFirst(view.getView()); - view.setup(); - - active = view; - }); - } else { - Platform.runLater(() -> { - stack.push(view); - root.getChildren().addLast(view.getView()); - view.setup(); - }); - } - } - - public static void pop() { - assert setup; - - if (stack.isEmpty()) { - return; - } - - Platform.runLater(() -> { - final var last = stack.pop(); - root.getChildren().removeLast(); - last.cleanup(); - }); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/displays/SongDisplay.java b/app/src/main/java/org/toop/app/view/displays/SongDisplay.java deleted file mode 100644 index f21e2aa..0000000 --- a/app/src/main/java/org/toop/app/view/displays/SongDisplay.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.toop.app.view.displays; - -import javafx.application.Platform; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ProgressBar; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; -import org.toop.app.widget.Widget; -import org.toop.framework.audio.AudioEventListener; -import org.toop.framework.audio.events.AudioEvents; -import org.toop.framework.eventbus.EventFlow; -import javafx.geometry.Pos; -import javafx.scene.text.Text; -import org.toop.framework.eventbus.GlobalEventBus; - -public class SongDisplay extends VBox implements Widget { - - private final Text songTitle; - private final ProgressBar progressBar; - private final Text progressText; - private boolean paused = false; - - public SongDisplay() { - new EventFlow() - .listen(this::updateTheSong); - - setAlignment(Pos.CENTER); - getStyleClass().add("song-display"); - - songTitle = new Text("song playing"); - songTitle.getStyleClass().add("song-title"); - - progressBar = new ProgressBar(0); - progressBar.getStyleClass().add("progress-bar"); - - progressText = new Text("0:00/0:00"); - progressText.getStyleClass().add("progress-text"); - - Button skipButton = new Button(">>"); - Button pauseButton = new Button("⏸"); - Button previousButton = new Button("<<"); - - skipButton.getStyleClass().setAll("skip-button"); - pauseButton.getStyleClass().setAll("pause-button"); - previousButton.getStyleClass().setAll("previous-button"); - - skipButton.setOnAction( event -> { - GlobalEventBus.post(new AudioEvents.SkipMusic()); - paused = false; - pauseButton.setText(getPlayString(paused)); - }); - - pauseButton.setOnAction(event -> { - GlobalEventBus.post(new AudioEvents.PauseMusic()); - paused = !paused; - pauseButton.setText(getPlayString(paused)); - }); - - previousButton.setOnAction( event -> { - GlobalEventBus.post(new AudioEvents.PreviousMusic()); - paused = false; - pauseButton.setText(getPlayString(paused)); - }); - - HBox control = new HBox(10, previousButton, pauseButton, skipButton); - control.setAlignment(Pos.CENTER); - control.getStyleClass().add("controls"); - - getChildren().addAll(songTitle, progressBar, progressText, control); - } - - private void updateTheSong(AudioEvents.PlayingMusic event) { - Platform.runLater(() -> { - String text = event.name(); - text = text.substring(0, text.length() - 4); - songTitle.setText(text); - double currentPos = event.currentPosition(); - double duration = event.duration(); - if (currentPos / duration > 0.05) { - double progress = currentPos / duration; - progressBar.setProgress(progress); - } - else if (currentPos / duration < 0.05) { - progressBar.setProgress(0.05); - } - progressText.setText(getTimeString(event.currentPosition(), event.duration())); - }); - } - - private String getTimeString(long position, long duration) { - long positionMinutes = position / 60; - long durationMinutes = duration / 60; - long positionSeconds = position % 60; - long durationSeconds = duration % 60; - String positionSecondsStr = String.valueOf(positionSeconds); - String durationSecondsStr = String.valueOf(durationSeconds); - - if (positionSeconds < 10) { - positionSecondsStr = "0" + positionSeconds; - } - if (durationSeconds < 10) { - durationSecondsStr = "0" + durationSeconds; - } - - String time = positionMinutes + ":" + positionSecondsStr + " / " + durationMinutes + ":" + durationSecondsStr; - return time; - } - - private String getPlayString(boolean paused) { - if (paused) { - return "▶"; - } - else { - return "⏸"; - } - } - - @Override - public Node getNode() { - return this; - } -} - - - - - diff --git a/app/src/main/java/org/toop/app/view/views/ChallengeView.java b/app/src/main/java/org/toop/app/view/views/ChallengeView.java deleted file mode 100644 index 36184f6..0000000 --- a/app/src/main/java/org/toop/app/view/views/ChallengeView.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.GameInformation; -import org.toop.app.Server; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Slider; -import javafx.scene.text.Text; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -public final class ChallengeView extends View { - private final GameInformation.Player playerInformation; - - private final String challenger; - private final String game; - - private final Consumer onAccept; - - public ChallengeView(String challenger, String game, Consumer onAccept) { - super(false, "bg-popup"); - - playerInformation = new GameInformation.Player(); - - this.challenger = challenger; - this.game = game; - - this.onAccept = onAccept; - } - - @Override - public void setup() { - final Text challengeText = text(); - challengeText.setText(AppContext.getString("you-were-challenged-by")); - - final Text challengerHeader = header(); - challengerHeader.setText(challenger); - - final Text gameText = text(); - gameText.setText(AppContext.getString("to-a-game-of") + " " + game); - - final Button acceptButton = button(); - acceptButton.setText(AppContext.getString("accept")); - acceptButton.setOnAction(_ -> { - onAccept.accept(playerInformation); - }); - - final Button denyButton = button(); - denyButton.setText(AppContext.getString("deny")); - denyButton.setOnAction(_ -> { - ViewStack.pop(); - }); - - final List nodes = new ArrayList<>(); - - if (playerInformation.isHuman) { - final Button playerToggle = button(); - playerToggle.setText(AppContext.getString("player")); - playerToggle.setOnAction(_ -> { - playerInformation.isHuman = false; - cleanup(); - setup(); - }); - - nodes.add(vbox(playerToggle)); - } else { - final Button computerToggle = button(); - computerToggle.setText(AppContext.getString("computer")); - computerToggle.setOnAction(_ -> { - playerInformation.isHuman = true; - cleanup(); - setup(); - }); - - nodes.add(vbox(computerToggle)); - - final Text computerDifficultyText = text(); - computerDifficultyText.setText(AppContext.getString("computer-difficulty")); - - final Slider computerDifficultySlider = slider(); - computerDifficultySlider.setMin(0); - computerDifficultySlider.setMax(Server.gameToType(game).getMaxDepth()); - computerDifficultySlider.setValue(playerInformation.computerDifficulty); - computerDifficultySlider.valueProperty().addListener((_, _, newValue) -> { - playerInformation.computerDifficulty = newValue.intValue(); - }); - - nodes.add(vbox(computerDifficultyText, computerDifficultySlider)); - } - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.CENTER, - fit(hboxFill( - vboxFill( - challengeText, - challengerHeader, - gameText, - separator(), - - hboxFill( - acceptButton, - denyButton - ) - ), - - vboxFill( - nodes.toArray(new Node[0]) - ) - )) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/CreditsView.java b/app/src/main/java/org/toop/app/view/views/CreditsView.java deleted file mode 100644 index 3f02ef8..0000000 --- a/app/src/main/java/org/toop/app/view/views/CreditsView.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.App; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.control.ScrollPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import javafx.util.Duration; - -public final class CreditsView extends View { - public CreditsView() { - super(false, "bg-primary"); - } - - @Override - public void setup() { - final Text scrumMasterHeader = header(); - scrumMasterHeader.setText(AppContext.getString("scrum-master") + ": Stef"); - - final Text productOwnerHeader = header(); - productOwnerHeader.setText(AppContext.getString("product-owner") + ": Omar"); - - final Text mergeCommanderHeader = header(); - mergeCommanderHeader.setText(AppContext.getString("merge-commander") + ": Bas"); - - final Text localizationHeader = header(); - localizationHeader.setText(AppContext.getString("localization") + ": Ticho"); - - final Text aiHeader = header(); - aiHeader.setText(AppContext.getString("ai") + ": Michiel"); - - final Text developersHeader = header(); - developersHeader.setText(AppContext.getString("developers") + ": Michiel, Bas, Stef, Omar, Ticho"); - - final Text moralSupportHeader = header(); - moralSupportHeader.setText(AppContext.getString("moral-support") + ": Wesley"); - - final Text openglHeader = header(); - openglHeader.setText(AppContext.getString("opengl") + ": Omar"); - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.CENTER, - fit("credits-fit", vboxFill("credits-container", "credits-container", - vbox("credits-spacer-top", ""), - - scrumMasterHeader, - productOwnerHeader, - mergeCommanderHeader, - localizationHeader, - aiHeader, - developersHeader, - moralSupportHeader, - openglHeader, - - vbox("credits-spacer-bottom", "") - )) - ); - - final Button backButton = button(); - backButton.setText(AppContext.getString("back")); - backButton.setOnAction(_ -> { ViewStack.pop(); }); - - add(Pos.BOTTOM_LEFT, - vboxFill( - backButton - ) - ); - - playCredits(100, 20); - } - - private void playCredits(int lineHeight, int length) { - final ScrollPane creditsFit = get("credits-fit"); - creditsFit.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - creditsFit.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - - final VBox creditsContainer = get("credits-container"); - creditsContainer.setSpacing(lineHeight); - - final VBox creditsSpacerTop = get("credits-spacer-top"); - creditsSpacerTop.setMinHeight(App.getHeight() - lineHeight); - - final VBox creditsSpacerBottom = get("credits-spacer-bottom"); - creditsSpacerBottom.setMinHeight(App.getHeight() - lineHeight); - - final Timeline timeline = new Timeline( - new KeyFrame(Duration.seconds(0), new KeyValue(creditsFit.vvalueProperty(), 0.0)), - new KeyFrame(Duration.seconds(length), new KeyValue(creditsFit.vvalueProperty(), 1.0)) - ); - - timeline.setCycleCount(Timeline.INDEFINITE); - timeline.play(); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/ErrorView.java b/app/src/main/java/org/toop/app/view/views/ErrorView.java deleted file mode 100644 index 5dc85fa..0000000 --- a/app/src/main/java/org/toop/app/view/views/ErrorView.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.text.Text; - -public final class ErrorView extends View { - private final String error; - - public ErrorView(String error) { - super(false, "bg-popup"); - this.error = error; - } - - @Override - public void setup() { - final Text errorHeader = header(); - errorHeader.setText(AppContext.getString("error")); - - final Text errorText = text(); - errorText.setText(error); - - final Button okButton = button(); - okButton.setText(AppContext.getString("ok")); - okButton.setOnAction(_ -> { ViewStack.pop(); }); - - add(Pos.CENTER, - vboxFill( - errorHeader, - separator(), - - vspacer(), - errorText, - vspacer(), - - separator(), - okButton - ) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/GameView.java b/app/src/main/java/org/toop/app/view/views/GameView.java deleted file mode 100644 index df69240..0000000 --- a/app/src/main/java/org/toop/app/view/views/GameView.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.toop.app.view.views; - -import javafx.application.Platform; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.control.TextField; -import javafx.scene.text.Text; - -import java.util.function.Consumer; - -public final class GameView extends View { - private static class GameOverView extends View { - private final boolean iWon; - private final String winner; - - public GameOverView(boolean iWon, String winner) { - super(false, "bg-popup"); - - this.iWon = iWon; - this.winner = winner; - } - - @Override - public void setup() { - final Text gameOverHeader = header(); - gameOverHeader.setText(AppContext.getString("game-over")); - - final Button okButton = button(); - okButton.setText(AppContext.getString("ok")); - okButton.setOnAction(_ -> { ViewStack.pop(); }); - - Text gameOverText = text(); - - if (winner.isEmpty()) { - gameOverText.setText(AppContext.getString("the-game-ended-in-a-draw")); - } else { - if (iWon) { - gameOverText.setText(AppContext.getString("you-win") + " " + winner); - } else { - gameOverText.setText(AppContext.getString("you-lost-against") + " " + winner); - } - } - - add(Pos.CENTER, - fit(vboxFill( - gameOverHeader, - separator(), - - vspacer(), - gameOverText, - vspacer(), - - separator(), - okButton - )) - ); - } - } - - private final Button forfeitButton; - private final Button exitButton; - - private final Text currentPlayerHeader; - private final Text currentMoveHeader; - - private final Text nextPlayerHeader; - - private final ListView chatListView; - private final TextField chatInput; - - public GameView(Runnable onForfeit, Runnable onExit, Consumer onMessage) { - assert onExit != null; - - super(true, "bg-primary"); - - if (onForfeit != null) { - forfeitButton = button(); - forfeitButton.setText(AppContext.getString("forfeit")); - forfeitButton.setOnAction(_ -> onForfeit.run()); - } else { - forfeitButton = null; - } - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - if (onMessage != null) { - chatListView = new ListView(); - - chatInput = input(); - chatInput.setOnAction(_ -> { - onMessage.accept(chatInput.getText()); - chatInput.setText(""); - }); - } else { - chatListView = null; - chatInput = null; - } - - exitButton = button(); - exitButton.setText(AppContext.getString("exit")); - exitButton.setOnAction(_ -> onExit.run()); - - currentPlayerHeader = header("", "current-player"); - currentMoveHeader = header(); - - nextPlayerHeader = header(); - } - - @Override - public void setup() { - add(Pos.TOP_RIGHT, - fit(vboxFill( - currentPlayerHeader, - - hboxFill( - separator(), - currentMoveHeader, - separator() - ), - - nextPlayerHeader - )) - ); - - add(Pos.BOTTOM_LEFT, - vboxFill( - forfeitButton, - exitButton - ) - ); - - if (chatListView != null) { - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - chatListView, - chatInput - ) - )); - } - } - - public void nextPlayer(boolean isMe, String currentPlayer, String currentMove, String nextPlayer) { - Platform.runLater(() -> { - currentPlayerHeader.setText(currentPlayer); - currentMoveHeader.setText(currentMove); - - nextPlayerHeader.setText(nextPlayer); - - if (isMe) { - currentPlayerHeader.getStyleClass().add("my-turn"); - } else { - currentPlayerHeader.getStyleClass().remove("my-turn"); - } - }); - - } - - public void updateChat(String message) { - if (chatListView == null) { - return; - } - - final Text messageText = text(); - messageText.setText(message); - - chatListView.getItems().add(messageText); - } - - public void gameOver(boolean iWon, String winner) { - ViewStack.push(new GameOverView(iWon, winner)); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/LocalMultiplayerView.java b/app/src/main/java/org/toop/app/view/views/LocalMultiplayerView.java deleted file mode 100644 index c44d784..0000000 --- a/app/src/main/java/org/toop/app/view/views/LocalMultiplayerView.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.GameInformation; -import org.toop.app.game.Connect4Game; -import org.toop.app.game.ReversiGame; -import org.toop.app.game.TicTacToeGameThread; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Slider; -import javafx.scene.control.TextField; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; - -import java.util.ArrayList; -import java.util.List; - -public final class LocalMultiplayerView extends View { - private final GameInformation information; - - public LocalMultiplayerView(GameInformation information) { - super(true, "bg-primary"); - this.information = information; - } - - public LocalMultiplayerView(GameInformation.Type type) { - this(new GameInformation(type)); - } - - @Override - public void setup() { - final Button playButton = button(); - playButton.setText(AppContext.getString("play")); - playButton.setOnAction(_ -> { - for (final GameInformation.Player player : information.players) { - if (player.name.isEmpty()) { - ViewStack.push(new ErrorView(AppContext.getString("please-enter-your-name"))); - return; - } - } - - switch (information.type) { - case TICTACTOE: new TicTacToeGameThread(information); break; - case REVERSI: new ReversiGame(information); break; - case CONNECT4: new Connect4Game(information); break; - // case BATTLESHIP: new BattleshipGame(information); break; - } - }); - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.CENTER, - fit(vboxFill( - hbox( - setupPlayers() - ), - - separator(), - playButton - )) - ); - - final Button backButton = button(); - backButton.setText(AppContext.getString("back")); - backButton.setOnAction(_ -> { ViewStack.push(new MainView()); }); - - add(Pos.BOTTOM_LEFT, - vboxFill( - backButton - ) - ); - } - - private VBox[] setupPlayers() { - final VBox[] playerBoxes = new VBox[information.type.getPlayerCount()]; - - for (int i = 0; i < playerBoxes.length; i++) { - final int index = i; - - List nodes = new ArrayList<>(); - - final Text playerHeader = header(); - playerHeader.setText(AppContext.getString("player") + " #" + (i + 1)); - - nodes.add(playerHeader); - nodes.add(separator()); - - final Text nameText = text(); - nameText.setText(AppContext.getString("name")); - - if (information.players[i].isHuman) { - final Button playerToggle = button(); - playerToggle.setText(AppContext.getString("player")); - playerToggle.setOnAction(_ -> { - information.players[index].isHuman = false; - cleanup(); - setup(); - }); - - nodes.add(vboxFill(playerToggle)); - - final TextField playerNameInput = input(); - playerNameInput.setPromptText(AppContext.getString("enter-your-name")); - playerNameInput.setText(information.players[i].name); - playerNameInput.textProperty().addListener((_, _, newValue) -> { - information.players[index].name = newValue; - }); - - nodes.add(vboxFill(nameText, playerNameInput)); - } else { - final Button computerToggle = button(); - computerToggle.setText(AppContext.getString("computer")); - computerToggle.setOnAction(_ -> { - information.players[index].isHuman = true; - cleanup(); - setup(); - }); - - nodes.add(vboxFill(computerToggle)); - - information.players[i].name = "Pism Bot V" + i; - - final Text computerNameText = text(); - computerNameText.setText(information.players[index].name); - - nodes.add(vboxFill(nameText, computerNameText)); - - final Text computerDifficultyText = text(); - computerDifficultyText.setText(AppContext.getString("computer-difficulty")); - - final Slider computerDifficultySlider = slider(); - computerDifficultySlider.setMin(0); - computerDifficultySlider.setMax(information.type.getMaxDepth()); - computerDifficultySlider.setValue(information.players[i].computerDifficulty); - computerDifficultySlider.valueProperty().addListener((_, _, newValue) -> { - information.players[index].computerDifficulty = newValue.intValue(); - }); - - nodes.add(vboxFill(computerDifficultyText, computerDifficultySlider)); - - final Text computerThinkTimeText = text(); - computerThinkTimeText.setText(AppContext.getString("computer-think-time")); - - final Slider computerThinkTimeSlider = slider(); - computerThinkTimeSlider.setMin(0); - computerThinkTimeSlider.setMax(5); - computerThinkTimeSlider.setValue(information.players[i].computerThinkTime); - computerThinkTimeSlider.valueProperty().addListener((_, _, newValue) -> { - information.players[index].computerThinkTime = newValue.intValue(); - }); - - nodes.add(vboxFill(computerThinkTimeText, computerThinkTimeSlider)); - } - - playerBoxes[i] = vboxFill(nodes.toArray(new Node[0])); - } - - return playerBoxes; - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/LocalView.java b/app/src/main/java/org/toop/app/view/views/LocalView.java deleted file mode 100644 index c4a1c4b..0000000 --- a/app/src/main/java/org/toop/app/view/views/LocalView.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.GameInformation; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; - -public final class LocalView extends View { - public LocalView() { - super(true, "bg-primary"); - } - - @Override - public void setup() { - final Button ticTacToeButton = button(); - ticTacToeButton.setText(AppContext.getString("tic-tac-toe")); - ticTacToeButton.setOnAction(_ -> { ViewStack.push(new LocalMultiplayerView(GameInformation.Type.TICTACTOE)); }); - - final Button reversiButton = button(); - reversiButton.setText(AppContext.getString("reversi")); - reversiButton.setOnAction(_ -> { ViewStack.push(new LocalMultiplayerView(GameInformation.Type.REVERSI)); }); - - final Button connect4Button = button(); - connect4Button.setText(AppContext.getString("connect4")); - connect4Button.setOnAction(_ -> { ViewStack.push(new LocalMultiplayerView(GameInformation.Type.CONNECT4)); }); - - add(Pos.CENTER, - fit(vboxFill( - ticTacToeButton, - reversiButton, - connect4Button - )) - ); - - final Button backButton = button(); - backButton.setText(AppContext.getString("back")); - backButton.setOnAction(_ -> { ViewStack.push(new MainView()); }); - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.BOTTOM_LEFT, - vboxFill( - backButton - ) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/MainView.java b/app/src/main/java/org/toop/app/view/views/MainView.java deleted file mode 100644 index 10fa0fc..0000000 --- a/app/src/main/java/org/toop/app/view/views/MainView.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.App; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.local.AppContext; -import org.toop.app.view.displays.SongDisplay; -import javafx.geometry.Pos; -import javafx.scene.control.Button; - -public final class MainView extends View { - public MainView() { - super(true, "bg-primary"); - } - - @Override - public void setup() { - final Button localButton = button(); - localButton.setText(AppContext.getString("local")); - localButton.setOnAction(_ -> { ViewStack.push(new LocalView()); }); - - final Button onlineButton = button(); - onlineButton.setText(AppContext.getString("online")); - onlineButton.setOnAction(_ -> { ViewStack.push(new OnlineView()); }); - - final Button creditsButton = button(); - creditsButton.setText(AppContext.getString("credits")); - creditsButton.setOnAction(_ -> { ViewStack.push(new CreditsView()); }); - - final Button optionsButton = button(); - optionsButton.setText(AppContext.getString("options")); - optionsButton.setOnAction(_ -> { ViewStack.push(new OptionsView()); }); - - final Button quitButton = button(); - quitButton.setText(AppContext.getString("quit")); - quitButton.setOnAction(_ -> { App.startQuit(); }); - - final SongDisplay songdisplay = new SongDisplay(); - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.CENTER, - fit(vboxFill( - localButton, - onlineButton, - creditsButton, - optionsButton, - quitButton - )) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/OnlineView.java b/app/src/main/java/org/toop/app/view/views/OnlineView.java deleted file mode 100644 index 3d7750d..0000000 --- a/app/src/main/java/org/toop/app/view/views/OnlineView.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.Server; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.control.TextField; -import javafx.scene.text.Text; - -public class OnlineView extends View { - public OnlineView() { - super(true, "bg-primary"); - } - - @Override - public void setup() { - final Text serverInformationHeader = header(); - serverInformationHeader.setText(AppContext.getString("server-information")); - - final Text serverIPText = text(); - serverIPText.setText(AppContext.getString("ip-address")); - - final TextField serverIPInput = input(); - serverIPInput.setPromptText(AppContext.getString("enter-the-server-ip")); - - final Text serverPortText = text(); - serverPortText.setText(AppContext.getString("port")); - - final TextField serverPortInput = input(); - serverPortInput.setPromptText(AppContext.getString("enter-the-server-port")); - - final Text playerNameText = text(); - playerNameText.setText(AppContext.getString("player-name")); - - final TextField playerNameInput = input(); - playerNameInput.setPromptText(AppContext.getString("enter-your-name")); - - final Button connectButton = button(); - connectButton.setText(AppContext.getString("connect")); - connectButton.setOnAction(_ -> { - new Server(serverIPInput.getText(), serverPortInput.getText(), playerNameInput.getText()); - }); - - final SongDisplay songdisplay = new SongDisplay(); - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.CENTER, - fit(vboxFill( - serverInformationHeader, - separator(), - - vboxFill( - serverIPText, - serverIPInput - ), - - vboxFill( - serverPortText, - serverPortInput - ), - - vboxFill( - playerNameText, - playerNameInput - ), - - vboxFill( - connectButton - ) - )) - ); - - final Button backButton = button(); - backButton.setText(AppContext.getString("back")); - backButton.setOnAction(_ -> { ViewStack.push(new MainView()); }); - - add(Pos.BOTTOM_LEFT, - vboxFill( - backButton - ) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/OptionsView.java b/app/src/main/java/org/toop/app/view/views/OptionsView.java deleted file mode 100644 index 08cdfa0..0000000 --- a/app/src/main/java/org/toop/app/view/views/OptionsView.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.App; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.framework.audio.VolumeControl; -import org.toop.framework.audio.events.AudioEvents; -import org.toop.framework.eventbus.EventFlow; -import org.toop.local.AppContext; -import org.toop.local.AppSettings; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Slider; -import javafx.scene.text.Text; -import javafx.util.StringConverter; - -import java.util.Locale; - -public final class OptionsView extends View { - public OptionsView() { - super(false, "bg-secondary"); - } - - @Override - public void setup() { - final Text generalHeader = header(); - generalHeader.setText(AppContext.getString("general")); - - final Text volumeHeader = header(); - volumeHeader.setText(AppContext.getString("volume")); - - final Text styleHeader = header(); - styleHeader.setText(AppContext.getString("style")); - - add(Pos.CENTER, - fit(hboxFill( - vboxFill( - generalHeader, - separator(), - - vboxFill( - text("language-text"), - combobox("language-combobox") - ), - - vboxFill( - button("fullscreen-button") - ) - ), - - vboxFill( - volumeHeader, - separator(), - - vboxFill( - text("master-volume-text"), - slider("master-volume-slider") - ), - - vboxFill( - text("effects-volume-text"), - slider("effects-volume-slider") - ), - - vboxFill( - text("music-volume-text"), - slider("music-volume-slider") - ) - ), - - vboxFill( - styleHeader, - separator(), - - vboxFill( - text("theme-text"), - combobox("theme-combobox") - ), - - vboxFill( - text("layout-text"), - combobox("layout-combobox") - ) - ) - )) - ); - - setupLanguageOption(); - setupMasterVolumeOption(); - setupEffectsVolumeOption(); - setupMusicVolumeOption(); - setupThemeOption(); - setupLayoutOption(); - setupFullscreenOption(); - - final Button backButton = button(); - backButton.setText(AppContext.getString("back")); - backButton.setOnAction(_ -> { ViewStack.pop(); }); - - final SongDisplay songdisplay = new SongDisplay(); - - - add(Pos.BOTTOM_RIGHT, - fit(vboxFill( - songdisplay - ))); - - add(Pos.BOTTOM_LEFT, - vboxFill( - backButton - ) - ); - } - - private void setupLanguageOption() { - final Text languageText = get("language-text"); - languageText.setText(AppContext.getString("language")); - - final ComboBox languageCombobox = get("language-combobox"); - languageCombobox.getItems().addAll(AppContext.getLocalization().getAvailableLocales()); - languageCombobox.setValue(AppContext.getLocale()); - - languageCombobox.getSelectionModel().selectedItemProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setLocale(newValue.toString()); - AppContext.setLocale(newValue); - }); - - languageCombobox.setConverter(new StringConverter<>() { - @Override - public String toString(Locale locale) { - return AppContext.getString(locale.getDisplayName().toLowerCase()); - } - - @Override - public Locale fromString(String s) { - return null; - } - }); - } - - private void setupMasterVolumeOption() { - final Text masterVolumeText = get("master-volume-text"); - masterVolumeText.setText(AppContext.getString("master-volume")); - - final Slider masterVolumeSlider = get("master-volume-slider"); - masterVolumeSlider.setMin(0); - masterVolumeSlider.setMax(100); - masterVolumeSlider.setValue(AppSettings.getSettings().getVolume()); - - masterVolumeSlider.valueProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setVolume(newValue.intValue()); - new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(newValue.doubleValue(), VolumeControl.MASTERVOLUME)).asyncPostEvent(); - }); - } - - private void setupEffectsVolumeOption() { - final Text effectsVolumeText = get("effects-volume-text"); - effectsVolumeText.setText(AppContext.getString("effects-volume")); - - final Slider effectsVolumeSlider = get("effects-volume-slider"); - effectsVolumeSlider.setMin(0); - effectsVolumeSlider.setMax(100); - effectsVolumeSlider.setValue(AppSettings.getSettings().getFxVolume()); - - effectsVolumeSlider.valueProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setFxVolume(newValue.intValue()); - new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(newValue.doubleValue(), VolumeControl.FX)).asyncPostEvent(); - }); - } - - private void setupMusicVolumeOption() { - final Text musicVolumeText = get("music-volume-text"); - musicVolumeText.setText(AppContext.getString("music-volume")); - - final Slider musicVolumeSlider = get("music-volume-slider"); - musicVolumeSlider.setMin(0); - musicVolumeSlider.setMax(100); - musicVolumeSlider.setValue(AppSettings.getSettings().getMusicVolume()); - - musicVolumeSlider.valueProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setMusicVolume(newValue.intValue()); - new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(newValue.doubleValue(), VolumeControl.MUSIC)).asyncPostEvent(); - }); - } - - private void setupThemeOption() { - final Text themeText = get("theme-text"); - themeText.setText(AppContext.getString("theme")); - - final ComboBox themeCombobox = get("theme-combobox"); - themeCombobox.getItems().addAll("dark", "light", "high-contrast"); - themeCombobox.setValue(AppSettings.getSettings().getTheme()); - - themeCombobox.getSelectionModel().selectedItemProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setTheme(newValue); - App.setStyle(newValue, AppSettings.getSettings().getLayoutSize()); - }); - - themeCombobox.setConverter(new StringConverter<>() { - @Override - public String toString(String theme) { - return AppContext.getString(theme); - } - - @Override - public String fromString(String s) { - return null; - } - }); - } - - private void setupLayoutOption() { - final Text layoutText = get("layout-text"); - layoutText.setText(AppContext.getString("layout-size")); - - final ComboBox layoutCombobox = get("layout-combobox"); - layoutCombobox.getItems().addAll("small", "medium", "large"); - layoutCombobox.setValue(AppSettings.getSettings().getLayoutSize()); - - layoutCombobox.getSelectionModel().selectedItemProperty().addListener((_, _, newValue) -> { - AppSettings.getSettings().setLayoutSize(newValue); - App.setStyle(AppSettings.getSettings().getTheme(), newValue); - }); - - layoutCombobox.setConverter(new StringConverter<>() { - @Override - public String toString(String layout) { - return AppContext.getString(layout); - } - - @Override - public String fromString(String s) { - return null; - } - }); - } - - private void setupFullscreenOption() { - final Button fullscreenButton = get("fullscreen-button"); - - if (AppSettings.getSettings().getFullscreen()) { - fullscreenButton.setText(AppContext.getString("windowed")); - fullscreenButton.setOnAction(_ -> { - AppSettings.getSettings().setFullscreen(false); - App.setFullscreen(false); - }); - } else { - fullscreenButton.setText(AppContext.getString("fullscreen")); - fullscreenButton.setOnAction(_ -> { - AppSettings.getSettings().setFullscreen(true); - App.setFullscreen(true); - }); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/QuitView.java b/app/src/main/java/org/toop/app/view/views/QuitView.java deleted file mode 100644 index c2f37eb..0000000 --- a/app/src/main/java/org/toop/app/view/views/QuitView.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.App; -import org.toop.app.view.View; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.text.Text; - -public final class QuitView extends View { - public QuitView() { - super(false, "bg-popup"); - } - - @Override - public void setup() { - final Text sureHeader = header(); - sureHeader.setText(AppContext.getString("are-you-sure")); - - final Button yesButton = button(); - yesButton.setText(AppContext.getString("yes")); - yesButton.setOnAction(_ -> { App.quit(); }); - - final Button noButton = button(); - noButton.setText(AppContext.getString("no")); - noButton.setOnAction(_ -> { App.stopQuit(); }); - - add(Pos.CENTER, - fit(vbox( - sureHeader, - - hbox( - yesButton, - noButton - ) - )) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/SendChallengeView.java b/app/src/main/java/org/toop/app/view/views/SendChallengeView.java deleted file mode 100644 index d72560c..0000000 --- a/app/src/main/java/org/toop/app/view/views/SendChallengeView.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.GameInformation; -import org.toop.app.Server; -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.local.AppContext; - -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Slider; -import javafx.scene.text.Text; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiConsumer; - -public final class SendChallengeView extends View { - private final Server server; - private final String opponent; - private final BiConsumer onSend; - - private final GameInformation.Player playerInformation; - - public SendChallengeView(Server server, String opponent, BiConsumer onSend) { - super(false, "bg-popup"); - - this.server = server; - this.opponent = opponent; - this.onSend = onSend; - - playerInformation = new GameInformation.Player(); - } - - @Override - public void setup() { - final Text challengeText = text(); - challengeText.setText(AppContext.getString("challenge")); - - final Text opponentHeader = header(); - opponentHeader.setText(opponent); - - final Text gameText = text(); - gameText.setText(AppContext.getString("to-a-game-of")); - - final ComboBox gamesCombobox = combobox(); - gamesCombobox.getItems().addAll(server.getGameList()); - gamesCombobox.setValue(gamesCombobox.getItems().getFirst()); - - final Button sendButton = button(); - sendButton.setText(AppContext.getString("send")); - sendButton.setOnAction(_ -> { onSend.accept(playerInformation, gamesCombobox.getValue()); }); - - final Button cancelButton = button(); - cancelButton.setText(AppContext.getString("cancel")); - cancelButton.setOnAction(_ -> { - ViewStack.pop(); }); - - final List nodes = new ArrayList<>(); - - if (playerInformation.isHuman) { - final Button playerToggle = button(); - playerToggle.setText(AppContext.getString("player")); - playerToggle.setOnAction(_ -> { - playerInformation.isHuman = false; - cleanup(); - setup(); - }); - - nodes.add(vbox(playerToggle)); - } else { - final Button computerToggle = button(); - computerToggle.setText(AppContext.getString("computer")); - computerToggle.setOnAction(_ -> { - playerInformation.isHuman = true; - cleanup(); - setup(); - }); - - nodes.add(vbox(computerToggle)); - - final Text computerDifficultyText = text(); - computerDifficultyText.setText(AppContext.getString("computer-difficulty")); - - final Slider computerDifficultySlider = slider(); - computerDifficultySlider.setMin(0); - computerDifficultySlider.setMax(Server.gameToType(gamesCombobox.getValue()).getMaxDepth()); - computerDifficultySlider.setValue(playerInformation.computerDifficulty); - computerDifficultySlider.valueProperty().addListener((_, _, newValue) -> { - playerInformation.computerDifficulty = newValue.intValue(); - }); - - nodes.add(vbox(computerDifficultyText, computerDifficultySlider)); - } - - add(Pos.CENTER, - fit(hboxFill( - vboxFill( - challengeText, - opponentHeader, - gameText, - gamesCombobox, - separator(), - - hboxFill( - sendButton, - cancelButton - ) - ), - - vboxFill( - nodes.toArray(new Node[0]) - ) - )) - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/view/views/ServerView.java b/app/src/main/java/org/toop/app/view/views/ServerView.java deleted file mode 100644 index c819c14..0000000 --- a/app/src/main/java/org/toop/app/view/views/ServerView.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.toop.app.view.views; - -import org.toop.app.view.View; -import org.toop.app.view.ViewStack; -import org.toop.app.view.displays.SongDisplay; -import org.toop.local.AppContext; - -import javafx.application.Platform; -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.text.Text; - -import java.util.List; -import java.util.function.Consumer; - -public final class ServerView extends View { - private final String user; - private final Consumer onPlayerClicked; - private final Runnable onDisconnect; - - private ListView