From 40675f5a393f10ba9eedf4a65be29b5deec1ad3f Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 21 Nov 2022 16:36:38 +0100 Subject: [PATCH] Command pattern over actions - tested, it works --- .../java/com/github/dtschust/zork/Zork.java | 329 +----------------- .../github/dtschust/zork/ZorkCondition.java | 9 + .../dtschust/zork/ZorkConditionHas.java | 15 +- .../dtschust/zork/ZorkConditionStatus.java | 5 +- .../github/dtschust/zork/ZorkEvaluatable.java | 2 + .../github/dtschust/zork/parser/ZorkGame.java | 28 +- .../com/github/dtschust/zork/repl/Action.java | 15 + .../dtschust/zork/repl/ActionDispatcher.java | 54 +++ .../dtschust/zork/repl/actions/AddAction.java | 59 ++++ .../zork/repl/actions/AttackAction.java | 48 +++ .../zork/repl/actions/DeleteAction.java | 72 ++++ .../zork/repl/actions/DropItemAction.java | 34 ++ .../zork/repl/actions/GameOverAction.java | 27 ++ .../zork/repl/actions/InventoryAction.java | 23 ++ .../zork/repl/actions/MoveAction.java | 43 +++ .../zork/repl/actions/OpenAction.java | 42 +++ .../dtschust/zork/repl/actions/PutAction.java | 36 ++ .../zork/repl/actions/ReadAction.java | 35 ++ .../zork/repl/actions/TakeAction.java | 46 +++ .../zork/repl/actions/TurnOnAction.java | 44 +++ .../zork/repl/actions/UpdateAction.java | 34 ++ .../dtschust/zork/types/ZorkCreature.java | 5 +- 22 files changed, 666 insertions(+), 339 deletions(-) create mode 100644 src/main/java/com/github/dtschust/zork/repl/Action.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/ActionDispatcher.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/AddAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/AttackAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/DeleteAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/DropItemAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/GameOverAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/InventoryAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/MoveAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/OpenAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/PutAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/ReadAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/TakeAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/TurnOnAction.java create mode 100644 src/main/java/com/github/dtschust/zork/repl/actions/UpdateAction.java diff --git a/src/main/java/com/github/dtschust/zork/Zork.java b/src/main/java/com/github/dtschust/zork/Zork.java index 2c9d7bb..71caeae 100644 --- a/src/main/java/com/github/dtschust/zork/Zork.java +++ b/src/main/java/com/github/dtschust/zork/Zork.java @@ -6,19 +6,18 @@ package com.github.dtschust.zork; import com.github.dtschust.zork.parser.ZorkGame; -import com.github.dtschust.zork.types.*; import com.github.dtschust.zork.parser.ZorkReader; +import com.github.dtschust.zork.repl.ActionDispatcher; +import com.github.dtschust.zork.types.ZorkContainer; +import com.github.dtschust.zork.types.ZorkObject; -import java.util.Map; import java.util.Scanner; -import static java.util.Map.entry; - /* And away we go*/ public class Zork { public String userInput; - + public ZorkGame game; Scanner source = new Scanner(System.in); @@ -30,14 +29,16 @@ public class Zork { /* Print out the first entrance description, starting the game!*/ System.out.println(game.getCurrentRoom().description); + ActionDispatcher d = new ActionDispatcher(game); + /* There is no stopping in Zork, until we're done!!*/ - while(game.isRunning()) { + 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*/ - executeAction(userInput); + d.dispatch(userInput); /* Clear the user input, and check the triggers again (various states have changed, gnomes need to be found!*/ userInput = ""; @@ -59,317 +60,14 @@ public class Zork { new Zork(args[0]); } - 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")) { - doActionUpdate(action[1], action[3]); - } - /*Game Over: pretty straight forward*/ - else if (input.equals("Game Over")) { - 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")) { - doActionAdd(action[1], action[3]); - } - /* Delete: figure out what object it is and delete it accordingly. Rooms are especially tricky */ - else if (action[0].equals("Delete")) { - doActionDelete(action[1]); - } - /*If it's not a "Special Action", just treat it normally */ - /* Execute a user action or an action command from some element that is not one of the "Special Commands"*/ - /* Movement */ - else if (action[0].length() == 1 && "nswe".contains(action[0])) { - doActionMove(action[0]); - } - /* Inventory */ - else if (action[0].equals("i")) { - doActionInventory(); - } - /* Take */ - else if (action[0].equals("take") && action.length > 1) { - doActionTake(action[1]); - } - /* Open Exit (you should be so lucky)*/ - else if (input.equals("open exit")) { - doActionOpenExit(); - } - /* Open a container */ - else if (action[0].equals("open") && action.length > 1) { - doActionOpenContainer(action[1]); - } - /* Read an object */ - else if (action[0].equals("read") && action.length > 1) { - doActionReadObject(action[1]); - } - /* Drop an item*/ - else if (action[0].equals("drop") && action.length > 1) { - doActionDropItem(action[1]); - } - /* Put an item somewhere */ - else if (action[0].equals("put") && action.length >= 4) { - doActionPutItem(action[1], action[3]); - } - /* Turn on an item*/ - else if (input.startsWith("turn on") && action.length >= 3) { - doActionTurnOn(action[2]); - } - /* Attempt an attack, you feeling lucky?*/ - else if (action[0].equals("attack") && action.length >= 4) { - doActionAttack(action[1], action[3]); - } - /* Invalid command*/ - else System.out.println("Error"); - } - - private void doActionGameWon() { - System.out.println("Victory!"); - game.setGameOver(); - } - - private void doActionAdd(String object, String destination) { - String objectType; - objectType = game.getTypeFromLookup(object); - String destinationType = game.getTypeFromLookup(destination); - if (destinationType.equals("room")) { - ZorkRoom tempRoom = (ZorkRoom) game.get("room", destination); - if (objectType.equals("item")) - tempRoom.item.add(object); - else if (objectType.equals("creature")) - tempRoom.creature.add(object); - else if (objectType.equals("container")) - tempRoom.container.add(object); - else - System.out.println("Error"); - game.put("room", tempRoom); - } else if (destinationType.equals("container")) { - ZorkContainer tempContainer = (ZorkContainer) game.get("container", destination); - if (objectType.equals("item")) - tempContainer.item.add(object); - else - System.out.println("Error"); - game.put("container", tempContainer); - } else { - System.out.println("Error"); - } - } - - private void doActionDelete(String object) { - String objectType = game.getTypeFromLookup(object); - if (objectType.equals("room")) { - 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.put("room", tempRoom); - } - } else if (objectType.equals("item")) { - for (ZorkRoom tempRoom : (Iterable) game.values("room")) { - if (tempRoom.item.contains(object)) { - tempRoom.item.remove(object); - game.put("room", tempRoom); - } - } - for (ZorkContainer tempContainer : (Iterable) game.values("container")) { - if (tempContainer.item.contains(object)) { - tempContainer.item.remove(object); - game.put("container", tempContainer); - } - } - } else if (objectType.equals("container")) { - for (ZorkRoom tempRoom : (Iterable) game.values("room")) { - if (tempRoom.container.contains(object)) { - tempRoom.container.remove(object); - game.put("room", tempRoom); - } - } - } else if (objectType.equals("creature")) { - for (ZorkRoom tempRoom : (Iterable) game.values("room")) { - if (tempRoom.creature.contains(object)) { - tempRoom.creature.remove(object); - game.put("room", tempRoom); - } - } - } - } - - private void doActionUpdate(String object, String newStatus) { - ZorkMap collection = (ZorkMap) game.getListThroughLookup(object); - ZorkObject tempObject = collection.get(object); - tempObject.updateStatus(newStatus); - collection.put(tempObject); - } - - private void doActionAttack(String tempString, String 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) { - System.out.println(print); - } - for (String action: tempCreature.action) { - executeAction(action); - } - return; - } - } - } - System.out.println("Error"); - } - - private void doActionTurnOn(String 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) { - System.out.println(print); - } - for (String action: tempItem.turnOnAction) { - executeAction(action); - } - return; - } - } - System.out.println("Error"); - } - - private void doActionPutItem(String tempString, String 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); - System.out.println("Item " + tempString + " added to " + destination + "."); - return; - } - } - System.out.println("Error"); - } - - private void doActionDropItem(String tempString) { - if (game.inventory.contains(tempString)) { - ZorkRoom tempRoom = game.getCurrentRoom(); - tempRoom.item.add(tempString); - game.put("room", tempRoom); - game.inventory.remove(tempString); - System.out.println(tempString + " dropped."); - } else { - System.out.println("Error"); - } - } - - private void doActionReadObject(String tempString) { - 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."); - } - } else { - System.out.println("Error"); - } - } - - private void doActionOpenContainer(String tempString) { - ZorkContainer tempContainer; - 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 + ", "; - } - output = output.substring(0, output.length() - 2); - System.out.println(output + "."); - } - } else { - System.out.println("Error"); - } - } - - private void doActionOpenExit() { - if (game.getCurrentRoom().type.equals("exit")) { - System.out.println("Game Over"); - game.setGameOver(); - } else { - System.out.println("Error"); - } - } - - /*Basic movement function */ - private void doActionMove(String direction) { - final Map fullDirections = Map.ofEntries( - entry("n", "north"), - entry("s", "south"), - entry("e", "east"), - entry("w", "west") - ); - - 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."); - } - } - - - /* Print out the inventory when user types i */ - private void doActionInventory() { - String output = "Inventory: "; - if (game.inventory.isEmpty()) { - System.out.println("Inventory: empty"); - } else { - for (String key : game.inventory) { - output += key + ", "; - } - output = output.substring(0, output.length() - 2); - System.out.println(output); - } - } - - private void doActionTake(String tempString) { - if ((game.getCurrentRoom()).item.contains(tempString)) { - game.inventory.add(tempString); - ZorkRoom tempRoom = (game.getCurrentRoom()); - tempRoom.item.remove(tempString); - game.put("room", tempRoom); - System.out.println("Item " + tempString + " added to inventory."); - } else { - /*Search all containers in the current room for the item!*/ - 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.put("container", tempContainer); - System.out.println("Item " + tempString + " added to inventory."); - return; - } - } - System.out.println("Error"); - } - } - - /* Check triggers */ public boolean executeTriggers() { /*Variable initialization*/ - boolean skip = false; + boolean skip; /*Check Room triggers*/ - skip = skip || doTriggersRoom(); + skip = doTriggersRoom(); /* Check items in the containers in the room */ skip = skip || doTriggersItemsInContainersInRoom(); /* Check all containers in the room*/ @@ -437,11 +135,12 @@ public class Zork { 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) { + for (String print : tempTrigger.print) { System.out.println(print); } - for (String action: tempTrigger.action) { - executeAction(action); + final ActionDispatcher d = new ActionDispatcher(game); + for (String action : tempTrigger.action) { + d.dispatch(action); } skip = skip || tempTrigger.hasCommand; if (tempTrigger.type.equals("single")) { diff --git a/src/main/java/com/github/dtschust/zork/ZorkCondition.java b/src/main/java/com/github/dtschust/zork/ZorkCondition.java index 1a1fcac..a4eb525 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkCondition.java +++ b/src/main/java/com/github/dtschust/zork/ZorkCondition.java @@ -1,5 +1,7 @@ package com.github.dtschust.zork; +import com.github.dtschust.zork.parser.ZorkGame; + /* Generic condition*/ public abstract class ZorkCondition implements ZorkEvaluatable { public final String object; @@ -7,4 +9,11 @@ public abstract class ZorkCondition implements ZorkEvaluatable { protected ZorkCondition(String object) { this.object = object; } + + public abstract boolean evaluate(ZorkGame game); + + @Override + public boolean evaluate(Zork zork) { + return this.evaluate(zork.game); + } } diff --git a/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java b/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java index d543472..0f32d3f 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java +++ b/src/main/java/com/github/dtschust/zork/ZorkConditionHas.java @@ -1,5 +1,6 @@ package com.github.dtschust.zork; +import com.github.dtschust.zork.parser.ZorkGame; import com.github.dtschust.zork.types.ZorkContainer; import com.github.dtschust.zork.types.ZorkRoom; @@ -16,19 +17,19 @@ public class ZorkConditionHas extends ZorkCondition { } @Override - public boolean evaluate(Zork zork) { + public boolean evaluate(ZorkGame game) { /*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.contains(object)); + return evaluateCondition(game.inventory.contains(object)); } else { /* is it a room?*/ - ZorkRoom roomObject = (ZorkRoom) zork.game.get("room", owner); + ZorkRoom roomObject = (ZorkRoom) game.get("room", owner); if (roomObject != null) { return evaluateCondition(roomObject.item.contains(object)); } /* is it a container?*/ else { - ZorkContainer containerObject = (ZorkContainer) zork.game.get("container", owner); + ZorkContainer containerObject = (ZorkContainer) game.get("container", owner); if (containerObject != null) { return evaluateCondition(containerObject.item.contains(object)); } @@ -38,9 +39,9 @@ public class ZorkConditionHas extends ZorkCondition { return false; } - private boolean evaluateCondition(boolean contained){ - if(has.equals("yes")) return contained; - else if(has.equals("no")) return !contained; + 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 0a1dc57..9553286 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java +++ b/src/main/java/com/github/dtschust/zork/ZorkConditionStatus.java @@ -1,5 +1,6 @@ package com.github.dtschust.zork; +import com.github.dtschust.zork.parser.ZorkGame; import com.github.dtschust.zork.types.ZorkObject; /* Status conditions*/ @@ -12,8 +13,8 @@ public class ZorkConditionStatus extends ZorkCondition { } @Override - public boolean evaluate(Zork zork) { - ZorkObject tested = zork.game.getListThroughLookup(object).get(object); + public boolean evaluate(ZorkGame game) { + ZorkObject tested = game.getListThroughLookup(object).get(object); return tested != null && tested.isStatusEqualTo(status); } } diff --git a/src/main/java/com/github/dtschust/zork/ZorkEvaluatable.java b/src/main/java/com/github/dtschust/zork/ZorkEvaluatable.java index f9aba99..590def1 100644 --- a/src/main/java/com/github/dtschust/zork/ZorkEvaluatable.java +++ b/src/main/java/com/github/dtschust/zork/ZorkEvaluatable.java @@ -1,5 +1,7 @@ package com.github.dtschust.zork; +import com.github.dtschust.zork.parser.ZorkGame; + public interface ZorkEvaluatable { boolean evaluate(Zork 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 6d25752..ec912c8 100644 --- a/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java +++ b/src/main/java/com/github/dtschust/zork/parser/ZorkGame.java @@ -17,11 +17,12 @@ public class ZorkGame { public final Set inventory = new HashSet<>(); protected HashMap objectLookup = new HashMap<>(); - public ZorkRoom getCurrentRoom(){ + public ZorkRoom getCurrentRoom() { return rooms.get(currentRoom); } - public boolean changeRoom(String newRoom){ - if(rooms.containsKey(newRoom)) { + + public boolean changeRoom(String newRoom) { + if (rooms.containsKey(newRoom)) { currentRoom = newRoom; running = true; return true; @@ -29,39 +30,40 @@ public class ZorkGame { return false; } - public boolean isRunning(){ + public boolean isRunning() { return running; } - public void setGameOver(){ + public void setGameOver() { running = false; } - public String getTypeFromLookup(String object){ + public String getTypeFromLookup(String object) { return objectLookup.get(object); } - public void addObjectThroughLookup(String name, ZorkObject object){ + public void addObjectThroughLookup(String name, ZorkObject object) { putInMapGivenType(name, object); objectLookup.put(object.name, name); } - public ZorkMap getListThroughLookup(String name){ + + public ZorkMap getListThroughLookup(String name) { return getMapFromType(objectLookup.get(name)); } - public ZorkObject get(String type, String key){ + public ZorkObject get(String type, String key) { return getMapFromType(type).get(key); } - public void put(String type, ZorkObject object){ + public void put(String type, ZorkObject object) { putInMapGivenType(type, object); } - public Iterable values(String type){ + public Iterable values(String type) { return getMapFromType(type).values(); } - private ZorkMap getMapFromType(String type){ + private ZorkMap getMapFromType(String type) { switch (type) { case "room": return rooms; @@ -76,7 +78,7 @@ public class ZorkGame { } } - private void putInMapGivenType(String type, ZorkObject object){ + private void putInMapGivenType(String type, ZorkObject object) { switch (type) { case "room": rooms.put((ZorkRoom) object); diff --git a/src/main/java/com/github/dtschust/zork/repl/Action.java b/src/main/java/com/github/dtschust/zork/repl/Action.java new file mode 100644 index 0000000..f6da0f7 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/Action.java @@ -0,0 +1,15 @@ +package com.github.dtschust.zork.repl; + +import com.github.dtschust.zork.parser.ZorkGame; + +import java.util.List; + +public abstract class Action { + public abstract boolean matchesInput(final List arguments); + public int getMinimumArgCount() { + return 1; + } + + public int getMaximumArgCount() { return Integer.MAX_VALUE; } + public abstract void run(final ZorkGame game, final List arguments); +} diff --git a/src/main/java/com/github/dtschust/zork/repl/ActionDispatcher.java b/src/main/java/com/github/dtschust/zork/repl/ActionDispatcher.java new file mode 100644 index 0000000..1ee6177 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/ActionDispatcher.java @@ -0,0 +1,54 @@ +package com.github.dtschust.zork.repl; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.actions.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class ActionDispatcher { + private static final List actionList = List.of( + new AddAction(), + new AttackAction(), + new DeleteAction(), + new DropItemAction(), + new GameOverAction(), + new InventoryAction(), + new MoveAction(), + new OpenAction(), + new PutAction(), + new ReadAction(), + new TakeAction(), + new TurnOnAction(), + new UpdateAction() + ); + + private final ZorkGame game; + + public ActionDispatcher(ZorkGame game) { + this.game = game; + } + + private Optional findAction(final List arguments) { + if (arguments.isEmpty()) return Optional.empty(); + final int size = arguments.size(); + return actionList.stream().filter( + u -> size >= u.getMinimumArgCount() && + size <= u.getMaximumArgCount() && + u.matchesInput(arguments) + ).findAny(); + } + + public void dispatch(String input) { + final List arguments = Arrays.asList(input.split(" ")); + final Optional action = findAction(arguments); + + if (action.isEmpty()) { + System.out.println("Error"); + } else { + action.get().run(game, arguments); + } + } + +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/AddAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/AddAction.java new file mode 100644 index 0000000..616671f --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/AddAction.java @@ -0,0 +1,59 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkContainer; +import com.github.dtschust.zork.types.ZorkRoom; + +import java.util.List; + +/** + * Add: figure out what type the destination is, then what type the object is. Then add object to destination if it makes sense + */ +public class AddAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("Add"); + } + + @Override + public int getMinimumArgCount() { + return 4; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String object = arguments.get(1); + final String destination = arguments.get(3); + + final String objectType = game.getTypeFromLookup(object); + final String destinationType = game.getTypeFromLookup(destination); + if (destinationType.equals("room")) { + ZorkRoom tempRoom = (ZorkRoom) game.get("room", destination); + switch (objectType) { + case "item": + tempRoom.item.add(object); + break; + case "creature": + tempRoom.creature.add(object); + break; + case "container": + tempRoom.container.add(object); + break; + default: + System.out.println("Error"); + break; + } + game.put("room", tempRoom); + } else if (destinationType.equals("container")) { + final ZorkContainer tempContainer = (ZorkContainer) game.get("container", destination); + if (objectType.equals("item")) + tempContainer.item.add(object); + else + System.out.println("Error"); + game.put("container", tempContainer); + } else { + System.out.println("Error"); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/AttackAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/AttackAction.java new file mode 100644 index 0000000..c555e5d --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/AttackAction.java @@ -0,0 +1,48 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.repl.ActionDispatcher; +import com.github.dtschust.zork.types.ZorkCreature; + +import java.util.List; + +/** + * Attempt an attack, do you feel lucky? + */ +public class AttackAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("attack"); + } + + @Override + public int getMinimumArgCount() { + return 4; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String tempString = arguments.get(1); + final String weapon = arguments.get(3); + + if (game.getCurrentRoom().creature.contains(tempString)) { + ZorkCreature tempCreature = (ZorkCreature) game.get("creature", tempString); + if (tempCreature != null && game.inventory.contains(weapon)) { + if (tempCreature.attack(game, weapon)) { + System.out.println("You assault the " + tempString + " with the " + weapon + "."); + for (String print : tempCreature.print) { + System.out.println(print); + } + final ActionDispatcher effectsDispatcher = new ActionDispatcher(game); + for (final String action : tempCreature.action) { + effectsDispatcher.dispatch(action); + } + return; + } + } + } + + System.out.println("Error"); + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/DeleteAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/DeleteAction.java new file mode 100644 index 0000000..60530f6 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/DeleteAction.java @@ -0,0 +1,72 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkContainer; +import com.github.dtschust.zork.types.ZorkRoom; + +import java.util.List; + +/** + * Delete: figure out what object it is and delete it accordingly. Rooms are especially tricky + */ +public class DeleteAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("Delete"); + } + + @Override + public int getMinimumArgCount() { + return 2; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String object = arguments.get(1); + + String objectType = game.getTypeFromLookup(object); + switch (objectType) { + case "room": + 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.put("room", tempRoom); + } + break; + case "item": + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { + if (tempRoom.item.contains(object)) { + tempRoom.item.remove(object); + game.put("room", tempRoom); + } + } + for (ZorkContainer tempContainer : (Iterable) game.values("container")) { + if (tempContainer.item.contains(object)) { + tempContainer.item.remove(object); + game.put("container", tempContainer); + } + } + break; + case "container": + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { + if (tempRoom.container.contains(object)) { + tempRoom.container.remove(object); + game.put("room", tempRoom); + } + } + break; + case "creature": + for (ZorkRoom tempRoom : (Iterable) game.values("room")) { + if (tempRoom.creature.contains(object)) { + tempRoom.creature.remove(object); + game.put("room", tempRoom); + } + } + break; + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/DropItemAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/DropItemAction.java new file mode 100644 index 0000000..5e0537d --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/DropItemAction.java @@ -0,0 +1,34 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkRoom; + +import java.util.List; + +public class DropItemAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("drop"); + } + + @Override + public int getMinimumArgCount() { + return 2; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String what = arguments.get(1); + + if (game.inventory.contains(what)) { + ZorkRoom tempRoom = game.getCurrentRoom(); + tempRoom.item.add(what); + game.put("room", tempRoom); + game.inventory.remove(what); + System.out.println(what + " dropped."); + } else { + System.out.println("Error"); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/GameOverAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/GameOverAction.java new file mode 100644 index 0000000..fe407bc --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/GameOverAction.java @@ -0,0 +1,27 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; + +import java.util.List; + +/** + * The "Game Over" action marks the end of the game. + */ +public class GameOverAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("Game") && arguments.get(1).equals("Over"); + } + + @Override + public int getMinimumArgCount() { + return 2; + } + + @Override + public void run(ZorkGame game, List arguments) { + System.out.println("Victory!"); + game.setGameOver(); + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/InventoryAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/InventoryAction.java new file mode 100644 index 0000000..7397de5 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/InventoryAction.java @@ -0,0 +1,23 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; + +import java.util.List; + +public class InventoryAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("i"); + } + + @Override + public void run(ZorkGame game, List arguments) { + if (game.inventory.isEmpty()) { + System.out.println("Inventory: empty"); + } else { + final String output = "Inventory: " + String.join(", ", game.inventory); + System.out.println(output); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/MoveAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/MoveAction.java new file mode 100644 index 0000000..c0b8441 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/MoveAction.java @@ -0,0 +1,43 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; + +import java.util.List; +import java.util.Map; + +import static java.util.Map.entry; + +/** + * If it's not a "Special Action", just treat it normally + * Execute a user action or an action command from some element that is not one of the "Special Commands" + * Movement + */ +public class MoveAction extends Action { + private static final Map fullDirections = Map.ofEntries( + entry("n", "north"), + entry("s", "south"), + entry("e", "east"), + entry("w", "west") + ); + + @Override + public boolean matchesInput(List arguments) { + return fullDirections.containsKey(arguments.get(0)); + } + + @Override + public int getMaximumArgCount() { + return 1; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String direction = arguments.get(0); + 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."); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/OpenAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/OpenAction.java new file mode 100644 index 0000000..1b1a175 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/OpenAction.java @@ -0,0 +1,42 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkContainer; + +import java.util.List; + +public class OpenAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("open"); + } + + @Override + public void run(ZorkGame game, List arguments) { + final String what = arguments.get(1); + + if (what.equals("exit")) { + if (game.getCurrentRoom().type.equals("exit")) { + System.out.println("Game Over"); + game.setGameOver(); + } else { + System.out.println("Error"); + } + } else { + ZorkContainer tempContainer; + if (game.getCurrentRoom().container.contains(what)) { + tempContainer = (ZorkContainer) game.get("container", what); + tempContainer.open(); + if (tempContainer.item.isEmpty()) { + System.out.println(what + " is empty"); + } else { + final String output = String.join(", ", tempContainer.item); + System.out.println(what + " contains " + output + "."); + } + } else { + System.out.println("Error"); + } + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/PutAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/PutAction.java new file mode 100644 index 0000000..b5bed9d --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/PutAction.java @@ -0,0 +1,36 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkContainer; + +import java.util.List; + +public class PutAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("put"); + } + + @Override + public int getMinimumArgCount() { + return 4; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String what = arguments.get(1); + final String destination = arguments.get(3); + + if (game.getCurrentRoom().container.contains(destination)) { + ZorkContainer tempContainer = (ZorkContainer) game.get("container", destination); + if (tempContainer.isOpen() && game.inventory.contains(what)) { + tempContainer.item.add(what); + game.inventory.remove(what); + System.out.println("Item " + what + " added to " + destination + "."); + return; + } + } + System.out.println("Error"); + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/ReadAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/ReadAction.java new file mode 100644 index 0000000..6ae56be --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/ReadAction.java @@ -0,0 +1,35 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkItem; + +import java.util.List; + +public class ReadAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("read"); + } + + @Override + public int getMinimumArgCount() { + return 2; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String what = arguments.get(1); + + if (game.inventory.contains(what)) { + ZorkItem tempItem = (ZorkItem) game.get("item", what); + if (tempItem.writing != null && !tempItem.writing.isEmpty()) { + System.out.println(tempItem.writing); + } else { + System.out.println("Nothing written."); + } + } else { + System.out.println("Error"); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/TakeAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/TakeAction.java new file mode 100644 index 0000000..31cf3d5 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/TakeAction.java @@ -0,0 +1,46 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkContainer; +import com.github.dtschust.zork.types.ZorkRoom; + +import java.util.List; + +public class TakeAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("take"); + } + + @Override + public int getMinimumArgCount() { + return 2; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String tempString = arguments.get(1); + + if ((game.getCurrentRoom()).item.contains(tempString)) { + game.inventory.add(tempString); + ZorkRoom tempRoom = (game.getCurrentRoom()); + tempRoom.item.remove(tempString); + game.put("room", tempRoom); + System.out.println("Item " + tempString + " added to inventory."); + } else { + /* Search all containers in the current room for the item! */ + 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.put("container", tempContainer); + System.out.println("Item " + tempString + " added to inventory."); + return; + } + } + System.out.println("Error"); + } + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/TurnOnAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/TurnOnAction.java new file mode 100644 index 0000000..015df31 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/TurnOnAction.java @@ -0,0 +1,44 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.repl.ActionDispatcher; +import com.github.dtschust.zork.types.ZorkItem; + +import java.util.List; + +/** + * Turn on an item + */ +public class TurnOnAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("turn") && arguments.get(1).equals("on"); + } + + @Override + public int getMinimumArgCount() { + return 3; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String what = arguments.get(2); + + if (game.inventory.contains(what)) { + ZorkItem tempItem = (ZorkItem) game.get("item", what); + System.out.println("You activate the " + what + "."); + if (tempItem != null) { + for (String print : tempItem.turnOnPrint) { + System.out.println(print); + } + final ActionDispatcher effectsDispatcher = new ActionDispatcher(game); + for (final String action : tempItem.turnOnAction) { + effectsDispatcher.dispatch(action); + } + return; + } + } + System.out.println("Error"); + } +} diff --git a/src/main/java/com/github/dtschust/zork/repl/actions/UpdateAction.java b/src/main/java/com/github/dtschust/zork/repl/actions/UpdateAction.java new file mode 100644 index 0000000..0681aa0 --- /dev/null +++ b/src/main/java/com/github/dtschust/zork/repl/actions/UpdateAction.java @@ -0,0 +1,34 @@ +package com.github.dtschust.zork.repl.actions; + +import com.github.dtschust.zork.parser.ZorkGame; +import com.github.dtschust.zork.repl.Action; +import com.github.dtschust.zork.types.ZorkMap; +import com.github.dtschust.zork.types.ZorkObject; + +import java.util.List; + +/** + * The "Update" command figures out what type of item it is, and then change its status + */ +public class UpdateAction extends Action { + @Override + public boolean matchesInput(List arguments) { + return arguments.get(0).equals("Update"); + } + + @Override + public int getMinimumArgCount() { + return 1; + } + + @Override + public void run(ZorkGame game, List arguments) { + final String object = arguments.get(1); + final String newStatus = arguments.get(3); + + ZorkMap collection = (ZorkMap) game.getListThroughLookup(object); + ZorkObject tempObject = collection.get(object); + tempObject.updateStatus(newStatus); + collection.put(tempObject); + } +} 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 9c7502b..c9a0219 100644 --- a/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java +++ b/src/main/java/com/github/dtschust/zork/types/ZorkCreature.java @@ -2,6 +2,7 @@ package com.github.dtschust.zork.types; import com.github.dtschust.zork.Zork; import com.github.dtschust.zork.ZorkCondition; +import com.github.dtschust.zork.parser.ZorkGame; import java.util.ArrayList; import java.util.HashSet; @@ -21,12 +22,12 @@ public class ZorkCreature extends ZorkObject { /* Evaluate the success of an attack*/ - public boolean attack(Zork zork, String weapon) { + public boolean attack(ZorkGame game, String weapon) { if (!vulnerability.contains(weapon)) { return false; } for (ZorkCondition condition : conditions) { - if (!condition.evaluate(zork)) { + if (!condition.evaluate(game)) { return false; } }