diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 655cfae..e0e273b 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,7 +2,7 @@ diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index bd330d2..3b4fef3 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -4,50 +4,6 @@ import org.toop.app.App; public final class Main { static void main(String[] args) { - App.run(args); - // testMCTS(10); + App.run(args); } - - // Voor onderzoek - // private static void testMCTS(int games) { - // var random = new ArtificialPlayer<>(new RandomAI(), "Random AI"); - // var v1 = new ArtificialPlayer<>(new MCTSAI(10), "MCTS V1 AI"); - // var v2 = new ArtificialPlayer<>(new MCTSAI2(10), "MCTS V2 AI"); - // var v2_2 = new ArtificialPlayer<>(new MCTSAI2(100), "MCTS V2_2 AI"); - // var v3 = new ArtificialPlayer<>(new MCTSAI3(10), "MCTS V3 AI"); - - // testAI(games, new Player[]{ v1, v2 }); - // // testAI(games, new Player[]{ v1, v3 }); - - // // testAI(games, new Player[]{ random, v3 }); - // // testAI(games, new Player[]{ v2, v3 }); - // testAI(games, new Player[]{ v2, v3 }); - // // testAI(games, new Player[]{ v3, v2 }); - // } - - // private static void testAI(int games, Player[] ais) { - // int wins = 0; - // int ties = 0; - - // for (int i = 0; i < games; i++) { - // final BitboardReversi match = new BitboardReversi(ais); - - // while (!match.isTerminal()) { - // final int currentAI = match.getCurrentTurn(); - // final long move = ais[currentAI].getMove(match); - - // match.play(move); - // } - - // if (match.getWinner() < 0) { - // ties++; - // continue; - // } - - // wins += match.getWinner() == 0? 1 : 0; - // } - - // System.out.printf("Out of %d games, %s won %d -- tied %d -- lost %d, games against %s\n", games, ais[0].getName(), wins, ties, games - wins - ties, ais[1].getName()); - // System.out.printf("Average win rate was: %.2f\n\n", wins / (float)games); - // } } diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index f6bcdec..d8c4acf 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -11,6 +11,7 @@ import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.view.ServerView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.game.players.ArtificialPlayer; import org.toop.framework.game.players.OnlinePlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.eventbus.GlobalEventBus; @@ -19,9 +20,10 @@ import org.toop.framework.networking.connection.clients.TournamentNetworkingClie import org.toop.framework.networking.connection.events.NetworkEvents; import org.toop.framework.networking.connection.types.NetworkingConnector; import org.toop.framework.networking.server.gateway.NettyGatewayServer; -import org.toop.framework.game.players.LocalPlayer; +import org.toop.game.players.ai.mcts.MCTSAI3; import org.toop.local.AppContext; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; @@ -117,7 +119,8 @@ public final class Server { return; } - primary = new ServerView(user, this::sendChallenge, clientId); + primary = new ServerView(user, this::sendChallenge, user, clientId); + WidgetContainer.getCurrentView().transitionNextCustom(primary, "disconnect", this::disconnect); a.unsubscribe("connecting"); @@ -159,7 +162,8 @@ public final class Server { .listen(NetworkEvents.GameResultResponse.class, this::handleGameResult, false, "game-result") .listen(NetworkEvents.GameMoveResponse.class, this::handleReceivedMove, false, "game-move") .listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn") - .listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection"); + .listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection") + .listen(NetworkEvents.TournamentResultResponse.class, this::handleTournamentResult, false, "tournament-result"); connectFlow = a; } @@ -205,7 +209,8 @@ public final class Server { information.players[opponentStartingTurn].name = response.opponent(); Player[] players = new Player[2]; - players[userStartingTurn] = new LocalPlayer(user); + + players[userStartingTurn] = new ArtificialPlayer(new MCTSAI3(1000, 8), user); players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { @@ -238,6 +243,13 @@ public final class Server { gameController.gameFinished(response); } + private void handleTournamentResult(NetworkEvents.TournamentResultResponse response) { + IO.println(response.gameType()); + IO.println(Arrays.toString(response.names())); + IO.println(Arrays.toString(response.scoreTypes())); + IO.println(Arrays.toString(response.scores().toArray())); + } + private void handleReceivedMove(NetworkEvents.GameMoveResponse response) { if (gameController == null) { return; @@ -337,7 +349,8 @@ public final class Server { private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) { gameList.clear(); - var gl = List.of(event.gamelist()); + var gl = new java.util.ArrayList<>(List.of(event.gamelist())); + gl.sort(String::compareTo); gameList.addAll(gl); primary.updateGameList(gl); } diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java index 685a985..d210b16 100644 --- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java @@ -2,9 +2,13 @@ package org.toop.app.canvas; import javafx.scene.paint.Color; import org.toop.app.App; +import org.toop.framework.game.games.reversi.BitboardReversi; +import org.toop.framework.game.players.LocalPlayer; import org.toop.framework.gameFramework.model.game.TurnBasedGame; public class ReversiBitCanvas extends BitGameCanvas { + private TurnBasedGame gameCopy; + private int previousCell; public ReversiBitCanvas() { super(Color.GRAY, new Color(0f, 0.4f, 0.2f, 1f), (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, 8, 8, 5, true); canvas.setOnMouseMoved(event -> { @@ -20,6 +24,9 @@ public class ReversiBitCanvas extends BitGameCanvas { break; } } + if (hovered != null) { + checkHoverDots(hovered, cellId); + } }); } @@ -31,9 +38,31 @@ public class ReversiBitCanvas extends BitGameCanvas { @Override public void redraw(TurnBasedGame gameCopy) { + this.gameCopy = gameCopy; clearAll(); long[] board = gameCopy.getBoard(); loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, i)); loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, i)); } + + public void drawLegalDots(TurnBasedGame gameCopy){ + long legal = gameCopy.getLegalMoves(); + loopOverBoard(legal, (i) -> drawInnerDot(gameCopy.getCurrentTurn()==0?new Color(1f,1f,1f,0.65f) :new Color(0f,0f,0f,0.65f), i,false)); + } + + private void checkHoverDots(BitGameCanvas.Cell hovered, int cellId){ + if (previousCell == cellId){ + return; + } + long backflips = ((BitboardReversi)gameCopy).getFlips(1L << previousCell); + loopOverBoard(backflips, (i) -> drawInnerDot(gameCopy.getCurrentTurn()==1?Color.WHITE:Color.BLACK, i,true)); + previousCell = cellId; + if (gameCopy.getPlayer(gameCopy.getCurrentTurn()) instanceof LocalPlayer) { + long legal = gameCopy.getLegalMoves(); + if ((legal & (1L << cellId)) != 0) { + long flips = ((BitboardReversi) gameCopy).getFlips(1L << cellId); + loopOverBoard(flips, (i) -> drawInnerDot(gameCopy.getCurrentTurn() == 0 ? Color.WHITE : Color.BLACK, i, false)); + } + } + } } diff --git a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java index 0c68a74..d31c60d 100644 --- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java +++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java @@ -5,10 +5,12 @@ import javafx.geometry.Pos; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.toop.app.canvas.GameCanvas; +import org.toop.app.canvas.ReversiBitCanvas; import org.toop.app.widget.WidgetContainer; import org.toop.app.widget.view.GameView; import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.GlobalEventBus; +import org.toop.framework.game.games.reversi.BitboardReversi; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.model.game.threadBehaviour.SupportsOnlinePlay; import org.toop.framework.gameFramework.model.game.TurnBasedGame; @@ -153,6 +155,18 @@ public class GenericGameController implements GameController { @Override public void updateUI() { - canvas.redraw(game.deepCopy()); + TurnBasedGame gameCopy = game.deepCopy(); + canvas.redraw(gameCopy); + String gameType = game.getClass().getSimpleName().replace("Bitboard",""); + gameView.nextPlayer(true, getCurrentPlayer().getName(), game.getPlayer(1-getCurrentPlayerIndex()).getName(),gameType); + if (gameType.equals("Reversi")) { + BitboardReversi reversiGame = (BitboardReversi) game; + BitboardReversi.Score reversiScore = reversiGame.getScore(); + gameView.setPlayer1Score(reversiScore.black()); + gameView.setPlayer2Score(reversiScore.white()); + if (getCurrentPlayer() instanceof LocalPlayer) { + ((ReversiBitCanvas)canvas).drawLegalDots(gameCopy); + } + } } } diff --git a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java index 1ea8109..8954a62 100644 --- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java +++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java @@ -11,13 +11,19 @@ import org.toop.framework.game.players.OnlinePlayer; import java.util.Arrays; public class ReversiBitController extends GenericGameController { + + private BitboardReversi game; + public ReversiBitController(Player[] players) { BitboardReversi game = new BitboardReversi(); game.init(players); - ThreadBehaviour thread = Arrays.stream(players).anyMatch(e -> e instanceof OnlinePlayer) ? new OnlineThreadBehaviour(game) : new LocalThreadBehaviour(game); super(new ReversiBitCanvas(), game, thread, "Reversi"); } + + public BitboardReversi.Score getScore() { + return game.getScore(); + } } diff --git a/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java b/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java index ab1ef3d..9c9f961 100644 --- a/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java +++ b/app/src/main/java/org/toop/app/widget/popup/GameOverPopup.java @@ -4,6 +4,7 @@ import org.toop.app.widget.complex.ConfirmWidget; import org.toop.app.widget.complex.PopupWidget; import javafx.geometry.Pos; +import org.toop.framework.game.games.reversi.BitboardReversi; public final class GameOverPopup extends PopupWidget { public GameOverPopup(boolean winOrTie, String winner) { @@ -15,7 +16,6 @@ public final class GameOverPopup extends PopupWidget { else{ confirmWidget.setMessage("It was a tie!"); } - confirmWidget.addButton("ok", this::hide); add(Pos.CENTER, confirmWidget); diff --git a/app/src/main/java/org/toop/app/widget/view/GameView.java b/app/src/main/java/org/toop/app/widget/view/GameView.java index 441cc0e..38fcd6c 100644 --- a/app/src/main/java/org/toop/app/widget/view/GameView.java +++ b/app/src/main/java/org/toop/app/widget/view/GameView.java @@ -6,6 +6,8 @@ import javafx.scene.text.Font; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.GameOverPopup; + +import java.util.Objects; import java.util.function.Consumer; import javafx.application.Platform; import javafx.geometry.Pos; @@ -24,6 +26,8 @@ public final class GameView extends ViewWidget { private final Text player2Header; private Circle player1Icon; private Circle player2Icon; + private final Text player1Score; + private final Text player2Score; private final Button forfeitButton; private final Button exitButton; private final TextField chatInput; @@ -38,6 +42,8 @@ public final class GameView extends ViewWidget { player2Header = Primitive.header(""); player1Icon = new Circle(); player2Icon = new Circle(); + player1Score = Primitive.header(""); + player2Score = Primitive.header(""); if (onForfeit != null) { forfeitButton = Primitive.button("forfeit", () -> onForfeit.run(), false); @@ -94,7 +100,7 @@ public final class GameView extends ViewWidget { } } - public void nextPlayer(boolean isMe, String currentPlayer, String currentMove, String nextPlayer, char GameType) { + public void nextPlayer(boolean isMe, String currentPlayer, String nextPlayer, String GameType) { Platform.runLater(() -> { if (!(hasSet)) { playerHeader.setText(currentPlayer + " vs. " + nextPlayer); @@ -112,8 +118,8 @@ public final class GameView extends ViewWidget { new GameOverPopup(iWon, winner).show(Pos.CENTER); } - private void setPlayerHeaders(boolean isMe, String currentPlayer, String nextPlayer, char GameType) { - if (GameType == 'T') { + private void setPlayerHeaders(boolean isMe, String currentPlayer, String nextPlayer, String GameType) { + if (Objects.equals(GameType, "TicTacToe")) { if (isMe) { player1Header.setText("X: " + currentPlayer); player2Header.setText("O: " + nextPlayer); @@ -124,7 +130,7 @@ public final class GameView extends ViewWidget { } setPlayerInfoTTT(); } - else if (GameType == 'R') { + else if (Objects.equals(GameType, "Reversi")) { if (isMe) { player1Header.setText(currentPlayer); player2Header.setText(nextPlayer); @@ -151,14 +157,16 @@ public final class GameView extends ViewWidget { private void setPlayerInfoReversi() { var player1box = Primitive.hbox( player1Icon, - player1Header + player1Header, + player1Score ); player1box.getStyleClass().add("hboxspacing"); var player2box = Primitive.hbox( player2Icon, - player2Header + player2Header, + player2Score ); player2box.getStyleClass().add("hboxspacing"); @@ -172,8 +180,16 @@ public final class GameView extends ViewWidget { player1Icon.setRadius(player1Header.fontProperty().map(Font::getSize).getValue()); player2Icon.setRadius(player2Header.fontProperty().map(Font::getSize).getValue()); - player1Icon.setFill(Color.BLACK); - player2Icon.setFill(Color.WHITE); + player1Icon.setFill(Color.WHITE); + player2Icon.setFill(Color.BLACK); add(Pos.TOP_RIGHT, playerInfo); } + + public void setPlayer1Score(int score) { + player1Score.setText("(" + Integer.toString(score) + ")"); + } + + public void setPlayer2Score(int score) { + player2Score.setText("(" + Integer.toString(score) + ")"); + } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java index 9139720..2db2419 100644 --- a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java +++ b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java @@ -4,6 +4,7 @@ import javafx.application.Platform; import org.toop.app.GameInformation; import org.toop.app.gameControllers.ReversiBitController; import org.toop.app.gameControllers.TicTacToeBitController; +import org.toop.framework.game.players.LocalPlayer; import org.toop.framework.gameFramework.controller.GameController; import org.toop.framework.gameFramework.model.player.Player; import org.toop.framework.game.players.ArtificialPlayer; @@ -12,11 +13,10 @@ import org.toop.app.widget.complex.PlayerInfoWidget; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.tutorial.*; -import org.toop.framework.game.players.LocalPlayer; -import org.toop.game.players.ai.MCTSAI; -import org.toop.game.players.ai.MCTSAI2; -import org.toop.game.players.ai.MCTSAI3; import org.toop.game.players.ai.MiniMaxAI; +import org.toop.game.players.ai.mcts.MCTSAI1; +import org.toop.game.players.ai.mcts.MCTSAI3; +import org.toop.game.players.ai.mcts.MCTSAI4; import org.toop.local.AppContext; import javafx.geometry.Pos; @@ -54,7 +54,7 @@ public class LocalMultiplayerView extends ViewWidget { if (information.players[0].isHuman) { players[0] = new LocalPlayer(information.players[0].name); } else { - players[0] = new ArtificialPlayer(new MCTSAI(100), "MCTS AI"); + players[0] = new ArtificialPlayer(new MCTSAI1(100), "MCTS AI"); } if (information.players[1].isHuman) { players[1] = new LocalPlayer(information.players[1].name); @@ -82,13 +82,13 @@ public class LocalMultiplayerView extends ViewWidget { if (information.players[0].isHuman) { players[0] = new LocalPlayer(information.players[0].name); } else { - // players[0] = new ArtificialPlayer(new RandomAI(), "Random AI"); - players[0] = new ArtificialPlayer(new MCTSAI3(50), "MCTS V3 AI"); + // players[0] = new ArtificialPlayer(new RandomAI(), "Random AI"); + players[0] = new ArtificialPlayer(new MCTSAI1(100), "MCTS V1 AI"); } if (information.players[1].isHuman) { players[1] = new LocalPlayer(information.players[1].name); } else { - players[1] = new ArtificialPlayer(new MCTSAI2(50), "MCTS V2 AI"); + players[1] = new ArtificialPlayer(new MCTSAI4(100, 8), "MCTS V4 AI"); } if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstReversi()) { new ShowEnableTutorialWidget( diff --git a/app/src/main/java/org/toop/app/widget/view/ServerView.java b/app/src/main/java/org/toop/app/widget/view/ServerView.java index 92c8101..9408b27 100644 --- a/app/src/main/java/org/toop/app/widget/view/ServerView.java +++ b/app/src/main/java/org/toop/app/widget/view/ServerView.java @@ -6,6 +6,8 @@ import javafx.scene.control.ComboBox; import org.toop.app.widget.Primitive; import org.toop.app.widget.complex.ViewWidget; +import java.io.Reader; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Consumer; @@ -15,6 +17,7 @@ import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.ListView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.eventbus.GlobalEventBus; import org.toop.framework.networking.connection.events.NetworkEvents; public final class ServerView extends ViewWidget { @@ -22,46 +25,65 @@ public final class ServerView extends ViewWidget { private final Consumer onPlayerClicked; private final long clientId; - private final ComboBox gameList; + private final ComboBox gameListSub; + private final ComboBox gameListTour; private final ListView