From 05a63e03992bb93d7b575f05d169fd50a5f77cd8 Mon Sep 17 00:00:00 2001 From: RaffaeleMorganti Date: Sun, 20 Nov 2022 14:11:58 +0100 Subject: [PATCH] some attribute visibility improvements, added sonar-scanner to maven, bug fix --- pom.xml | 54 ++++- .../java/com/github/dtschust/zork/Zork.java | 192 ++++++++---------- .../dtschust/zork/ZorkConditionHas.java | 17 +- .../dtschust/zork/ZorkConditionStatus.java | 2 +- .../com/github/dtschust/zork/ZorkTrigger.java | 13 +- .../github/dtschust/zork/parser/ZorkGame.java | 113 ++++++++--- .../dtschust/zork/parser/ZorkReader.java | 89 ++++---- .../dtschust/zork/types/ZorkContainer.java | 19 +- .../dtschust/zork/types/ZorkCreature.java | 13 +- .../github/dtschust/zork/types/ZorkItem.java | 11 +- .../dtschust/zork/types/ZorkObject.java | 22 +- .../github/dtschust/zork/types/ZorkRoom.java | 15 +- .../com/github/dtschust/zork/ZorkTest.java | 2 +- 13 files changed, 336 insertions(+), 226 deletions(-) diff --git a/pom.xml b/pom.xml index 941ec50..39b0f81 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.junit.jupiter junit-jupiter - RELEASE + 5.9.1 test @@ -64,6 +64,58 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M7 + + + org.junit.jupiter + junit-jupiter-engine + 5.4.0 + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.9.1.2184 + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + + coverage + + true + + + + + org.jacoco + jacoco-maven-plugin + + + prepare-agent + + prepare-agent + + + + report + + report + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/github/dtschust/zork/Zork.java b/src/main/java/com/github/dtschust/zork/Zork.java index 0f2423c..2c9d7bb 100644 --- a/src/main/java/com/github/dtschust/zork/Zork.java +++ b/src/main/java/com/github/dtschust/zork/Zork.java @@ -18,39 +18,32 @@ import static java.util.Map.entry; /* And away we go*/ public class Zork { public String userInput; - public String currentRoom; + public ZorkGame game; Scanner source = new Scanner(System.in); public Zork(String filename) { + game = new ZorkReader(filename).build(); - ZorkReader reader = new ZorkReader(filename); - - game = reader.build(); - /*Phew, we're finally done with that ... let's get playing!!*/ - - /* Some temporary initialization variables*/ - currentRoom = "Entrance"; - boolean ended = false; - + game.changeRoom("Entrance"); /* Print out the first entrance description, starting the game!*/ - System.out.println(game.Rooms.get(currentRoom).description); + System.out.println(game.getCurrentRoom().description); /* There is no stopping in Zork, until we're done!!*/ - do { + while(game.isRunning()) { userInput = source.nextLine(); /*Now that we have the user command, check the input*/ if (!executeTriggers()) { /* If we haven't skipped, perform the user action*/ - ended = executeAction(userInput); + executeAction(userInput); /* Clear the user input, and check the triggers again (various states have changed, gnomes need to be found!*/ userInput = ""; executeTriggers(); } - } while (!ended); + } // single point of termination System.exit(0); @@ -66,7 +59,7 @@ public class Zork { new Zork(args[0]); } - public boolean executeAction(String input) { + public void executeAction(String input) { String[] action = input.split(" "); /* Update: figure out what type of item it is, and then change it's status*/ if (action[0].equals("Update")) { @@ -74,7 +67,7 @@ public class Zork { } /*Game Over: pretty straight forward*/ else if (input.equals("Game Over")) { - return doActionGameWon(); + doActionGameWon(); } /* Add: figure out what type the destination is, then what type the object is. Then add object to destination if it makes sense */ else if (action[0].equals("Add")) { @@ -100,7 +93,7 @@ public class Zork { } /* Open Exit (you should be so lucky)*/ else if (input.equals("open exit")) { - return doActionOpenExit(); + doActionOpenExit(); } /* Open a container */ else if (action[0].equals("open") && action.length > 1) { @@ -128,20 +121,19 @@ public class Zork { } /* Invalid command*/ else System.out.println("Error"); - return false; } - private boolean doActionGameWon() { + private void doActionGameWon() { System.out.println("Victory!"); - return true; + game.setGameOver(); } private void doActionAdd(String object, String destination) { String objectType; - objectType = game.ObjectLookup.get(object); - String destinationType = game.ObjectLookup.get(destination); + objectType = game.getTypeFromLookup(object); + String destinationType = game.getTypeFromLookup(destination); if (destinationType.equals("room")) { - ZorkRoom tempRoom = game.Rooms.get(destination); + ZorkRoom tempRoom = (ZorkRoom) game.get("room", destination); if (objectType.equals("item")) tempRoom.item.add(object); else if (objectType.equals("creature")) @@ -150,61 +142,55 @@ public class Zork { tempRoom.container.add(object); else System.out.println("Error"); - game.Rooms.put(tempRoom); + game.put("room", tempRoom); } else if (destinationType.equals("container")) { - ZorkContainer tempContainer = game.Containers.get(destination); + ZorkContainer tempContainer = (ZorkContainer) game.get("container", destination); if (objectType.equals("item")) tempContainer.item.add(object); else System.out.println("Error"); - game.Containers.put(tempContainer); + game.put("container", tempContainer); } else { System.out.println("Error"); } } private void doActionDelete(String object) { - String objectType; - objectType = game.ObjectLookup.get(object); + String objectType = game.getTypeFromLookup(object); if (objectType.equals("room")) { - for (String key : game.Rooms.keySet()) { - ZorkRoom tempRoom = game.Rooms.get(key); - for (String key2 : tempRoom.border.keySet()) { - if (tempRoom.border.get(key2).equals(object)) { - tempRoom.border.remove(key2); + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { + for (String key : tempRoom.border.keySet()) { + if (tempRoom.border.get(key).equals(object)) { + tempRoom.border.remove(key); } } - game.Rooms.put(tempRoom); + game.put("room", tempRoom); } } else if (objectType.equals("item")) { - for (String key : game.Rooms.keySet()) { - ZorkRoom tempRoom = game.Rooms.get(key); + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { if (tempRoom.item.contains(object)) { tempRoom.item.remove(object); - game.Rooms.put(tempRoom); + game.put("room", tempRoom); } } - for (String key : game.Containers.keySet()) { - ZorkContainer tempContainer = game.Containers.get(key); + for (ZorkContainer tempContainer : (Iterable) game.values("container")) { if (tempContainer.item.contains(object)) { tempContainer.item.remove(object); - game.Containers.put(tempContainer); + game.put("container", tempContainer); } } } else if (objectType.equals("container")) { - for (String key : game.Rooms.keySet()) { - ZorkRoom tempRoom = game.Rooms.get(key); + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { if (tempRoom.container.contains(object)) { tempRoom.container.remove(object); - game.Rooms.put(tempRoom); + game.put("room", tempRoom); } } } else if (objectType.equals("creature")) { - for (String key : game.Rooms.keySet()) { - ZorkRoom tempRoom = game.Rooms.get(key); + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { if (tempRoom.creature.contains(object)) { tempRoom.creature.remove(object); - game.Rooms.put(tempRoom); + game.put("room", tempRoom); } } } @@ -213,15 +199,14 @@ public class Zork { private void doActionUpdate(String object, String newStatus) { ZorkMap collection = (ZorkMap) game.getListThroughLookup(object); ZorkObject tempObject = collection.get(object); - tempObject.status = newStatus; + tempObject.updateStatus(newStatus); collection.put(tempObject); } private void doActionAttack(String tempString, String weapon) { - ZorkCreature tempCreature; - if (game.Rooms.get(currentRoom).creature.contains(tempString)) { - tempCreature = game.Creatures.get(tempString); - if (tempCreature != null && game.Inventory.contains(weapon)) { + if (game.getCurrentRoom().creature.contains(tempString)) { + ZorkCreature tempCreature = (ZorkCreature) game.get("creature", tempString); + if (tempCreature != null && game.inventory.contains(weapon)) { if (tempCreature.attack(this, weapon)) { System.out.println("You assault the " + tempString + " with the " + weapon + "."); for (String print: tempCreature.print) { @@ -238,8 +223,8 @@ public class Zork { } private void doActionTurnOn(String tempString) { - if (game.Inventory.contains(tempString)) { - ZorkItem tempItem = game.Items.get(tempString); + if (game.inventory.contains(tempString)) { + ZorkItem tempItem = (ZorkItem) game.get("item", tempString); System.out.println("You activate the " + tempString + "."); if (tempItem != null) { for (String print: tempItem.turnOnPrint) { @@ -255,11 +240,11 @@ public class Zork { } private void doActionPutItem(String tempString, String destination) { - if (game.Rooms.get(currentRoom).container.contains(destination)){ - if(game.Containers.get(destination).isOpen && game.Inventory.contains(tempString)) { - ZorkContainer tempContainer = game.Containers.get(destination); + if (game.getCurrentRoom().container.contains(destination)){ + ZorkContainer tempContainer = (ZorkContainer) game.get("container", destination); + if(tempContainer.isOpen() && game.inventory.contains(tempString)) { tempContainer.item.add(tempString); - game.Inventory.remove(tempString); + game.inventory.remove(tempString); System.out.println("Item " + tempString + " added to " + destination + "."); return; } @@ -268,11 +253,11 @@ public class Zork { } private void doActionDropItem(String tempString) { - if (game.Inventory.contains(tempString)) { - ZorkRoom tempRoom = game.Rooms.get(currentRoom); + if (game.inventory.contains(tempString)) { + ZorkRoom tempRoom = game.getCurrentRoom(); tempRoom.item.add(tempString); - game.Rooms.put(tempRoom); - game.Inventory.remove(tempString); + game.put("room", tempRoom); + game.inventory.remove(tempString); System.out.println(tempString + " dropped."); } else { System.out.println("Error"); @@ -280,9 +265,9 @@ public class Zork { } private void doActionReadObject(String tempString) { - if (game.Inventory.contains(tempString)) { - ZorkItem tempItem = game.Items.get(tempString); - if (tempItem.writing != null && tempItem.writing != "") { + if (game.inventory.contains(tempString)) { + ZorkItem tempItem = (ZorkItem) game.get("item", tempString); + if (tempItem.writing != null && !tempItem.writing.isEmpty()) { System.out.println(tempItem.writing); } else { System.out.println("Nothing written."); @@ -294,13 +279,13 @@ public class Zork { private void doActionOpenContainer(String tempString) { ZorkContainer tempContainer; - if (game.Rooms.get(currentRoom).container.contains(tempString)) { - tempContainer = game.Containers.get(tempString); - tempContainer.isOpen = true; - String output = ""; + if (game.getCurrentRoom().container.contains(tempString)) { + tempContainer = (ZorkContainer) game.get("container", tempString); + tempContainer.open(); if (tempContainer.item.isEmpty()) { System.out.println(tempString + " is empty"); } else { + String output = ""; System.out.print(tempString + " contains "); for (String key : tempContainer.item) { output += key + ", "; @@ -313,13 +298,13 @@ public class Zork { } } - private boolean doActionOpenExit() { - if (game.Rooms.get(currentRoom).type.equals("exit")) { + private void doActionOpenExit() { + if (game.getCurrentRoom().type.equals("exit")) { System.out.println("Game Over"); - return true; + game.setGameOver(); + } else { + System.out.println("Error"); } - System.out.println("Error"); - return false; } /*Basic movement function */ @@ -331,10 +316,8 @@ public class Zork { entry("w", "west") ); - String destination = (game.Rooms.get(currentRoom)).border.get(fullDirections.get(direction)); - if (destination != null) { - currentRoom = destination; - System.out.println(game.Rooms.get(currentRoom).description); + if (game.changeRoom(game.getCurrentRoom().border.get(fullDirections.get(direction)))) { + System.out.println(game.getCurrentRoom().description); } else { System.out.println("Can't go that way."); } @@ -344,10 +327,10 @@ public class Zork { /* Print out the inventory when user types i */ private void doActionInventory() { String output = "Inventory: "; - if (game.Inventory.isEmpty()) { + if (game.inventory.isEmpty()) { System.out.println("Inventory: empty"); } else { - for (String key : game.Inventory) { + for (String key : game.inventory) { output += key + ", "; } output = output.substring(0, output.length() - 2); @@ -356,28 +339,25 @@ public class Zork { } private void doActionTake(String tempString) { - if ((game.Rooms.get(currentRoom)).item.contains(tempString)) { - game.Inventory.add(tempString); - ZorkRoom tempRoom = (game.Rooms.get(currentRoom)); + if ((game.getCurrentRoom()).item.contains(tempString)) { + game.inventory.add(tempString); + ZorkRoom tempRoom = (game.getCurrentRoom()); tempRoom.item.remove(tempString); - game.Rooms.put(tempRoom); + game.put("room", tempRoom); System.out.println("Item " + tempString + " added to inventory."); } else { /*Search all containers in the current room for the item!*/ - boolean found = false; - for (String key : game.Rooms.get(currentRoom).container) { - ZorkContainer tempContainer = game.Containers.get(key); - if (tempContainer != null && tempContainer.isOpen && tempContainer.item.contains(tempString)) { - game.Inventory.add(tempString); + for (String key : game.getCurrentRoom().container) { + ZorkContainer tempContainer = (ZorkContainer) game.get("container", key); + if (tempContainer != null && tempContainer.isOpen() && tempContainer.item.contains(tempString)) { + game.inventory.add(tempString); tempContainer.item.remove(tempString); - game.Containers.put(tempContainer); + game.put("container", tempContainer); System.out.println("Item " + tempString + " added to inventory."); - found = true; - break; + return; } } - if (!found) - System.out.println("Error"); + System.out.println("Error"); } } @@ -406,18 +386,18 @@ public class Zork { private boolean doTriggersContainersInRoom() { boolean skip = false; - for (String key : game.Rooms.get(currentRoom).container) { - skip = skip || doZorkTriggers(game.Containers.get(key)); + for (String key : game.getCurrentRoom().container) { + skip = skip || doZorkTriggers(game.get("container", key)); } return skip; } private boolean doTriggersItemsInContainersInRoom() { boolean skip = false; - for (String key : game.Rooms.get(currentRoom).container) { - ZorkContainer tempContainer = game.Containers.get(key); + for (String key : game.getCurrentRoom().container) { + ZorkContainer tempContainer = (ZorkContainer) game.get("container", key); for (String key2 : tempContainer.item) { - skip = skip || doZorkTriggers(game.Items.get(key2)); + skip = skip || doZorkTriggers(game.get("item", key2)); } } return skip; @@ -425,36 +405,36 @@ public class Zork { private boolean doTriggersItemsInRoom() { boolean skip = false; - for (String key : game.Rooms.get(currentRoom).item) { - skip = skip || doZorkTriggers(game.Items.get(key)); + for (String key : game.getCurrentRoom().item) { + skip = skip || doZorkTriggers(game.get("item", key)); } return skip; } private boolean doTriggersItemsInInventory() { boolean skip = false; - for (String key : game.Inventory) { - skip = skip || doZorkTriggers(game.Items.get(key)); + for (String key : game.inventory) { + skip = skip || doZorkTriggers(game.get("item", key)); } return skip; } private boolean doTriggersCreaturesInRoom() { boolean skip = false; - for (String key : game.Rooms.get(currentRoom).creature) { - skip = skip || doZorkTriggers(game.Creatures.get(key)); + for (String key : game.getCurrentRoom().creature) { + skip = skip || doZorkTriggers(game.get("creature", key)); } return skip; } private boolean doTriggersRoom() { - return doZorkTriggers(game.Rooms.get(currentRoom)); + return doZorkTriggers(game.getCurrentRoom()); } private boolean doZorkTriggers(ZorkObject zorkObject) { boolean skip = false; - for (int x = 0; x < zorkObject.trigger.size(); x++) { + for (int x = zorkObject.trigger.size() - 1; x >= 0; x--) { ZorkTrigger tempTrigger = zorkObject.trigger.get(x); if (tempTrigger.evaluate(this)) { for (String print: tempTrigger.print) { diff --git a/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java b/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java index 12c8b3d..d543472 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java +++ b/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java @@ -3,7 +3,6 @@ package com.github.dtschust.zork; import com.github.dtschust.zork.types.ZorkContainer; import com.github.dtschust.zork.types.ZorkRoom; -import java.util.Set; /* Has conditions*/ public class ZorkConditionHas extends ZorkCondition { @@ -20,18 +19,18 @@ public class ZorkConditionHas extends ZorkCondition { public boolean evaluate(Zork zork) { /*Inventory is a special case as it isn't the name of any object in the game, check for it specifically*/ if (owner.equals("inventory")) { - return evaluateCondition(zork.game.Inventory, object); + return evaluateCondition(zork.game.inventory.contains(object)); } else { /* is it a room?*/ - ZorkRoom roomObject = zork.game.Rooms.get(owner); + ZorkRoom roomObject = (ZorkRoom) zork.game.get("room", owner); if (roomObject != null) { - return evaluateCondition(roomObject.item, object); + return evaluateCondition(roomObject.item.contains(object)); } /* is it a container?*/ else { - ZorkContainer containerObject = zork.game.Containers.get(owner); + ZorkContainer containerObject = (ZorkContainer) zork.game.get("container", owner); if (containerObject != null) { - return evaluateCondition(containerObject.item, object); + return evaluateCondition(containerObject.item.contains(object)); } } } @@ -39,9 +38,9 @@ public class ZorkConditionHas extends ZorkCondition { return false; } - private boolean evaluateCondition(Set items, String object){ - if(has.equals("yes")) return items.contains(object); - else if(has.equals("no")) return !items.contains(object); + private boolean evaluateCondition(boolean contained){ + if(has.equals("yes")) return contained; + else if(has.equals("no")) return !contained; return false; } } diff --git a/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java b/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java index dfe80ed..0a1dc57 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java +++ b/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java @@ -14,6 +14,6 @@ public class ZorkConditionStatus extends ZorkCondition { @Override public boolean evaluate(Zork zork) { ZorkObject tested = zork.game.getListThroughLookup(object).get(object); - return tested != null && tested.status.equals(status); + return tested != null && tested.isStatusEqualTo(status); } } diff --git a/src/main/java/com/github/dtschust/zork/ZorkTrigger.java b/src/main/java/com/github/dtschust/zork/ZorkTrigger.java index 31dd8d3..2f9eea7 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkTrigger.java +++ b/src/main/java/com/github/dtschust/zork/ZorkTrigger.java @@ -1,15 +1,20 @@ package com.github.dtschust.zork; import java.util.ArrayList; +import java.util.List; /*Trigger*/ public class ZorkTrigger { - public ArrayList conditions = new ArrayList<>(); - public ArrayList print = new ArrayList<>(); - public ArrayList action = new ArrayList<>(); - public String type = "single"; /*By default, single*/ + public final List conditions = new ArrayList<>(); + public final List print = new ArrayList<>(); + public final List action = new ArrayList<>(); + public final String type; /*By default, single*/ public boolean hasCommand = false; + public ZorkTrigger(String type) { + this.type = type; + } + public boolean evaluate(Zork zork) { for (ZorkEvaluatable condition : conditions) { if (!condition.evaluate(zork)) { diff --git a/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java b/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java index e640697..6d25752 100644 --- a/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java +++ b/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java @@ -7,42 +7,91 @@ import java.util.HashSet; import java.util.Set; public class ZorkGame { - public ZorkMap Rooms = new ZorkMap<>(); - public ZorkMap Items = new ZorkMap<>(); - public ZorkMap Containers = new ZorkMap<>(); - public ZorkMap Creatures = new ZorkMap<>(); - public Set Inventory = new HashSet<>(); - public HashMap ObjectLookup = new HashMap<>(); + + protected boolean running = false; + protected String currentRoom; + protected ZorkMap rooms = new ZorkMap<>(); + protected ZorkMap items = new ZorkMap<>(); + protected ZorkMap containers = new ZorkMap<>(); + protected ZorkMap creatures = new ZorkMap<>(); + public final Set inventory = new HashSet<>(); + protected HashMap objectLookup = new HashMap<>(); + + public ZorkRoom getCurrentRoom(){ + return rooms.get(currentRoom); + } + public boolean changeRoom(String newRoom){ + if(rooms.containsKey(newRoom)) { + currentRoom = newRoom; + running = true; + return true; + } + return false; + } + + public boolean isRunning(){ + return running; + } + + public void setGameOver(){ + running = false; + } + + public String getTypeFromLookup(String object){ + return objectLookup.get(object); + } public void addObjectThroughLookup(String name, ZorkObject object){ - switch (name) { - case "room": - Rooms.put((ZorkRoom) object); - break; - case "container": - Containers.put((ZorkContainer) object); - break; - case "creature": - Creatures.put((ZorkCreature) object); - break; - case "item": - Items.put((ZorkItem) object); - break; - } - ObjectLookup.put(object.name, name); + putInMapGivenType(name, object); + objectLookup.put(object.name, name); } public ZorkMap getListThroughLookup(String name){ - switch (ObjectLookup.get(name)) { - case "room": - return Rooms; - case "container": - return Containers; - case "creature": - return Creatures; - case "item": - return Items; - } - return null; + return getMapFromType(objectLookup.get(name)); } + public ZorkObject get(String type, String key){ + return getMapFromType(type).get(key); + } + + public void put(String type, ZorkObject object){ + putInMapGivenType(type, object); + } + + public Iterable values(String type){ + return getMapFromType(type).values(); + } + + private ZorkMap getMapFromType(String type){ + switch (type) { + case "room": + return rooms; + case "container": + return containers; + case "creature": + return creatures; + case "item": + return items; + default: + throw new IllegalStateException("Unexpected value: " + type); + } + } + + private void putInMapGivenType(String type, ZorkObject object){ + switch (type) { + case "room": + rooms.put((ZorkRoom) object); + break; + case "container": + containers.put((ZorkContainer) object); + break; + case "creature": + creatures.put((ZorkCreature) object); + break; + case "item": + items.put((ZorkItem) object); + break; + default: + throw new IllegalStateException("Unexpected value: " + type); + } + } } diff --git a/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java b/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java index e513988..7d0f709 100644 --- a/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java +++ b/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java @@ -5,7 +5,6 @@ import com.github.dtschust.zork.types.*; import org.w3c.dom.CharacterData; import org.w3c.dom.*; -import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import java.util.Iterator; @@ -30,6 +29,11 @@ public class ZorkReader { return "?"; } + private static String getItemOrDefault(Element element, String name, String base){ + NodeList field = element.getElementsByTagName(name); + return (field.getLength() > 0) ? getString((Element) field.item(0)) : base; + } + public ZorkGame build() { ZorkGame data = new ZorkGame(); @@ -42,10 +46,13 @@ public class ZorkReader { try { /* Open the xml file*/ - DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = builder.parse(file); + DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance(); + // Limit XML features to mitigate vulnerabilities + builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + builder.setFeature("http://xml.org/sax/features/external-general-entities", false); + builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - Element rootElement = doc.getDocumentElement(); + Element rootElement = builder.newDocumentBuilder().parse(file).getDocumentElement(); /* Every single first generation child is a room, container, creature, or item. So load them in*/ for (Node node : iterNodes(rootElement.getChildNodes())) { @@ -86,7 +93,13 @@ public class ZorkReader { private static void addCreature(ZorkGame data, Element element) { /* Get all possible creature attributes*/ - ZorkCreature tempCreature = (ZorkCreature) readZorkObjectAttributes(new ZorkCreature(), element); + ZorkCreature tempCreature = new ZorkCreature( + getItemOrDefault(element, "name", ""), + getItemOrDefault(element, "description", "") + ); + + readTriggersInObject(element, tempCreature); + tempCreature.updateStatus(getItemOrDefault(element, "status", "")); for (Element vuln : iterElements(element.getElementsByTagName("vulnerability"))) { tempCreature.vulnerability.add(getString(vuln)); @@ -105,22 +118,24 @@ public class ZorkReader { } } - readTriggersInObject(element, tempCreature); - /* Put each creature in the creatures hashmap, the generic object hashmap, and the objectlookup hashmap*/ data.addObjectThroughLookup("creature", tempCreature); } private static void addContainer(ZorkGame data, Element element) { /*Get all possible container attributes*/ - ZorkContainer tempCont = (ZorkContainer) readZorkObjectAttributes(new ZorkContainer(), element); + ZorkContainer tempCont = new ZorkContainer( + getItemOrDefault(element, "name", ""), + getItemOrDefault(element, "description", "") + ); + + readTriggersInObject(element, tempCont); + tempCont.updateStatus(getItemOrDefault(element, "status", "")); /*Initially assume a closed container*/ - tempCont.isOpen = false; - for (Element accept : iterElements(element.getElementsByTagName("accept"))) { /* If container has an accepts attribute, then it is always open*/ - tempCont.isOpen = true; + tempCont.open(); tempCont.accept.add(getString(accept)); } @@ -129,19 +144,20 @@ public class ZorkReader { tempCont.item.add(itemName); } - readTriggersInObject(element, tempCont); - /* Put each container in the containers hashmap, the generic object hashmap, and the objectlookup hashmap*/ data.addObjectThroughLookup("container", tempCont); } private static void addItem(ZorkGame data, Element element) { /* Get all possible item attributes*/ - ZorkItem tempItem = (ZorkItem) readZorkObjectAttributes(new ZorkItem(), element); + ZorkItem tempItem = new ZorkItem( + getItemOrDefault(element, "name", ""), + getItemOrDefault(element, "description", ""), + getItemOrDefault(element, "writing","") + ); - NodeList writing = element.getElementsByTagName("writing"); - if (writing.getLength() > 0) - tempItem.writing = getString((Element) writing.item(0)); + readTriggersInObject(element, tempItem); + tempItem.updateStatus(getItemOrDefault(element, "status", "")); NodeList turnon = element.getElementsByTagName("turnon"); if (turnon.getLength() > 0) { @@ -154,8 +170,6 @@ public class ZorkReader { } - readTriggersInObject(element, tempItem); - /* Put each item in the items hashmap, the generic objects hashmap, and store its type in objectlookup*/ data.addObjectThroughLookup("item", tempItem); } @@ -163,14 +177,14 @@ public class ZorkReader { private static void addRoom(ZorkGame data, Element element) { /*Get all possible Room attributes*/ - ZorkRoom tempRoom = (ZorkRoom) readZorkObjectAttributes(new ZorkRoom(), element); + ZorkRoom tempRoom = new ZorkRoom( + getItemOrDefault(element, "name", ""), + getItemOrDefault(element, "description", ""), + getItemOrDefault(element, "type", "regular") + ); - NodeList type = element.getElementsByTagName("type"); - if (type.getLength() > 0) { - tempRoom.type = getString((Element) type.item(0)); - } else { - tempRoom.type = "regular"; - } + readTriggersInObject(element, tempRoom); + tempRoom.updateStatus(getItemOrDefault(element, "status", "")); for (Element item : iterElements(element.getElementsByTagName("item"))) { String itemName = getString(item); @@ -182,8 +196,6 @@ public class ZorkReader { tempRoom.creature.add(creatureName); } - readTriggersInObject(element, tempRoom); - for (Element container : iterElements(element.getElementsByTagName("container"))) { String containerName = getString(container); tempRoom.container.add(containerName); @@ -198,22 +210,9 @@ public class ZorkReader { data.addObjectThroughLookup("room", tempRoom); } - private static ZorkObject readZorkObjectAttributes(ZorkObject tempObject, Element element) { - NodeList name = element.getElementsByTagName("name"); - tempObject.name = getString((Element) name.item(0)); - - NodeList status = element.getElementsByTagName("status"); - tempObject.status = (status.getLength() > 0) ? getString((Element) status.item(0)) : ""; - - NodeList description = element.getElementsByTagName("description"); - tempObject.description = (description.getLength() > 0) ? getString((Element) description.item(0)) : ""; - - return tempObject; - } - private static void readTriggersInObject(Element element, ZorkObject tempRoom) { for (Element trigger : iterElements(element.getElementsByTagName("trigger"))) { - ZorkTrigger tempTrigger = new ZorkTrigger(); + ZorkTrigger tempTrigger = new ZorkTrigger(getItemOrDefault(element, "type", "single")); for (Element command : iterElements(trigger.getElementsByTagName("command"))) { ZorkCommand tempCommand = new ZorkCommand(getString(command)); tempTrigger.conditions.add(tempCommand); @@ -222,12 +221,6 @@ public class ZorkReader { readConditionsInTrigger(trigger, tempTrigger.conditions); - NodeList ttype = element.getElementsByTagName("type"); - if (ttype.getLength() > 0) { - tempTrigger.type = getString((Element) ttype.item(0)); - } else { - tempTrigger.type = "single"; - } for (Element print : iterElements(trigger.getElementsByTagName("print"))) { tempTrigger.print.add(getString(print)); } diff --git a/src/main/java/com/github/dtschust/zork/types/ZorkContainer.java b/src/main/java/com/github/dtschust/zork/types/ZorkContainer.java index a958528..bad2af2 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkContainer.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkContainer.java @@ -2,14 +2,25 @@ package com.github.dtschust.zork.types; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; /* Container*/ public class ZorkContainer extends ZorkObject { - public Set item = new HashSet(); - public ArrayList accept = new ArrayList<>(); - public boolean isOpen; + public final Set item = new HashSet<>(); + public final List accept = new ArrayList<>(); + protected boolean open = false; - public ZorkContainer() { + public ZorkContainer(String name, String description) { + super(name, description); } + + + public boolean isOpen(){ + return open; + } + public void open(){ + open = true; + } + } diff --git a/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java b/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java index 2a1013d..9c7502b 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java @@ -5,18 +5,21 @@ import com.github.dtschust.zork.ZorkCondition; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; /* Creature*/ public class ZorkCreature extends ZorkObject { - public Set vulnerability = new HashSet<>(); - public ArrayList conditions = new ArrayList<>(); - public ArrayList print = new ArrayList<>(); - public ArrayList action = new ArrayList<>(); + public final Set vulnerability = new HashSet<>(); + public final List conditions = new ArrayList<>(); + public final List print = new ArrayList<>(); + public final List action = new ArrayList<>(); - public ZorkCreature() { + public ZorkCreature(String name, String description) { + super(name, description); } + /* Evaluate the success of an attack*/ public boolean attack(Zork zork, String weapon) { if (!vulnerability.contains(weapon)) { diff --git a/src/main/java/com/github/dtschust/zork/types/ZorkItem.java b/src/main/java/com/github/dtschust/zork/types/ZorkItem.java index b32df86..a565f24 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkItem.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkItem.java @@ -1,13 +1,16 @@ package com.github.dtschust.zork.types; import java.util.ArrayList; +import java.util.List; /* Item*/ public class ZorkItem extends ZorkObject { - public String writing; - public ArrayList turnOnPrint = new ArrayList<>(); - public ArrayList turnOnAction = new ArrayList<>(); + public final String writing; + public final List turnOnPrint = new ArrayList<>(); + public final List turnOnAction = new ArrayList<>(); - public ZorkItem() { + public ZorkItem(String name, String description, String writing) { + super(name, description); + this.writing = writing; } } diff --git a/src/main/java/com/github/dtschust/zork/types/ZorkObject.java b/src/main/java/com/github/dtschust/zork/types/ZorkObject.java index d53926b..e9333b4 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkObject.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkObject.java @@ -3,14 +3,26 @@ package com.github.dtschust.zork.types; import com.github.dtschust.zork.ZorkTrigger; import java.util.ArrayList; +import java.util.List; /* Generic object, everything inherits from this*/ public abstract class ZorkObject { - public String name; - public String status; - public String description; - public ArrayList trigger = new ArrayList<>(); + public final String name; + public final String description; + private String status; - public ZorkObject() { + public final List trigger = new ArrayList<>(); + + protected ZorkObject(String name, String description) { + this.name = name; + this.description = description; + } + + public void updateStatus(String status) { + this.status = status; + } + + public boolean isStatusEqualTo(String status) { + return this.status.equals(status); } } diff --git a/src/main/java/com/github/dtschust/zork/types/ZorkRoom.java b/src/main/java/com/github/dtschust/zork/types/ZorkRoom.java index aea5688..b577171 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkRoom.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkRoom.java @@ -2,16 +2,19 @@ package com.github.dtschust.zork.types; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /* Room*/ public class ZorkRoom extends ZorkObject { - public String type = "regular"; - public HashMap border = new HashMap<>(); - public Set container = new HashSet<>(); - public Set item = new HashSet<>(); - public Set creature = new HashSet<>(); + public final String type; + public final Map border = new HashMap<>(); + public final Set container = new HashSet<>(); + public final Set item = new HashSet<>(); + public final Set creature = new HashSet<>(); - public ZorkRoom() { + public ZorkRoom(String name, String description, String type) { + super(name, description); + this.type = type; } } diff --git a/src/test/java/com/github/dtschust/zork/ZorkTest.java b/src/test/java/com/github/dtschust/zork/ZorkTest.java index b11f745..b39a9e7 100644 --- a/src/test/java/com/github/dtschust/zork/ZorkTest.java +++ b/src/test/java/com/github/dtschust/zork/ZorkTest.java @@ -13,7 +13,7 @@ class ZorkTest { * WARNING: when looking at inventory (i) we are relying on the HashMap order, so the test may be unsafe */ @Test - public void testSampleGame() { + void testSampleGame() { String gameConfig = "sampleGame.xml"; String gameExecution = "RunThroughResults.txt";