From cd8eb99559cfa7622f4c02adfbaa39eb5e8f9666 Mon Sep 17 00:00:00 2001 From: Stef <48526421+StefBuwalda@users.noreply.github.com> Date: Wed, 10 Dec 2025 12:39:40 +0100 Subject: [PATCH] Merge 292 into development (#293) Applied template method pattern to abstract player --- app/src/main/java/org/toop/app/Server.java | 2 +- .../app/widget/view/LocalMultiplayerView.java | 10 +-- .../model/player/AbstractPlayer.java | 64 ++++++++++++------- .../toop/game/players/ArtificialPlayer.java | 2 +- .../org/toop/game/players/LocalPlayer.java | 2 +- .../toop/game/players/{ => ai}/MiniMaxAI.java | 2 +- .../toop/game/players/{ => ai}/RandomAI.java | 2 +- 7 files changed, 49 insertions(+), 35 deletions(-) rename game/src/main/java/org/toop/game/players/{ => ai}/MiniMaxAI.java (99%) rename game/src/main/java/org/toop/game/players/{ => ai}/RandomAI.java (96%) diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index ef691b4..c451c3f 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -21,7 +21,7 @@ import org.toop.game.games.reversi.BitboardReversi; import org.toop.game.games.tictactoe.BitboardTicTacToe; import org.toop.game.players.ArtificialPlayer; import org.toop.game.players.OnlinePlayer; -import org.toop.game.players.RandomAI; +import org.toop.game.players.ai.RandomAI; import org.toop.local.AppContext; import java.util.List; 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 9b9bed2..f28f49d 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 @@ -2,9 +2,6 @@ package org.toop.app.widget.view; import javafx.application.Platform; import org.toop.app.GameInformation; -import org.toop.app.canvas.ReversiBitCanvas; -import org.toop.app.canvas.TicTacToeBitCanvas; -import org.toop.app.gameControllers.GenericGameController; import org.toop.app.gameControllers.ReversiBitController; import org.toop.app.gameControllers.TicTacToeBitController; import org.toop.framework.gameFramework.controller.GameController; @@ -18,8 +15,8 @@ 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.game.players.MiniMaxAI; -import org.toop.game.players.RandomAI; +import org.toop.game.players.ai.MiniMaxAI; +import org.toop.game.players.ai.RandomAI; import org.toop.local.AppContext; import javafx.geometry.Pos; @@ -27,9 +24,6 @@ import javafx.scene.control.ScrollPane; import javafx.scene.layout.VBox; import org.toop.local.AppSettings; -import java.util.Arrays; -import java.util.Random; - public class LocalMultiplayerView extends ViewWidget { private final GameInformation information; diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java index 57e2f18..52b0de4 100644 --- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java +++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java @@ -5,46 +5,66 @@ import org.apache.logging.log4j.Logger; import org.toop.framework.gameFramework.model.game.TurnBasedGame; /** - * Abstract class representing a player in a game. - *

- * Players are entities that can make moves based on the current state of a game. - * player types, such as human players or AI players. - *

- *

- * Subclasses should override the {@link #getMove(GameR)} method to provide - * specific move logic. - *

+ * Base class for players in a turn-based game. + * + * @param the game type */ public abstract class AbstractPlayer> implements Player { - private final Logger logger = LogManager.getLogger(this.getClass()); + private final Logger logger = LogManager.getLogger(this.getClass()); private final String name; + /** + * Creates a new player with the given name. + * + * @param name the player name + */ protected AbstractPlayer(String name) { this.name = name; } + /** + * Creates a copy of another player. + * + * @param other the player to copy + */ protected AbstractPlayer(AbstractPlayer other) { this.name = other.name; } + /** - * Determines the next move based on the provided game state. + * Gets the player's move for the given game state. + * A deep copy is provided so the player cannot modify the real state. *

- * The default implementation throws an {@link UnsupportedOperationException}, - * indicating that concrete subclasses must override this method to provide - * actual move logic. - *

+ * This method uses the Template Method Pattern: it defines the fixed + * algorithm and delegates the variable part to {@link #determineMove(T)}. * - * @param gameCopy a snapshot of the current game state - * @return an integer representing the chosen move - * @throws UnsupportedOperationException if the method is not overridden + * @param game the current game + * @return the chosen move */ - public long getMove(T gameCopy) { - logger.error("Method getMove not implemented."); - throw new UnsupportedOperationException("Not supported yet."); + public final long getMove(T game) { + return determineMove(game.deepCopy()); } - public String getName(){ + + /** + * Determines the player's move using a safe copy of the game. + *

+ * This method is called by {@link #getMove(T)} and should contain + * the player's strategy for choosing a move. + * + * @param gameCopy a deep copy of the game + * @return the chosen move + */ + protected abstract long determineMove(T gameCopy); + + + /** + * Returns the player's name. + * + * @return the name + */ + public String getName() { return this.name; } } diff --git a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java b/game/src/main/java/org/toop/game/players/ArtificialPlayer.java index 418cbed..d141503 100644 --- a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java +++ b/game/src/main/java/org/toop/game/players/ArtificialPlayer.java @@ -44,7 +44,7 @@ public class ArtificialPlayer> extends AbstractPlayer * @return the integer representing the chosen move * @throws ClassCastException if {@code gameCopy} is not of type {@code T} */ - public long getMove(T gameCopy) { + protected long determineMove(T gameCopy) { return ai.getMove(gameCopy); } diff --git a/game/src/main/java/org/toop/game/players/LocalPlayer.java b/game/src/main/java/org/toop/game/players/LocalPlayer.java index 8f3b94d..f5c2daa 100644 --- a/game/src/main/java/org/toop/game/players/LocalPlayer.java +++ b/game/src/main/java/org/toop/game/players/LocalPlayer.java @@ -22,7 +22,7 @@ public class LocalPlayer> extends AbstractPlayer { } @Override - public long getMove(T gameCopy) { + protected long determineMove(T gameCopy) { return getValidMove(gameCopy); } diff --git a/game/src/main/java/org/toop/game/players/MiniMaxAI.java b/game/src/main/java/org/toop/game/players/ai/MiniMaxAI.java similarity index 99% rename from game/src/main/java/org/toop/game/players/MiniMaxAI.java rename to game/src/main/java/org/toop/game/players/ai/MiniMaxAI.java index 440bb50..8ae270e 100644 --- a/game/src/main/java/org/toop/game/players/MiniMaxAI.java +++ b/game/src/main/java/org/toop/game/players/ai/MiniMaxAI.java @@ -1,4 +1,4 @@ -package org.toop.game.players; +package org.toop.game.players.ai; import org.toop.framework.gameFramework.GameState; import org.toop.framework.gameFramework.model.game.PlayResult; diff --git a/game/src/main/java/org/toop/game/players/RandomAI.java b/game/src/main/java/org/toop/game/players/ai/RandomAI.java similarity index 96% rename from game/src/main/java/org/toop/game/players/RandomAI.java rename to game/src/main/java/org/toop/game/players/ai/RandomAI.java index 2d0fe02..1c4223a 100644 --- a/game/src/main/java/org/toop/game/players/RandomAI.java +++ b/game/src/main/java/org/toop/game/players/ai/RandomAI.java @@ -1,4 +1,4 @@ -package org.toop.game.players; +package org.toop.game.players.ai; import org.toop.framework.gameFramework.model.game.TurnBasedGame; import org.toop.framework.gameFramework.model.player.AbstractAI;