mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
(RANDOM COMMIT) Hope it works
This commit is contained in:
@@ -4,35 +4,48 @@ import javafx.scene.paint.Color;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class TicTacToeCanvas extends GameCanvas {
|
||||
public final class TicTacToeCanvas extends GameCanvas implements Drawable {
|
||||
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null);
|
||||
}
|
||||
|
||||
public void drawX(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
public void drawPlayer(char a, Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
drawChar(a, color, cell);
|
||||
draw();
|
||||
}
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
// public void drawX(Color color, int cell) {
|
||||
// graphics.setStroke(color);
|
||||
// graphics.setLineWidth(gapSize);
|
||||
//
|
||||
// final float x = cells[cell].x() + gapSize;
|
||||
// final float y = cells[cell].y() + gapSize;
|
||||
//
|
||||
// final float width = cells[cell].width() - gapSize * 2;
|
||||
// final float height = cells[cell].height() - gapSize * 2;
|
||||
//
|
||||
// graphics.strokeLine(x, y, x + width, y + height);
|
||||
// graphics.strokeLine(x + width, y, x, y + height);
|
||||
// }
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
@Override
|
||||
public void draw() {
|
||||
|
||||
public void drawO(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
}
|
||||
//
|
||||
// public void drawO(Color color, int cell) {
|
||||
// graphics.setStroke(color);
|
||||
// graphics.setLineWidth(gapSize);
|
||||
//
|
||||
// final float x = cells[cell].x() + gapSize;
|
||||
// final float y = cells[cell].y() + gapSize;
|
||||
//
|
||||
// final float width = cells[cell].width() - gapSize * 2;
|
||||
// final float height = cells[cell].height() - gapSize * 2;
|
||||
//
|
||||
// graphics.strokeOval(x, y, width, height);
|
||||
// }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
public interface MoveBehaviour
|
||||
{
|
||||
int getMove();
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
public abstract class Player implements MoveBehaviour{
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.toop.app.game.Players;
|
||||
|
||||
import org.toop.game.AIR;
|
||||
import org.toop.game.GameR;
|
||||
|
||||
/**
|
||||
* Represents a player controlled by an AI in a game.
|
||||
* <p>
|
||||
* This player uses an {@link AIR} instance to determine its moves. The generic
|
||||
* parameter {@code T} specifies the type of {@link GameR} the AI can handle.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the specific type of game this AI player can play
|
||||
*/
|
||||
public class ArtificialPlayer<T extends GameR> extends Player {
|
||||
|
||||
/** The AI instance used to calculate moves. */
|
||||
private final AIR<T> ai;
|
||||
|
||||
/**
|
||||
* Constructs a new ArtificialPlayer using the specified AI.
|
||||
*
|
||||
* @param ai the AI instance that determines moves for this player
|
||||
*/
|
||||
public ArtificialPlayer(AIR<T> ai) {
|
||||
this.ai = ai;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the next move for this player using its AI.
|
||||
* <p>
|
||||
* This method overrides {@link Player#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>
|
||||
*
|
||||
* @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}
|
||||
*/
|
||||
@Override
|
||||
public int getMove(GameR gameCopy) {
|
||||
return ai.findBestMove((T) gameCopy, 9); // TODO: Make depth configurable
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package org.toop.app.game;
|
||||
package org.toop.app.game.Players;
|
||||
|
||||
import org.toop.game.GameR;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class LocalPlayer extends Player{
|
||||
private BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
|
||||
public class LocalPlayer extends Player {
|
||||
private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
|
||||
|
||||
public LocalPlayer() {}
|
||||
|
||||
@Override
|
||||
public int getMove() {
|
||||
public int getMove(GameR gameCopy) {
|
||||
try {
|
||||
return queue.take();
|
||||
}catch (InterruptedException e){
|
||||
23
app/src/main/java/org/toop/app/game/Players/MakesMove.java
Normal file
23
app/src/main/java/org/toop/app/game/Players/MakesMove.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package org.toop.app.game.Players;
|
||||
|
||||
import org.toop.game.GameR;
|
||||
|
||||
/**
|
||||
* Interface representing an entity capable of making a move in a game.
|
||||
* <p>
|
||||
* Any class implementing this interface should provide logic to determine
|
||||
* the next move given a snapshot of the current game state.
|
||||
* </p>
|
||||
*/
|
||||
public interface MakesMove {
|
||||
|
||||
/**
|
||||
* Determines the next move based on the provided game state.
|
||||
*
|
||||
* @param gameCopy a copy or snapshot of the current game state
|
||||
* (never null)
|
||||
* @return an integer representing the chosen move.
|
||||
* The interpretation of this value depends on the specific game.
|
||||
*/
|
||||
int getMove(GameR gameCopy);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.toop.app.game.Players;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Represents a player controlled remotely or over a network.
|
||||
* <p>
|
||||
* This class extends {@link Player} 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>
|
||||
*/
|
||||
public class OnlinePlayer extends Player {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public OnlinePlayer() {}
|
||||
}
|
||||
35
app/src/main/java/org/toop/app/game/Players/Player.java
Normal file
35
app/src/main/java/org/toop/app/game/Players/Player.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package org.toop.app.game.Players;
|
||||
|
||||
import org.toop.game.GameR;
|
||||
|
||||
/**
|
||||
* Abstract class representing a player in a game.
|
||||
* <p>
|
||||
* Players are entities that can make moves based on the current state of a game.
|
||||
* This class implements {@link MakesMove} and serves as a base for concrete
|
||||
* player types, such as human players or AI players.
|
||||
* </p>
|
||||
* <p>
|
||||
* Subclasses should override the {@link #getMove(GameR)} method to provide
|
||||
* specific move logic.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class Player implements MakesMove {
|
||||
|
||||
/**
|
||||
* Determines the next move based on the provided game state.
|
||||
* <p>
|
||||
* The default implementation throws an {@link UnsupportedOperationException},
|
||||
* indicating that concrete subclasses must override this method to provide
|
||||
* actual move logic.
|
||||
* </p>
|
||||
*
|
||||
* @param gameCopy a snapshot of the current game state
|
||||
* @return an integer representing the chosen move
|
||||
* @throws UnsupportedOperationException if the method is not overridden
|
||||
*/
|
||||
@Override
|
||||
public int getMove(GameR gameCopy) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
@@ -1,92 +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.canvas.GameCanvas;
|
||||
import org.toop.app.canvas.TicTacToeCanvas;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.view.GameView;
|
||||
import org.toop.game.TurnBasedGameR;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class TurnBasedGameThread implements Runnable {
|
||||
private final Player[] players; // List of players, can't be changed.
|
||||
private final TurnBasedGameR game; // Reference to game instance
|
||||
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean();
|
||||
|
||||
// TODO: Seperate this from game Thread
|
||||
private final GameView primary = new GameView(null, null, null);
|
||||
private final TicTacToeCanvas canvas;
|
||||
|
||||
public TurnBasedGameThread(Player[] players, TurnBasedGameR game) {
|
||||
// Make sure player list matches expected size
|
||||
if (players.length != game.getPlayerCount()){
|
||||
throw new IllegalArgumentException("players and game's players must have same length");
|
||||
}
|
||||
|
||||
this.players = players;
|
||||
this.game = game;
|
||||
|
||||
Thread thread = new Thread(this::run);
|
||||
thread.start();
|
||||
|
||||
// UI SHIZ TO MOVE
|
||||
canvas = new TicTacToeCanvas(Color.GRAY,
|
||||
(App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3,(c) -> {if (players[game.getCurrentTurn()] instanceof LocalPlayer lp) {lp.enqueueMove(c);}});
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
}
|
||||
|
||||
// Move to UI shiz
|
||||
private void drawMove(int move) {
|
||||
if (game.getCurrentTurn() == 1) canvas.drawX(Color.RED, move);
|
||||
else canvas.drawO(Color.BLUE, move);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
isRunning.set(true);
|
||||
|
||||
// Game logic loop
|
||||
while(isRunning.get()) {
|
||||
|
||||
// Get current player
|
||||
Player currentPlayer = players[game.getCurrentTurn()];
|
||||
|
||||
// Get this player's valid moves
|
||||
Integer[] validMoves = game.getLegalMoves();
|
||||
|
||||
// Get player's move, reask if Move is invalid
|
||||
// TODO: Limit amount of retries?
|
||||
int move = currentPlayer.getMove();
|
||||
while (!Arrays.asList(validMoves).contains(move)) {
|
||||
System.out.println("Invalid move");;
|
||||
move = currentPlayer.getMove();
|
||||
}
|
||||
|
||||
// Make move
|
||||
GameState state = game.play(move);
|
||||
drawMove(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
// Someone won
|
||||
} else if (state == GameState.DRAW) {
|
||||
// THere was a draw
|
||||
}
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUI(){
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,15 @@ package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.game.*;
|
||||
import org.toop.app.game.Players.ArtificialPlayer;
|
||||
import org.toop.app.game.Players.LocalPlayer;
|
||||
import org.toop.app.game.Players.Player;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.PlayerInfoWidget;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
import org.toop.app.widget.popup.ErrorPopup;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
import org.toop.game.TurnBasedGameThread;
|
||||
import org.toop.game.tictactoe.TicTacToeAIR;
|
||||
import org.toop.game.tictactoe.TicTacToeR;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
@@ -33,7 +36,7 @@ public class LocalMultiplayerView extends ViewWidget {
|
||||
}
|
||||
|
||||
switch (information.type) {
|
||||
case TICTACTOE -> new TurnBasedGameThread(new Player[]{new LocalPlayer(), new LocalPlayer()}, new TicTacToeR());
|
||||
case TICTACTOE -> new TurnBasedGameThread(new Player[]{new LocalPlayer(), new ArtificialPlayer<>(new TicTacToeAIR())}, new TicTacToeR());
|
||||
case REVERSI -> new ReversiGame(information);
|
||||
case CONNECT4 -> new Connect4Game(information);
|
||||
// case BATTLESHIP -> new BattleshipGame(information);
|
||||
|
||||
Reference in New Issue
Block a user