/* PlayDungeon.java CIS 250 2014-03-11 David Klick Modified 2017-02-11 - added ITEM as a valid data input for dungeon - added ability for rooms to hold objects - added ability for player to carry objects - added additional commands to parser: inv, take, drop, help - revamped parser to handle two word commands - added code to support an actual goal - added a considerable amount of debugging information Modified 2018-02-23 by dgk This is the driver to play a simple text-based dungeon game. The coding may be a bit rough since this was originally a conversion from a C++ version. */ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Scanner; public class PlayDungeon { public static void main(String[] args) { Room room; Path path; LinkedList inv = new LinkedList(); boolean done = false; String fileName = "dungeon.txt"; int datafileCount = 0; int i; boolean debug = false; boolean error = false; String action, object; // create dungeon Dungeon dungeon = new Dungeon(); // parse options and arguments to program for (i=0; i 0) && (args[i].charAt(0) == '-')) { System.err.println("Unrecognized option: " + args[i]); error = true; } else { if (datafileCount > 1) { System.err.println("Error: Multiple data files specified"); System.err.println("Usage: java PlayDungeon datafileName"); error = true; } else { fileName = args[i]; datafileCount++; } } } // end program if error encountered if (error) System.exit(1); // read in data file to populate dungeon readFile(dungeon, fileName); // initialize dungeon if (dungeon.rooms.size() == 0) { System.err.println("Error: No rooms in dungeon"); System.exit(4); } if (dungeon.currentRoom.length() == 0) { dungeon.currentRoom = dungeon.rooms.get(0).id; } // display debugging info if requested if (debug) { System.out.println("Debugging information:"); System.out.println("Number of rooms: " + dungeon.rooms.size()); System.out.println("List of rooms:"); for (int j=0; j 0) System.out.println(" Paths:"); for (int k=0; k 0) System.out.println(" Items:"); for (int m=0; m 2) System.out.println("Command not understood"); else { // command is one or two tokens long action = commands[0]; object = (commands.length > 1) ? commands[1] : null; if (action.equals("go")) { action = object; object = null; } switch (action) { case "drop": if (object == null) System.out.println("You must specify an object to drop"); else { for (i=inv.size()-1; i>=0; i--) { Item item = inv.get(i); if (item.name.equals(object) || object.equals("all")) { current.items.push(item); inv.remove(item); if (!object.equals("all")) break; } } Item item1 = findItem(current, "bike"); Item item2 = findItem(current, "instructor"); if (item1 != null && item2 != null) { current.items.remove(item1); current.items.remove(item2); System.out.println("The instructor wakes up and gets on the bike."); System.out.println("Before you can ask him what's happening, he pedals off"); System.out.println("and leaves the building going south from the east hall."); Path p = new Path("s", "outside"); Room r = dungeon.getRoom("east hall south"); r.paths.push(p); r.description = r.description.replace(" locked", " now unlocked"); r.visited = false; } } break; case "take": if (object == null) System.out.println("You must specify an object to take"); else { for (i=current.items.size()-1; i>=0; i--) { Item item = current.items.get(i); if (item.name.equals(object) || object.equals("all")) { inv.push(item); current.items.remove(item); } } } case "inv": StringBuilder sb = new StringBuilder("You are carrying: "); if (inv.size() == 0) sb.append("nothing"); else { for (i=0; i 0) sb.append(", "); sb.append(inv.get(i).name); } } System.out.println(sb.toString()); break; case "quit": done = true; break; case "exit": System.out.println("Use 'quit' to end the game."); break; case "help": System.out.println("Commands are: help, quit, look, drop, take, go, inv, and the exit directions"); break; case "look": current.visited = false; break; case "xyzzy": // check for regalia in inventory boolean hasRegalia = false; for (i=0; i dataLines = new ArrayList<>(); File dataFile = new File(filename); if (!dataFile.exists() || !dataFile.canRead()) { System.err.println("Error: Could not open/read data file"); System.exit(1); } try { java.nio.file.Path dataPath = FileSystems.getDefault().getPath(filename); dataLines = Files.readAllLines(dataPath, StandardCharsets.UTF_8); } catch (IOException e) { System.err.println("Error: I/O error while processing data file"); System.exit(2); } String previousLine = ""; for (String linein : dataLines) { if (linein.length() == 0) continue; if (linein.startsWith("ROOM:") || linein.startsWith("PATH:") || linein.startsWith("ITEM:") || linein.startsWith("INIT:")) { processLine(dungeon, previousLine); previousLine = ""; } if (previousLine.length() > 0) previousLine = previousLine + " "; previousLine = previousLine + trim$(linein); } processLine(dungeon, previousLine); } // routine to process one line of a dungeon data file // this will throw an exception if it has any problems private static void processLine(Dungeon dungeon, String line) { String[] fields; if (line.startsWith("ROOM:") || line.startsWith("PATH:") || line.startsWith("ITEM:")) { fields = line.split(":"); if (fields.length < 4) { System.err.println("Error: Problem parsing data file"); System.err.println(" " + line); System.exit(3); } fields[0] = trim$(fields[0]); fields[1] = trim$(fields[1]); fields[2] = trim$(fields[2]); fields[3] = trim$(fields[3]); if (line.startsWith("ROOM:")) { if (dungeon.getRoom(fields[1]) != null) { System.err.println("Error: Duplicate room ID found in data file"); System.exit(3); } dungeon.rooms.push(new Room(fields[1], fields[2], fields[3])); } else if (line.startsWith("PATH")) { Room roomSrc = dungeon.getRoom(fields[2]); Room roomDest = dungeon.getRoom(fields[3]); if (roomSrc == null) { System.err.printf("Error: Path from unknown room (%s) encountered in data file%n", fields[2]); System.err.println(" " + line); System.exit(3); } if (roomDest == null) { System.err.printf("Error: Path to unknown room (%s) encountered in data file%n", fields[3]); System.err.println(" " + line); System.exit(3); } Path path = roomSrc.getPath(fields[1]); if (path != null) { System.err.printf("Error: Duplicate path from room (%s) encountered in data file%n", fields[2]); System.err.println(" " + line); System.exit(3); } roomSrc.paths.push(new Path(fields[1], fields[3])); } else { // must be an ITEM Room room = dungeon.getRoom(fields[3]); if (room == null) { System.out.println("Room for item not found (" + room.id + ")"); } else { room.items.push(new Item(fields[1], fields[2], fields[3])); } } } else if (line.startsWith("INIT:")) { fields = line.split(":"); dungeon.currentRoom = trim$(fields[1]); } return; } private static String ltrim$(String s) { if (s == null) return ""; StringBuilder sb = new StringBuilder(s); while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) sb.deleteCharAt(0); return sb.toString(); } private static String rtrim$(String s) { if (s == null) return ""; StringBuilder sb = new StringBuilder(s); while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length()-1))) sb.deleteCharAt(sb.length()-1); return sb.toString(); } private static String trim$(String s) { return s==null ? "" : ltrim$(rtrim$(s)); } // prints room description // diplays short description if room is marked as // visited and long description otherwise private static void describeRoom(Room room) { int i; System.out.println("You are in " + room.name); if (!room.visited) System.out.println(room.description); if (room.paths.size() == 0) { System.out.println("There are no exits"); } else { for (i=0; i 0) System.out.print(", "); System.out.print(room.paths.get(i).direction); } System.out.println(); } room.visited = true; } }