Added documentation to player classes and improved method names (#295)

This commit is contained in:
Stef
2025-12-10 13:17:01 +01:00
committed by GitHub
parent cd8eb99559
commit 1ae79daef0
4 changed files with 99 additions and 83 deletions

View File

@@ -55,7 +55,7 @@ public class GenericGameController<T extends TurnBasedGame<T>> implements GameCo
// Listen to updates
eventFlow
.listen(GUIEvents.GameEnded.class, this::onGameFinish, false)
.listen(GUIEvents.PlayerAttemptedMove.class, event -> {if (getCurrentPlayer() instanceof LocalPlayer<T> lp){lp.setMove(event.move());}}, false);
.listen(GUIEvents.PlayerAttemptedMove.class, event -> {if (getCurrentPlayer() instanceof LocalPlayer<T> lp){lp.setLastMove(event.move());}}, false);
}
public void start(){

View File

@@ -4,52 +4,52 @@ import org.toop.framework.gameFramework.model.player.*;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
/**
* Represents a player controlled by an AI in a game.
* <p>
* This player uses an {@link AbstractAI} instance to determine its moves. The generic
* parameter {@code T} specifies the type of {@link GameR} the AI can handle.
* </p>
* Represents a player controlled by an AI.
*
* @param <T> the specific type of game this AI player can play
* @param <T> the type of turn-based game
*/
public class ArtificialPlayer<T extends TurnBasedGame<T>> extends AbstractPlayer<T> {
/** The AI instance used to calculate moves. */
private final AI<T> ai;
/**
* Constructs a new ArtificialPlayer using the specified AI.
* Creates a new AI-controlled player.
*
* @param ai the AI instance that determines moves for this player
* @param ai the AI controlling this player
* @param name the player's name
*/
public ArtificialPlayer(AI<T> ai, String name) {
super(name);
this.ai = ai;
}
/**
* Creates a copy of another AI-controlled player.
*
* @param other the player to copy
*/
public ArtificialPlayer(ArtificialPlayer<T> other) {
super(other);
this.ai = other.ai.deepCopy();
}
/**
* Determines the next move for this player using its AI.
* <p>
* This method overrides {@link AbstractPlayer#getMove(GameR)}. Because the AI is
* typed to {@code T}, a runtime cast is required. It is the caller's
* responsibility to ensure that {@code gameCopy} is of type {@code T}.
* </p>
* Determines the player's move using the AI.
*
* @param gameCopy a copy of the current game state
* @return the integer representing the chosen move
* @throws ClassCastException if {@code gameCopy} is not of type {@code T}
* @param gameCopy a copy of the current game
* @return the move chosen by the AI
*/
protected long determineMove(T gameCopy) {
return ai.getMove(gameCopy);
}
/**
* Creates a deep copy of this AI player.
*
* @return a copy of this player
*/
@Override
public ArtificialPlayer<T> deepCopy() {
return new ArtificialPlayer<T>(this);
return new ArtificialPlayer<>(this);
}
}

View File

@@ -2,85 +2,86 @@ package org.toop.game.players;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.AbstractPlayer;
import org.toop.framework.gameFramework.model.player.Player;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* Represents a local player who provides moves manually.
*
* @param <T> the type of turn-based game
*/
public class LocalPlayer<T extends TurnBasedGame<T>> extends AbstractPlayer<T> {
// Future can be used with event system, IF unsubscribeAfterSuccess works...
// private CompletableFuture<Integer> LastMove = new CompletableFuture<>();
private CompletableFuture<Long> LastMove;
private CompletableFuture<Long> LastMove = new CompletableFuture<>();
/**
* Creates a new local player with the given name.
*
* @param name the player's name
*/
public LocalPlayer(String name) {
super(name);
}
/**
* Creates a copy of another local player.
*
* @param other the player to copy
*/
public LocalPlayer(LocalPlayer<T> other) {
super(other);
this.LastMove = other.LastMove;
}
/**
* Waits for and returns the player's next legal move.
*
* @param gameCopy a copy of the current game
* @return the chosen move
*/
@Override
protected long determineMove(T gameCopy) {
return getValidMove(gameCopy);
long legalMoves = gameCopy.getLegalMoves();
long move;
do {
move = getLastMove();
} while ((legalMoves & move) == 0);
return move;
}
public void setMove(long move) {
/**
* Sets the player's last move.
*
* @param move the move to set
*/
public void setLastMove(long move) {
LastMove.complete(move);
}
// TODO: helper function, would like to replace to get rid of this method
public static boolean contains(int[] array, int value){
for (int i : array) if (i == value) return true;
return false;
}
private long getMove2(T gameCopy) {
LastMove = new CompletableFuture<>();
long move = 0;
/**
* Waits for the next move from the player.
*
* @return the chosen move or 0 if interrupted
*/
private long getLastMove() {
LastMove = new CompletableFuture<>(); // Reset the future
try {
move = LastMove.get();
System.out.println(Long.toBinaryString(move));
} catch (InterruptedException | ExecutionException e) {
// TODO: Add proper logging.
e.printStackTrace();
return LastMove.get();
} catch (ExecutionException | InterruptedException e) {
return 0;
}
return move;
}
protected long getValidMove(T gameCopy){
// Get this player's valid moves
long validMoves = gameCopy.getLegalMoves();
// Make sure provided move is valid
// TODO: Limit amount of retries?
// TODO: Stop copying game so many times
long move = getMove2(gameCopy.deepCopy());
while ((validMoves & move) == 0) {
System.out.println("Not a valid move, try again");
move = getMove2(gameCopy.deepCopy());
}
return move;
}
/**
* Creates a deep copy of this local player.
*
* @return a copy of this player
*/
@Override
public LocalPlayer<T> deepCopy() {
return new LocalPlayer<T>(this.getName());
return new LocalPlayer<>(this);
}
/*public void register() {
// Listening to PlayerAttemptedMove
new EventFlow().listen(GUIEvents.PlayerAttemptedMove.class, event -> {
if (!LastMove.isDone()) {
LastMove.complete(event.move()); // complete the future
}
}, true); // auto-unsubscribe
}
// This blocks until the next move arrives
public int take() throws ExecutionException, InterruptedException {
int move = LastMove.get(); // blocking
LastMove = new CompletableFuture<>(); // reset for next move
return move;
}*/
}

View File

@@ -5,30 +5,45 @@ import org.toop.framework.gameFramework.model.player.AbstractPlayer;
import org.toop.framework.gameFramework.model.player.Player;
/**
* Represents a player controlled remotely or over a network.
* <p>
* This class extends {@link AbstractPlayer} and can be used to implement game logic
* where moves are provided by an external source (e.g., another user or a server).
* Currently, this class is a placeholder and does not implement move logic.
* </p>
* Represents a player that participates online.
*
* @param <T> the type of turn-based game
*/
public class OnlinePlayer<T extends TurnBasedGame<T>> extends AbstractPlayer<T> {
/**
* Constructs a new OnlinePlayer.
* <p>
* Currently, no additional initialization is performed. Subclasses or
* future implementations should provide mechanisms to receive moves from
* an external source.
* Creates a new online player with the given name.
*
* @param name the name of the player
*/
public OnlinePlayer(String name) {
super(name);
}
/**
* Creates a copy of another online player.
*
* @param other the player to copy
*/
public OnlinePlayer(OnlinePlayer<T> other) {
super(other);
}
/**
* {@inheritDoc}
* <p>
* This method is not supported for online players.
*
* @throws UnsupportedOperationException always
*/
@Override
protected long determineMove(T gameCopy) {
throw new UnsupportedOperationException("An online player does not support determining move");
}
/**
* {@inheritDoc}
*/
@Override
public Player<T> deepCopy() {
return new OnlinePlayer<>(this);