mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Merge remote-tracking branch 'refs/remotes/origin/Development' into Tutorials
# Conflicts: # app/src/main/java/org/toop/app/game/Connect4Game.java
This commit is contained in:
@@ -43,13 +43,15 @@ public final class App extends Application {
|
||||
|
||||
scene.getRoot();
|
||||
|
||||
stage.setMinWidth(1080);
|
||||
stage.setMinHeight(720);
|
||||
stage.setOnCloseRequest(event -> {
|
||||
event.consume();
|
||||
startQuit();
|
||||
});
|
||||
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(false);
|
||||
stage.setResizable(true);
|
||||
|
||||
stage.show();
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ public final class Server {
|
||||
information.players[0].name = user;
|
||||
information.players[0].isHuman = false;
|
||||
information.players[0].computerDifficulty = 5;
|
||||
information.players[0].computerThinkTime = 1;
|
||||
information.players[1].name = response.opponent();
|
||||
|
||||
Runnable onGameOverRunnable = isSingleGame.get()? null: this::gameOver;
|
||||
|
||||
@@ -6,6 +6,6 @@ import java.util.function.Consumer;
|
||||
|
||||
public class Connect4Canvas extends GameCanvas {
|
||||
public Connect4Canvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked);
|
||||
super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked,null);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class GameCanvas {
|
||||
@@ -35,7 +36,7 @@ public abstract class GameCanvas {
|
||||
|
||||
protected final Cell[] cells;
|
||||
|
||||
protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked) {
|
||||
protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
|
||||
canvas = new Canvas(width, height);
|
||||
graphics = canvas.getGraphicsContext2D();
|
||||
|
||||
@@ -81,6 +82,9 @@ public abstract class GameCanvas {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
@@ -150,6 +154,21 @@ public abstract class GameCanvas {
|
||||
graphics.fillOval(x, y, width, height);
|
||||
}
|
||||
|
||||
public void drawInnerDot(Color color, int cell, boolean slightlyBigger) {
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
float multiplier = slightlyBigger?1.4f:1.5f;
|
||||
|
||||
final float width = (cells[cell].width() - gapSize * 2)/multiplier;
|
||||
final float height = (cells[cell].height() - gapSize * 2)/multiplier;
|
||||
|
||||
float offset = slightlyBigger?5f:4f;
|
||||
|
||||
graphics.setFill(color);
|
||||
graphics.fillOval(x + width/offset, y + height/offset, width, height);
|
||||
}
|
||||
|
||||
private void drawDotScaled(Color color, int cell, double scale) {
|
||||
final float cx = cells[cell].x() + gapSize;
|
||||
final float cy = cells[cell].y() + gapSize;
|
||||
|
||||
@@ -1,15 +1,68 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ReversiCanvas extends GameCanvas {
|
||||
public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.GREEN, width, height, 8, 8, 5, true, onCellClicked);
|
||||
private Move[] currentlyHighlightedMoves = null;
|
||||
public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
|
||||
super(color, new Color(0f,0.4f,0.2f,1f), width, height, 8, 8, 5, true, onCellClicked, newCellEntered);
|
||||
drawStartingDots();
|
||||
|
||||
final AtomicReference<Cell> 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 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;
|
||||
}
|
||||
|
||||
public void drawStartingDots() {
|
||||
drawDot(Color.BLACK, 28);
|
||||
drawDot(Color.WHITE, 36);
|
||||
@@ -17,7 +70,15 @@ public final class ReversiCanvas extends GameCanvas {
|
||||
drawDot(Color.WHITE, 27);
|
||||
}
|
||||
|
||||
public void drawLegalPosition(Color color, int cell) {
|
||||
drawDot(new Color(color.getRed(), color.getGreen(), color.getBlue(), 0.25), cell);
|
||||
public void drawLegalPosition(int cell, char player) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public final class TicTacToeCanvas extends GameCanvas {
|
||||
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked);
|
||||
super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null);
|
||||
}
|
||||
|
||||
public void drawX(Color color, int cell) {
|
||||
|
||||
@@ -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<TGame extends Game, TAI, TCanvas> {
|
||||
protected final GameInformation information;
|
||||
protected final int myTurn;
|
||||
protected final Runnable onGameOver;
|
||||
protected final BlockingQueue<Game.Move> moveQueue;
|
||||
protected final BlockingQueue<Move> moveQueue;
|
||||
|
||||
protected final TGame game;
|
||||
protected final TAI ai;
|
||||
@@ -85,7 +86,7 @@ public abstract class BaseGameThread<TGame extends Game, TAI, TCanvas> {
|
||||
final char value = getSymbolForTurn(currentTurn);
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell, value));
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ 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.Game;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -23,7 +24,7 @@ public class Connect4Game {
|
||||
|
||||
private final int myTurn;
|
||||
private Runnable onGameOver;
|
||||
private final BlockingQueue<Game.Move> moveQueue;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final Connect4 game;
|
||||
private final Connect4AI ai;
|
||||
@@ -39,7 +40,7 @@ public class Connect4Game {
|
||||
this.information = information;
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
moveQueue = new LinkedBlockingQueue<Game.Move>();
|
||||
moveQueue = new LinkedBlockingQueue<Move>();
|
||||
|
||||
|
||||
game = new Connect4();
|
||||
@@ -67,7 +68,7 @@ public class Connect4Game {
|
||||
final char value = game.getCurrentTurn() == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell%columnSize, value));
|
||||
moveQueue.put(new Move(cell%columnSize, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
@@ -75,7 +76,7 @@ public class Connect4Game {
|
||||
final char value = myTurn == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell%columnSize, value));
|
||||
moveQueue.put(new Move(cell%columnSize, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
@@ -111,14 +112,14 @@ public class Connect4Game {
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Game.Move move = null;
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Game.Move wants = moveQueue.take();
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
@@ -145,7 +146,7 @@ public class Connect4Game {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Game.State state = game.play(move);
|
||||
final GameState state = game.play(move);
|
||||
updateCanvas();
|
||||
/*
|
||||
if (move.value() == 'X') {
|
||||
@@ -154,10 +155,10 @@ public class Connect4Game {
|
||||
canvas.drawO(Color.ROYALBLUE, move.position());
|
||||
}
|
||||
*/
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(true, information.players[currentTurn].name);
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
@@ -179,11 +180,11 @@ public class Connect4Game {
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Game.Move move = new Game.Move(Integer.parseInt(response.move()), playerChar);
|
||||
final Game.State state = game.play(move);
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
@@ -191,7 +192,7 @@ public class Connect4Game {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
gameOver();
|
||||
}
|
||||
@@ -230,7 +231,7 @@ public class Connect4Game {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Game.Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
final Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
@@ -243,10 +244,10 @@ public class Connect4Game {
|
||||
private void updateCanvas() {
|
||||
canvas.clearAll();
|
||||
|
||||
for (int i = 0; i < game.board.length; i++) {
|
||||
if (game.board[i] == 'X') {
|
||||
for (int i = 0; i < game.getBoard().length; i++) {
|
||||
if (game.getBoard()[i] == 'X') {
|
||||
canvas.drawDot(Color.RED, i);
|
||||
} else if (game.board[i] == 'O') {
|
||||
} else if (game.getBoard()[i] == 'O') {
|
||||
canvas.drawDot(Color.BLUE, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@ 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.Game;
|
||||
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;
|
||||
@@ -25,7 +27,7 @@ public final class ReversiGame {
|
||||
|
||||
private final int myTurn;
|
||||
private final Runnable onGameOver;
|
||||
private final BlockingQueue<Game.Move> moveQueue;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final Reversi game;
|
||||
private final ReversiAI ai;
|
||||
@@ -69,7 +71,7 @@ public final class ReversiGame {
|
||||
final char value = game.getCurrentTurn() == 0? 'B' : 'W';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell, value));
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
@@ -77,11 +79,13 @@ public final class ReversiGame {
|
||||
final char value = myTurn == 0? 'B' : 'W';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell, value));
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
},this::highlightCells);
|
||||
|
||||
|
||||
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
@@ -123,14 +127,14 @@ public final class ReversiGame {
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Game.Move move = null;
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Game.Move wants = moveQueue.take();
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
@@ -157,13 +161,18 @@ public final class ReversiGame {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Game.State state = game.play(move);
|
||||
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) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.TURN_SKIPPED){
|
||||
continue;
|
||||
}
|
||||
int winningPLayerNumber = getPlayerNumberWithHighestScore();
|
||||
if (state == GameState.WIN && winningPLayerNumber > -1) {
|
||||
primary.gameOver(true, information.players[winningPLayerNumber].name);
|
||||
} else if (state == GameState.DRAW || winningPLayerNumber == -1) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
@@ -172,6 +181,13 @@ public final class ReversiGame {
|
||||
}
|
||||
}
|
||||
|
||||
private int getPlayerNumberWithHighestScore(){
|
||||
Reversi.Score score = game.getScore();
|
||||
if (score.player1Score() > score.player2Score()) return 0;
|
||||
if (score.player1Score() < score.player2Score()) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void onMoveResponse(NetworkEvents.GameMoveResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
@@ -185,11 +201,11 @@ public final class ReversiGame {
|
||||
playerChar = myTurn == 0? 'W' : 'B';
|
||||
}
|
||||
|
||||
final Game.Move move = new Game.Move(Integer.parseInt(response.move()), playerChar);
|
||||
final Game.State state = game.play(move);
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
@@ -197,7 +213,7 @@ public final class ReversiGame {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
game.play(move);
|
||||
}
|
||||
@@ -229,7 +245,7 @@ public final class ReversiGame {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Game.Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
final Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
@@ -243,15 +259,15 @@ public final class ReversiGame {
|
||||
// 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.board.length; i++) {
|
||||
if (game.board[i] == 'B') {
|
||||
for (int i = 0; i < game.getBoard().length; i++) {
|
||||
if (game.getBoard()[i] == 'B') {
|
||||
canvas.drawDot(Color.BLACK, i);
|
||||
} else if (game.board[i] == 'W') {
|
||||
} else if (game.getBoard()[i] == 'W') {
|
||||
canvas.drawDot(Color.WHITE, i);
|
||||
}
|
||||
}
|
||||
|
||||
final Game.Move[] flipped = game.getMostRecentlyFlippedPieces();
|
||||
final Move[] flipped = game.getMostRecentlyFlippedPieces();
|
||||
|
||||
final SequentialTransition animation = new SequentialTransition();
|
||||
isPaused.set(true);
|
||||
@@ -260,7 +276,7 @@ public final class ReversiGame {
|
||||
final Color toColor = game.getCurrentPlayer() == 'W'? Color.BLACK : Color.WHITE;
|
||||
|
||||
if (animate && flipped != null) {
|
||||
for (final Game.Move flip : flipped) {
|
||||
for (final Move flip : flipped) {
|
||||
canvas.clear(flip.position());
|
||||
canvas.drawDot(fromColor, flip.position());
|
||||
animation.getChildren().addFirst(canvas.flipDot(fromColor, toColor, flip.position()));
|
||||
@@ -270,11 +286,13 @@ public final class ReversiGame {
|
||||
animation.setOnFinished(_ -> {
|
||||
isPaused.set(false);
|
||||
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
canvas.drawLegalPosition(fromColor, legalMove.position());
|
||||
}
|
||||
for (final Move legalMove : legalMoves) {
|
||||
canvas.drawLegalPosition(legalMove.position(), game.getCurrentPlayer());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
animation.play();
|
||||
@@ -289,4 +307,27 @@ public final class ReversiGame {
|
||||
currentValue,
|
||||
information.players[isMe? 1 : 0].name);
|
||||
}
|
||||
|
||||
private void highlightCells(int cellEntered) {
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ 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.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;
|
||||
|
||||
@@ -24,7 +25,7 @@ public final class TicTacToeGame {
|
||||
|
||||
private final int myTurn;
|
||||
private final Runnable onGameOver;
|
||||
private final BlockingQueue<Game.Move> moveQueue;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final TicTacToe game;
|
||||
private final TicTacToeAI ai;
|
||||
@@ -39,7 +40,7 @@ public final class TicTacToeGame {
|
||||
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
moveQueue = new LinkedBlockingQueue<Game.Move>();
|
||||
moveQueue = new LinkedBlockingQueue<Move>();
|
||||
|
||||
game = new TicTacToe();
|
||||
ai = new TicTacToeAI();
|
||||
@@ -66,7 +67,7 @@ public final class TicTacToeGame {
|
||||
final char value = game.getCurrentTurn() == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell, value));
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
@@ -74,7 +75,7 @@ public final class TicTacToeGame {
|
||||
final char value = myTurn == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Game.Move(cell, value));
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
@@ -109,14 +110,14 @@ public final class TicTacToeGame {
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Game.Move move = null;
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Game.Move wants = moveQueue.take();
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
@@ -143,7 +144,7 @@ public final class TicTacToeGame {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Game.State state = game.play(move);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.INDIANRED, move.position());
|
||||
@@ -151,10 +152,10 @@ public final class TicTacToeGame {
|
||||
canvas.drawO(Color.ROYALBLUE, move.position());
|
||||
}
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(true, information.players[currentTurn].name);
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
@@ -176,11 +177,11 @@ public final class TicTacToeGame {
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Game.Move move = new Game.Move(Integer.parseInt(response.move()), playerChar);
|
||||
final Game.State state = game.play(move);
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
@@ -188,7 +189,7 @@ public final class TicTacToeGame {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} 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();
|
||||
@@ -227,13 +228,8 @@ public final class TicTacToeGame {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Game.Move move;
|
||||
if (information.players[1].name.equalsIgnoreCase("pism")) {
|
||||
move = ai.findWorstMove(game,9);
|
||||
}else{
|
||||
move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
}
|
||||
|
||||
final Move move;
|
||||
move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ 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;
|
||||
@@ -45,7 +46,7 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
return turn == 0 ? "X" : "O";
|
||||
}
|
||||
|
||||
private void drawMove(Game.Move move) {
|
||||
private void drawMove(Move move) {
|
||||
if (move.value() == 'X') canvas.drawX(Color.RED, move.position());
|
||||
else canvas.drawO(Color.BLUE, move.position());
|
||||
}
|
||||
@@ -64,11 +65,11 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Game.Move move = new Game.Move(Integer.parseInt(response.move()), playerChar);
|
||||
final Game.State state = game.play(move);
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
@@ -76,7 +77,7 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
if (game.getLegalMoves().length == 0) {
|
||||
primary.gameOver(false, "");
|
||||
gameOver();
|
||||
@@ -103,7 +104,7 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Game.Move move;
|
||||
final Move move;
|
||||
if (information.players[1].name.equalsIgnoreCase("pism")) {
|
||||
move = ai.findWorstMove(game,9);
|
||||
}else{
|
||||
@@ -124,14 +125,14 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
setGameLabels(currentTurn == myTurn);
|
||||
|
||||
Game.Move move = null;
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Game.Move wants = moveQueue.take();
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
@@ -158,13 +159,13 @@ public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacT
|
||||
continue;
|
||||
}
|
||||
|
||||
final Game.State state = game.play(move);
|
||||
final GameState state = game.play(move);
|
||||
drawMove(move);
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(information.players[currentTurn].isHuman, information.players[currentTurn].name);
|
||||
} else if (state == Game.State.DRAW) {
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ 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()
|
||||
@@ -28,7 +29,6 @@ public class SongDisplay extends VBox implements Widget {
|
||||
setAlignment(Pos.CENTER);
|
||||
getStyleClass().add("song-display");
|
||||
|
||||
// TODO ADD GOOD SONG TITLES WITH ARTISTS DISPLAYED
|
||||
songTitle = new Text("song playing");
|
||||
songTitle.getStyleClass().add("song-title");
|
||||
|
||||
@@ -38,8 +38,6 @@ public class SongDisplay extends VBox implements Widget {
|
||||
progressText = new Text("0:00/0:00");
|
||||
progressText.getStyleClass().add("progress-text");
|
||||
|
||||
// TODO ADD BETTER CSS FOR THE SKIPBUTTON WHERE ITS AT A NICER POSITION
|
||||
|
||||
Button skipButton = new Button(">>");
|
||||
Button pauseButton = new Button("⏸");
|
||||
Button previousButton = new Button("<<");
|
||||
@@ -50,20 +48,20 @@ public class SongDisplay extends VBox implements Widget {
|
||||
|
||||
skipButton.setOnAction( event -> {
|
||||
GlobalEventBus.post(new AudioEvents.SkipMusic());
|
||||
paused = false;
|
||||
pauseButton.setText(getPlayString(paused));
|
||||
});
|
||||
|
||||
pauseButton.setOnAction(event -> {
|
||||
GlobalEventBus.post(new AudioEvents.PauseMusic());
|
||||
if (pauseButton.getText().equals("⏸")) {
|
||||
pauseButton.setText("▶");
|
||||
}
|
||||
else if (pauseButton.getText().equals("▶")) {
|
||||
pauseButton.setText("⏸");
|
||||
}
|
||||
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);
|
||||
@@ -114,6 +112,14 @@ public class SongDisplay extends VBox implements Widget {
|
||||
public Node getNode() {
|
||||
return this;
|
||||
}
|
||||
private String getPlayString(boolean paused) {
|
||||
if (paused) {
|
||||
return "▶";
|
||||
}
|
||||
else {
|
||||
return "⏸";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,10 +15,12 @@ import javafx.scene.text.Text;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class GameView extends View {
|
||||
// TODO: This should be it's own file...
|
||||
private static class GameOverView extends View {
|
||||
private final boolean iWon;
|
||||
private final String winner;
|
||||
|
||||
// TODO: Make winner generic, there is no "I won" unless you play online or against bot. Should be a generic "... won" to simplify
|
||||
public GameOverView(boolean iWon, String winner) {
|
||||
super(false, "bg-popup");
|
||||
|
||||
@@ -71,6 +73,8 @@ public final class GameView extends View {
|
||||
|
||||
private final Text nextPlayerHeader;
|
||||
|
||||
private final Text gameStateFeedback = text();
|
||||
|
||||
private final ListView<Text> chatListView;
|
||||
private final TextField chatInput;
|
||||
|
||||
@@ -112,34 +116,24 @@ public final class GameView extends View {
|
||||
exitButton.setText(AppContext.getString("exit"));
|
||||
exitButton.setOnAction(_ -> onExit.run());
|
||||
|
||||
currentPlayerHeader = header("", "current-player");
|
||||
currentPlayerHeader = header("", "header");
|
||||
currentMoveHeader = header();
|
||||
|
||||
nextPlayerHeader = header();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
add(Pos.TOP_RIGHT,
|
||||
fit(vboxFill(
|
||||
currentPlayerHeader,
|
||||
|
||||
hboxFill(
|
||||
separator(),
|
||||
currentMoveHeader,
|
||||
separator()
|
||||
),
|
||||
|
||||
nextPlayerHeader
|
||||
))
|
||||
add(
|
||||
Pos.TOP_CENTER,
|
||||
gameStateFeedback
|
||||
);
|
||||
|
||||
add(Pos.BOTTOM_LEFT,
|
||||
vboxFill(
|
||||
forfeitButton,
|
||||
exitButton
|
||||
)
|
||||
);
|
||||
vboxFill(
|
||||
forfeitButton,
|
||||
exitButton
|
||||
)
|
||||
);
|
||||
|
||||
if (chatListView != null) {
|
||||
add(Pos.BOTTOM_RIGHT,
|
||||
@@ -153,6 +147,7 @@ public final class GameView extends View {
|
||||
|
||||
public void nextPlayer(boolean isMe, String currentPlayer, String currentMove, String nextPlayer) {
|
||||
Platform.runLater(() -> {
|
||||
gameStateFeedback.setText("Waiting on " + currentPlayer + " to make their move.");
|
||||
currentPlayerHeader.setText(currentPlayer);
|
||||
currentMoveHeader.setText(currentMove);
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package org.toop.local;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
import org.toop.framework.resource.resources.LocalizationAsset;
|
||||
|
||||
@@ -15,6 +20,7 @@ public class AppContext {
|
||||
private static Locale locale = Locale.forLanguageTag("en");
|
||||
|
||||
private static final ObjectProperty<Locale> localeProperty = new SimpleObjectProperty<>(locale);
|
||||
private static final Logger logger = LogManager.getLogger(AppContext.class);
|
||||
|
||||
public static LocalizationAsset getLocalization() {
|
||||
return localization;
|
||||
@@ -30,7 +36,26 @@ public class AppContext {
|
||||
}
|
||||
|
||||
public static String getString(String key) {
|
||||
return localization.getString(key, locale);
|
||||
assert localization != null;
|
||||
|
||||
// TODO: Gebruik ResourceBundle.getBundle() zodat de fallback automatisch gaat.
|
||||
// Hiervoor zou de assetManager aangepast moeten worden.
|
||||
|
||||
try{ // Main return
|
||||
return localization.getString(key, locale);
|
||||
}
|
||||
catch (MissingResourceException e) {
|
||||
logger.error("Missing resource key: {}, in bundle: {}. ", key, locale, e);
|
||||
}
|
||||
|
||||
try{ // Fallback return
|
||||
return localization.getString(key, localization.getFallback());
|
||||
}
|
||||
catch (MissingResourceException e) {
|
||||
logger.error("Missing resource key: {}, in default bundle!", key, e);
|
||||
}
|
||||
// Default return
|
||||
return "MISSING RESOURCE";
|
||||
}
|
||||
|
||||
public static StringBinding bindToKey(String key) {
|
||||
|
||||
Reference in New Issue
Block a user