From c37ee0c5f701089803515e4b0450413ad29486bb Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Mon, 1 May 2023 14:32:22 +1000 Subject: [PATCH] game: Added player actions --- src/comp1110/ass2/BlueLagoon.java | 3 +- src/comp1110/ass2/Player.java | 10 ++ src/comp1110/ass2/Resource.java | 21 ++++ src/comp1110/ass2/State.java | 12 ++ src/comp1110/ass2/gui/Game.java | 175 +++++++++++++++++++++++++++--- 5 files changed, 203 insertions(+), 18 deletions(-) diff --git a/src/comp1110/ass2/BlueLagoon.java b/src/comp1110/ass2/BlueLagoon.java index 9ef9097..2e279f5 100644 --- a/src/comp1110/ass2/BlueLagoon.java +++ b/src/comp1110/ass2/BlueLagoon.java @@ -307,8 +307,7 @@ public class BlueLagoon { !isAdjacent(moveCoords, playerVillageCoords)) return false; } } - System.out.println(coordsContainer); - return true; + return true; } private static boolean isAdjacent(String centerCoords, ArrayList coordsContainer) { diff --git a/src/comp1110/ass2/Player.java b/src/comp1110/ass2/Player.java index 2333b62..961616d 100644 --- a/src/comp1110/ass2/Player.java +++ b/src/comp1110/ass2/Player.java @@ -20,6 +20,7 @@ public class Player { private int numStatuette; private Coord[] settlers; private Coord[] villages; + private Coord lastMove; /** * Constructor for Player class @@ -36,6 +37,7 @@ public class Player { this.numStatuette = 0; this.settlers = new Coord[0]; this.villages = new Coord[0]; + lastMove = new Coord(-1, -1); } // endregion // region Getters and Setters @@ -151,6 +153,7 @@ public class Player { } newSettlers[settlers.length] = coord; settlers = newSettlers; + lastMove = coord; } /** @@ -169,6 +172,7 @@ public class Player { } newVillages[villages.length] = coord; villages = newVillages; + lastMove = coord; } /** @@ -224,6 +228,10 @@ public class Player { return numPieces; } + public Coord getLastMove() { + return lastMove; + } + // endregion /** @@ -259,6 +267,7 @@ public class Player { int x = Integer.parseInt(coordStr.split(",")[0]); int y = Integer.parseInt(coordStr.split(",")[1]); Coord coord = new Coord(x, y); + lastMove = coord; state.placePiece(coord, pieceType); state.nextPlayer(); return; @@ -309,6 +318,7 @@ public class Player { int x = Integer.parseInt(coordStr.split(",")[0]); int y = Integer.parseInt(coordStr.split(",")[1]); Coord coord = new Coord(x, y); + lastMove = coord; state.placePiece(coord, pieceType); state.nextPlayer(); } diff --git a/src/comp1110/ass2/Resource.java b/src/comp1110/ass2/Resource.java index 372e8cb..84d2b43 100644 --- a/src/comp1110/ass2/Resource.java +++ b/src/comp1110/ass2/Resource.java @@ -30,6 +30,27 @@ public class Resource { return type; } + /** + * Get the type of the resource + * @return String type of the resource + */ + public String getTypeString() { + switch (type){ + case 'C': + return "Coconut"; + case 'B': + return "Bamboo"; + case 'W': + return "Water"; + case 'P': + return "Precious Stone"; + case 'S': + return "Statuette"; + default: + return "Invalid"; + } + } + /** * Get the coordinate of the resource * @return Coord coordinate of the resource diff --git a/src/comp1110/ass2/State.java b/src/comp1110/ass2/State.java index 592e35d..807c5e7 100644 --- a/src/comp1110/ass2/State.java +++ b/src/comp1110/ass2/State.java @@ -394,6 +394,18 @@ public class State { } } + /** + * Is move valid? + * @param coord Coord coordinate to place piece + * @param type char type of piece + * @return boolean true if move is valid + */ + public boolean isMoveValid(Coord coord, char type){ + // Create moveString + String moveString = type + " " + coord.toString(); + return BlueLagoon.isMoveValid(this.toString(), moveString); + } + /** * is the phase over? * Defaults to simple mode diff --git a/src/comp1110/ass2/gui/Game.java b/src/comp1110/ass2/gui/Game.java index 181d143..be1ae98 100644 --- a/src/comp1110/ass2/gui/Game.java +++ b/src/comp1110/ass2/gui/Game.java @@ -1,9 +1,6 @@ package comp1110.ass2.gui; -import comp1110.ass2.Coord; -import comp1110.ass2.Island; -import comp1110.ass2.Player; -import comp1110.ass2.State; +import comp1110.ass2.*; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; @@ -22,8 +19,6 @@ import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import javafx.stage.Stage; -// FIXME Task 14 -// FIXME Task 15 public class Game extends Application { // region Variables @@ -35,13 +30,18 @@ public class Game extends Application { State currentGame; String message; + Boolean messageError; + + Coord selectedTile; // endregion @Override public void start(Stage stage) throws Exception { + selectedTile = new Coord(-1,-1); message = "Waiting for Move..."; + messageError = false; Scene scene = new Scene(this.root, WINDOW_WIDTH, WINDOW_HEIGHT); // From Viewer @@ -68,6 +68,8 @@ public class Game extends Application { Button threePlayer = new Button("3 Player"); Button fourPlayer = new Button("4 Player"); Button AIMove = new Button("AI Move"); + Button placeVillage = new Button("Place Village"); + Button placeSettler = new Button("Place Settler"); twoPlayer.setOnAction(new EventHandler() { @@ -96,8 +98,22 @@ public class Game extends Application { } }); + placeVillage.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent e) { + doMove(1); + } + }); + + placeSettler.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent e) { + doMove(0); + } + }); + HBox hb = new HBox(); - hb.getChildren().addAll(newLabel, twoPlayer,threePlayer,fourPlayer,AIMove); + hb.getChildren().addAll(newLabel, twoPlayer,threePlayer,fourPlayer,AIMove,placeVillage,placeSettler); hb.setSpacing(10); hb.setLayoutX(50); hb.setLayoutY(WINDOW_HEIGHT - 50); @@ -128,17 +144,68 @@ public class Game extends Application { // region Game Play - - void doMove(){ - - + + /** + * Do a move of the given type + * @param type the type of move 0 = place settler, 1 = place village + */ + void doMove(int type){ + if (selectedTile.equals(new Coord(-1,-1))){ + sendMessage("No tile selected"); + return; + } + if (currentGame.isPhaseOver()){ + sendMessage("Phase is over"); + return; + } + else { + char typeC = 'S'; + if (type == 1){ + typeC = 'T'; + } + if (currentGame.isMoveValid(selectedTile,typeC)){ + currentGame.placePiece(selectedTile,typeC); + Player player = currentGame.getCurrentPlayer(); + Coord lastMove = player.getLastMove(); + if (currentGame.isStone(lastMove)){ + for (Resource resource : currentGame.getResources()) { + if (resource.getCoord().equals(lastMove) ) { + sendMessage("Player " + player.getPlayerID() +" picked up a " + resource.getTypeString().toLowerCase()); + } + } + } + currentGame.nextPlayer(); + selectedTile = new Coord(-1,-1); + } + else { + sendMessage("Invalid move",true); + } + } + + refresh(); } + + /** + * Do an AI move for the current player + */ void doAIMove(){ if (!currentGame.isPhaseOver()){ - currentGame.getCurrentPlayer().doAIMove(currentGame); + Player player = currentGame.getCurrentPlayer(); + player.doAIMove(currentGame); + if (currentGame.isPhaseOver()){ sendMessage("Phase is over"); } + if (!player.getLastMove().equals(new Coord(-1,-1))){ + Coord lastMove = player.getLastMove(); + if (currentGame.isStone(lastMove)){ + for (Resource resource : currentGame.getResources()) { + if (resource.getCoord().equals(lastMove) ) { + sendMessage("Player " + player.getPlayerID() +" picked up a " + resource.getTypeString().toLowerCase()); + } + } + } + } refresh(); } else { @@ -146,17 +213,37 @@ public class Game extends Application { } } // endregion - + // region HID + /** + * Send a message to the user without error + * @param message the message to send + */ void sendMessage(String message){ sendMessage(message, false); } + + /** + * Send a message to the user + * @param message the message to send + * @param error if the message is an error + */ void sendMessage(String message, boolean error){ this.message = message; + messageError = error; + refresh(); + } + + void tileClick(String coordString){ + + int y = Integer.parseInt(coordString.split(",")[0]); + int x = Integer.parseInt(coordString.split(",")[1]); + + selectedTile = new Coord(y,x); + sendMessage("Tile " + selectedTile.toString() + " selected"); refresh(); } - // endregion @@ -171,11 +258,17 @@ public class Game extends Application { messageLabel.setLayoutX(50); messageLabel.setLayoutY(50); messageLabel.setFont(Font.font("Sans Serif",FontWeight.BOLD, 20)); + if (messageError){ + messageLabel.setTextFill(Color.RED); + } + else { + messageLabel.setTextFill(Color.BLACK); + } + root.getChildren().add(messageLabel); // Intizialiation of the grid GridPane viewerGrid = new GridPane(); - String[] parts = currentGame.toString().split("; ?"); int boardHeight = 0; int boardHeightPx = 0; int tileSize = 0; @@ -273,9 +366,13 @@ public class Game extends Application { viewerGrid.relocate((WINDOW_WIDTH/2-viewerGrid.getPrefWidth()/2), ((WINDOW_HEIGHT+100)/2-viewerGrid.getPrefHeight()/2)); root.getChildren().add(viewerGrid); + // Add selected tile + if (!selectedTile.equals(new Coord(-1,-1))){ + addTileSelector(viewerGrid, tileSize, selectedTile.toString()); + } + // Move buttons to front controls.toFront(); - } // Generating the big board tiles such as the water tiles and the island tiles @@ -292,6 +389,12 @@ public class Game extends Application { // Translate the whole tile's Y axis downwards so they connect and there's no gap hex.setTranslateY(Integer.parseInt(coords[0]) * -0.25 * tileSize); board.add(hex, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + + // Add a mouse click event to the tile + hex.setOnMouseClicked(event -> { + tileClick(coordString); + }); + } // Generating the small tiles such as resources, stones, etc @@ -312,6 +415,11 @@ public class Game extends Application { // Translate the tile so they look center hex.setTranslateX(7 + hex.getTranslateX()); board.add(hex, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + + // Add a mouse click event to the tile + hex.setOnMouseClicked(event -> { + tileClick(coordString); + }); } void addTileToBoard(GridPane board, int tileSize, String coordString, Color color) { @@ -331,6 +439,11 @@ public class Game extends Application { // Translate the tile so they look center hex.setTranslateX(12 + hex.getTranslateX()); board.add(hex, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + + // Add a mouse click event to the tile + hex.setOnMouseClicked(event -> { + tileClick(coordString); + }); } // Adding labels to the resources tiles and stones tiles @@ -349,6 +462,11 @@ public class Game extends Application { // Making the label center newLabel.setTranslateX(19.5 + newLabel.getTranslateX()); board.add(newLabel, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + + // Add a mouse click event to the tile + newLabel.setOnMouseClicked(event -> { + tileClick(coordString); + }); } // Adding labels to the villagers and settlers @@ -367,6 +485,31 @@ public class Game extends Application { // Making the label center newLabel.setTranslateX(11 + newLabel.getTranslateX()); board.add(newLabel, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + // Add a mouse click event to the tile + newLabel.setOnMouseClicked(event -> { + tileClick(coordString); + }); + } + void addTileSelector(GridPane board, int tileSize, String coordString){ + // If the string empty, stop the function + if (coordString.equals("")) return; + String[] coords = coordString.split(","); + Label newLabel = new Label("X"); + newLabel.setFont(Font.font("Sans Serif", 20)); + + // Following the tile's pos format + if (Integer.parseInt(coords[0]) % 2 == 0) newLabel.setTranslateX(tileSize/2); + newLabel.setTranslateY(Integer.parseInt(coords[0]) * -0.25 * tileSize); + + // Making the label center + newLabel.setTranslateX(17 + newLabel.getTranslateX()); + newLabel.setTextFill(Color.RED); + + board.add(newLabel, Integer.parseInt(coords[1]), Integer.parseInt(coords[0])); + // Add a mouse click event to the tile + newLabel.setOnMouseClicked(event -> { + tileClick(coordString); + }); } // A hexagon nested class shape