From 8ed19d75bda7b912757ab26343be1ad5a6542e4c Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Mon, 24 Apr 2023 16:56:31 +1000 Subject: [PATCH] state: Added more scoring and turn actions --- src/comp1110/ass2/Player.java | 44 ++++++++++ src/comp1110/ass2/State.java | 125 +++++++++++++++++++++++++---- tests/comp1110/ass2/StateTest.java | 16 +++- 3 files changed, 169 insertions(+), 16 deletions(-) diff --git a/src/comp1110/ass2/Player.java b/src/comp1110/ass2/Player.java index eb9a903..e9ae6ce 100644 --- a/src/comp1110/ass2/Player.java +++ b/src/comp1110/ass2/Player.java @@ -1,5 +1,8 @@ package comp1110.ass2; +import java.util.Random; +import java.util.Set; + /** * Player class * This class is used to store the information of a player @@ -231,6 +234,47 @@ public class Player { return numPieces; } + /** + * Check if player is able to do any moves + * @return true if player can do any moves, false otherwise + */ + public boolean canPlay(State state) { + Set validMoves = BlueLagoon.generateAllValidMoves(state.toString()); + return validMoves.size() > 0; + } + + /** + * Do a Random Move + * @param state State to do the move on + */ + public void doRandomMove(State state) { + if (state.getCurrentPlayerID() != playerID) { + return; + } + Set validMoves = BlueLagoon.generateAllValidMoves(state.toString()); + if (validMoves.size() == 0) { + return; + } + Random rand = new Random(); + int randomMove = rand.nextInt(0, validMoves.size()); + int i = 0; + for (String move : validMoves) { + if (i == randomMove) { + char pieceType = move.charAt(0); + String coordStr = move.substring(2); + int x = Integer.parseInt(coordStr.split(",")[0]); + int y = Integer.parseInt(coordStr.split(",")[1]); + Coord coord = new Coord(x, y); + state.placePiece(coord, pieceType); + state.nextPlayer(); + return; + } + i++; + } + } + + + @Override public String toString() { String str = "p " + playerID + " " + score + " " + numCoconuts + " " + numBamboo + " " + numWater + " " + numPreciousStones + " " + numStatuette + " S"; diff --git a/src/comp1110/ass2/State.java b/src/comp1110/ass2/State.java index 75ba6b1..1b98ec1 100644 --- a/src/comp1110/ass2/State.java +++ b/src/comp1110/ass2/State.java @@ -228,19 +228,29 @@ public class State { } /** - * Get the current player + * Get the current player ID * @return int current player */ - public int getCurrentPlayer() { + public int getCurrentPlayerID() { return currentPlayer; } + /** + * Get the current player + * @return Player current player + */ + public Player getCurrentPlayer() { + return players[currentPlayer]; + } + /** * Get the current phase + * Returns 'E' for exploration, 'S' for settlement, 'O' for game over * @return char current phase */ public char getCurrentPhase() { if (currentPhase == 0) return 'E'; - else return 'S'; + else if (currentPhase == 1) return 'S'; + else return 'O'; // Return 'O' for game over } /** @@ -340,16 +350,6 @@ public class State { if (currentPlayer >= numPlayers) currentPlayer = 0; } - /** - * Start next phase. - * This handles changing the current player and scoring - */ - public void nextPhase() { - currentPhase++; - if (currentPhase > 1) currentPhase = 0; - nextPlayer(); - } - /** * Place a piece on the board. Uses current turn's player * @param coord Coord coordinate to place piece @@ -374,9 +374,54 @@ public class State { } } + /** + * is the phase over? + */ + public boolean isPhaseOver() { + + boolean resourcesLeft = false; + for (Resource r : resources) { + if (!r.isClaimed() && r.getType() != 'S') resourcesLeft = true; + } + + boolean moveLeft = false; + for (Player player : players) { + if (player.canPlay(this)) moveLeft = true; + } + + return !resourcesLeft || !moveLeft; + } + + + // endregion // region Scoring + + /** + * Score for that phase + */ + public void scorePhase() { + for (Player p: players) { + p.addScore(createScore(p.getPlayerID())); + } + if (getCurrentPhase() == 'E') { + currentPhase++; + } + else { + // Game over + finalScore(); + currentPhase++; + } + } + + /** + * Final score + * + */ + public void finalScore() { + + } /** * Get score of player ID based on current phase and game state * @param playerID int player ID base 0 @@ -465,12 +510,64 @@ public class State { return score; } + /** + * Score Links + * A (potentially) branching path of neighbouring settlers and villages + * belonging to a player forms a chain. Players earn points from the chain + * of their pieces which links the most islands. Players earn 5 points + * per linked island in this chain. + * @param playerID int player to score + * @return int score + */ + public int scoreLinks(int playerID) { + int score = 0; + return score; //! TODO + } + + /** + * Score resources + * @param playerID int player to score + * @return int score + */ + public int scoreResources(int playerID) { + int score = 0; + char[] resourceTypes = {'C', 'B', 'W', 'P'}; + for (char type : resourceTypes) { + int numResources = players[playerID].getNumResource(type); + if (numResources >= 4) { + score += 20; + } else if (numResources == 3) { + score += 10; + } else if (numResources == 2) { + score += 5; + } + } + int numCoconuts = players[playerID].getNumResource('C'); + int numBananas = players[playerID].getNumResource('B'); + int numWater = players[playerID].getNumResource('W'); + int numPreciousStones = players[playerID].getNumResource('P'); + if (numCoconuts >= 1 && numBananas >= 1 && numWater >= 1 && numPreciousStones >= 1) { + score += 10; + } + return score; + } + + /** + * Score statuettes + * @param playerID int player to score + * @return int score + */ + public int scoreStatuettes(int playerID) { + int score = 0; + return score; //! TODO + } + // endregion @Override public String toString() { - String str = "a " + boardHeight + " " + getNumPlayers() + "; c " + getCurrentPlayer() + " " + getCurrentPhase() + "; "; + String str = "a " + boardHeight + " " + getNumPlayers() + "; c " + getCurrentPlayerID() + " " + getCurrentPhase() + "; "; for (Island island : islands) { str += island.toString() + " "; } diff --git a/tests/comp1110/ass2/StateTest.java b/tests/comp1110/ass2/StateTest.java index 2d02d1b..9fda78e 100644 --- a/tests/comp1110/ass2/StateTest.java +++ b/tests/comp1110/ass2/StateTest.java @@ -15,7 +15,7 @@ public class StateTest { State state = new State(GameDataLoader.DEFAULT_GAME); Assertions.assertEquals(13, state.getBoardHeight(), "The test failed because the board length is not 13"); Assertions.assertEquals(2, state.getNumPlayers(), "The test failed because the number of players is not 2"); - Assertions.assertEquals(0, state.getCurrentPlayer(), "The test failed because the current player is not 0"); + Assertions.assertEquals(0, state.getCurrentPlayerID(), "The test failed because the current player is not 0"); Assertions.assertEquals('E', state.getCurrentPhase(), "The test failed because the current phase is not E"); Assertions.assertEquals(GameDataLoader.DEFAULT_GAME,state.toString(), "The test failed because the state created from the string is not the same as the state created from the string"); @@ -56,7 +56,6 @@ public class StateTest { // Distribute resources state.distributeResources(); Resource toClaim = state.getUnclaimedResource(new Coord(0,0)); - System.out.println(toClaim); // Place a settler at (0,0) state.placePiece(new Coord(0,0), 'S'); @@ -71,6 +70,19 @@ public class StateTest { public void testStateWHEELSGAME(){ State state = new State(GameDataLoader.WHEELS_GAME); Assertions.assertEquals(GameDataLoader.WHEELS_GAME,state.toString(), "The test failed because the state created from the string is not the same as the state created from the string"); + + state.distributeResources(); + Assertions.assertFalse(state.isPhaseOver(), "The test failed because the phase is over even though it should not be because the phase is not over"); + + // Test endPhase + while (!state.isPhaseOver()) { + if (!state.getCurrentPlayer().canPlay(state)) state.nextPlayer(); + state.getCurrentPlayer().doRandomMove(state); + } + state.scorePhase(); + System.out.println(state); + + } }