From c164daed53574babb26796b05682432709e2c5c1 Mon Sep 17 00:00:00 2001 From: mithe24 Date: Wed, 7 May 2025 17:11:58 +0200 Subject: Feature/json parser (#18) * chore(model/json-parser): Added maven dependency * chore(model): Removed old test JSON file * refactor(model/GameState): List better then map, entities should be able to overlap * feat(Pacman): Added GameState builder to initiate GameState with given paramters. Added a short example JSON-file, more key-value pairs needs to be added as the game progresses. Likewise the builder won't parse for any other key-value pair automatically. --- .../main/java/com/gr15/pacman/model/GameState.java | 15 +-- .../com/gr15/pacman/model/GameStateBuilder.java | 117 +++++++++++++++++++++ .../java/com/gr15/pacman/model/JsonParser.java | 36 ------- pacman/model/src/main/java/module-info.java | 1 + pacman/model/src/main/resources/maps/testmap.json | 20 ---- 5 files changed, 126 insertions(+), 63 deletions(-) create mode 100644 pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java delete mode 100644 pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java delete mode 100644 pacman/model/src/main/resources/maps/testmap.json (limited to 'pacman/model/src') diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java b/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java index ef33488..609bfc0 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java @@ -1,5 +1,6 @@ package com.gr15.pacman.model; +import java.util.List; import java.util.Map; import com.gr15.pacman.model.entities.Entity; @@ -15,15 +16,15 @@ public class GameState { private Board board; private Pacman pacman; - private Map entities; + private List entities; private Map items; private int score = 0; private int lives = 3; private double powerModeDuration = 0; - public GameState(Board board, Pacman pacman, - Map entities, Map items) { + protected GameState(Board board, Pacman pacman, + List entities, Map items) { this.board = board; this.entities = entities; this.items = items; @@ -42,7 +43,7 @@ public class GameState { powerModeDuration = Math.max(powerModeDuration, 0); /* updating and checking collisions with entities */ - entities.forEach((pos, entity) -> { + for (Entity entity : entities) { entity.move(board, deltaSeconds); if (EntityUtils.hasCollided(pacman, entity) && powerModeDuration == 0) { @@ -50,7 +51,7 @@ public class GameState { } else if (EntityUtils.hasCollided(pacman, entity)) { score += 100; } - }); + } /* checking collisions with items */ Items item = items.get(pacman.getPosition()); @@ -66,7 +67,7 @@ public class GameState { /* Getters and setters */ public Board getBoard() { return this.board; } public Pacman getPacman() { return this.pacman; } - public Map getEntities() { return this.entities; } + public List getEntities() { return this.entities; } public Map getItems() { return this.items; } public int getScore() { return this.score; } public int getLives() { return this.lives; } @@ -79,7 +80,7 @@ public class GameState { public void setItems(Map newItems) { this.items = newItems; } - public void setEntities(Map newEntities) { + public void setEntities(List newEntities) { this.entities = newEntities; } } diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java b/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java new file mode 100644 index 0000000..aab7dd9 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java @@ -0,0 +1,117 @@ +package com.gr15.pacman.model; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +import com.gr15.pacman.model.Board.Direction; +import com.gr15.pacman.model.Board.TileType; +import com.gr15.pacman.model.entities.Entity; +import com.gr15.pacman.model.entities.Ghost; +import com.gr15.pacman.model.entities.Items; +import com.gr15.pacman.model.entities.Pacman; + +/** + * Utility class to build a {@link GameState} object from a JSON configuration. + * + *

+ * This class provides static methods to parse game data such as the board, + * entities, and items from a JSON input stream and use it to initialize + * a game state. It handles parsing logic and translates string representations + * into model objects used by the game engine. + *

+ */ +public class GameStateBuilder { + + /** + Parses a JSON input stream and constructs a {@link GameState} based on the configuration. + *

+ * Expected JSON structure includes: + *

    + *
  • {@code pacmanSpawnPoint}: an array of two integers + * representing the X and Y coordinates.
  • + *
  • {@code board}: a 2D array of strings + * representing the board tiles ("W" for wall, "E" for empty).
  • + *
  • {@code pacman}: a JSON object containing properties + * such as {@code x}, {@code y}, {@code speed}, and {@code radius}.
  • + *
+ * + * @param inputStream the input stream of the JSON file. + * @return a {@link GameState} object built from the JSON configuration. + * @throws RuntimeException if the JSON is invalid or the file cannot be read. + */ + public static GameState fromJson(InputStream inputStream) { + /* Reader gets closed automatically, + * because it's in the resources part of a try-with-resource statement. + * The InputStream gets closed by Reader */ + try (InputStreamReader reader = new InputStreamReader(inputStream)) { + JSONTokener tokener = new JSONTokener(reader); + JSONObject jsonObject = new JSONObject(tokener); + return buildFromJsonObject(jsonObject); + } catch (JSONException jsonException) { + throw new RuntimeException(""" + Failed to parse JSON content. + Please ensure the file contains valid JSON.""", jsonException); + } catch (IOException ioException) { + throw new RuntimeException(""" + Error reading JSON file. + Ensure the file exists and is accessible""", ioException); + } + } + + /** + * Internal helper method that constructs a {@link GameState} object + * from a given {@link JSONObject}. + * + *

+ * This method extracts the board layout, Pacman parameters, + * and initializes the entities and items. + * + * @param jsonObject the JSON object containing game configuration data. + * @return a fully constructed {@link GameState} object. + * @throws RuntimeException if required fields are missing or incorrectly formatted. + + */ + private static GameState buildFromJsonObject(JSONObject jsonObject) { + try { + JSONArray stringBoard = jsonObject.getJSONArray("board"); + TileType[][] tileBoard = new TileType + [stringBoard.length()] + [stringBoard.getJSONArray(0).length()]; + for (int y = 0; y < stringBoard.length(); y++) { + JSONArray row = stringBoard.getJSONArray(y); + for (int x = 0; x < row.length(); x++) { + switch (row.getString(x)) { + case "W" -> tileBoard[y][x] = TileType.WALL; + case "E" -> tileBoard[y][x] = TileType.EMPTY; + default -> {} + } + } + } + Board board = new Board(tileBoard[0].length, tileBoard.length, tileBoard); + + JSONObject pacmanJsonObject = jsonObject.getJSONObject("pacman"); + double speed = pacmanJsonObject.getDouble("speed"); + double radius = pacmanJsonObject.getDouble("radius"); + Position pacmanStartPos = new Position( + pacmanJsonObject.getInt("x"), + pacmanJsonObject.getInt("y")); + Pacman pacman = new Pacman(pacmanStartPos, speed, Direction.NONE, radius); + + ArrayList entities = new ArrayList<>(); + Map items = new HashMap<>(); + + return new GameState(board, pacman, entities, items); + } catch (JSONException jsonException) { + throw new RuntimeException("Failed to parse GameState json", jsonException); + } + } +} diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java b/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java deleted file mode 100644 index 990fb15..0000000 --- a/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gr15.pacman.model; - -import java.util.HashMap; -import java.util.Map; - -import com.gr15.pacman.model.entities.Entity.Direction; -import com.gr15.pacman.model.Board.TileType; -import com.gr15.pacman.model.entities.Entity; -import com.gr15.pacman.model.entities.Pacman; -import com.gr15.pacman.model.entities.Items; - -/** - * jsonParser - */ -public final class JsonParser { - - public static GameState getGameState(String path) { - TileType[][] tileBoard = { - {TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, - {TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL,}, - }; - Board board = new Board(8, 5, tileBoard); - Pacman pacman = new Pacman(new Position(1, 1), 3.0, Direction.NONE, 1); - Map entities = new HashMap<>(); - Map items = new HashMap<>(); - - return new GameState(board, pacman, entities, items); - } - -} diff --git a/pacman/model/src/main/java/module-info.java b/pacman/model/src/main/java/module-info.java index 95d9324..5a7d26d 100644 --- a/pacman/model/src/main/java/module-info.java +++ b/pacman/model/src/main/java/module-info.java @@ -3,6 +3,7 @@ */ module com.gr15.pacman.model { requires transitive javafx.controls; + requires org.json; exports com.gr15.pacman.model; exports com.gr15.pacman.model.entities; } diff --git a/pacman/model/src/main/resources/maps/testmap.json b/pacman/model/src/main/resources/maps/testmap.json deleted file mode 100644 index 547f48f..0000000 --- a/pacman/model/src/main/resources/maps/testmap.json +++ /dev/null @@ -1,20 +0,0 @@ - -{ - "spooky": true, - "pacManSpawn": [ - { - "x": 1, - "y": 1 - } - ], - "tileBoard": [ - "x","x","x","x","x", - "x","e","e","e","x", - "x","e","x","e","x", - "x","e","e","e","x", - "x","x","e","x","x", - "x","e","e","e","x", - "x","x","e","x","x", - "x","x","x","x","x" - ] -} -- cgit v1.2.3-70-g09d2