diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..16923d19 Binary files /dev/null and b/.DS_Store differ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..19d9aa74 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "java.project.referencedLibraries": [ + "lib/**/*.jar", + "guava-31.1-jre.jar" + ] +} \ No newline at end of file diff --git a/CSC 120 final map.jpg b/CSC 120 final map.jpg new file mode 100644 index 00000000..ca8852d5 Binary files /dev/null and b/CSC 120 final map.jpg differ diff --git a/Final Architecture Diagram.png b/Final Architecture Diagram.png new file mode 100644 index 00000000..04aadf7c Binary files /dev/null and b/Final Architecture Diagram.png differ diff --git a/Game.java b/Game.java new file mode 100644 index 00000000..ee6bbab2 --- /dev/null +++ b/Game.java @@ -0,0 +1,450 @@ +import java.util.*; +import com.google.common.graph.*; + +/** + * The game class controlls the game, keeps track of the player, and keeps track + * of the map. + * + * @author tillie and reed + */ +public class Game { + protected ArrayList inventory; + protected ImmutableGraph map; + protected Place currentPlace; + protected ArrayList currentConnections; + protected boolean stillPlaying; + protected boolean gameComplete; + + /** + * the game constructor. sets up the user's inventory, sets up and places the + * user on the map. + */ + public Game() { + this.inventory = new ArrayList(); + Place outside = new Place("OUTSIDE", "OUTSIDE the tower.", + "You are OUTSIDE the mage\'s tower. Grassy fields surround you. The mage is standing up at the top of the tower, pointing you towards where he dropped his BRASS KEY. The ENTRYWAY seems to be unlocked", + "none", true); + + outside.addItem(new Item("BRASS KEY", "A gleaming brass key")); + this.currentPlace = outside; + this.map = this.ConstructMap(outside); + this.findConnections(); + this.stillPlaying = true; + this.gameComplete = false; + } + + /** + * Creates the map (a immutable graph) for the game. It creates all the places + * the player can move to and populates that place with an array list of items + * that live in it. The places and items get string descriptions. This method + * can be overridden easily to make similar games on different maps. + * + * @param startPlace the starting place for the map, created in the constructor + * @return the complete map of the game + */ + + protected ImmutableGraph ConstructMap(Place startPlace) { + + Place entryway = new Place("ENTRYWAY", "A triangular room with three painted doors.", + "On the wall to your left is a RED DOOR. It seems newly painted. On the middle of the right wall is a newly painted BLUE DOOR. To the right of the BLUE DOOR is a YELLOW DOOR, also newly painted. A RED KEY hands from a string in front of you.", + "none"); + entryway.addItem(new Item("RED KEY", + "A painted RED KEY, with a string through its handle so that it can be hung from a keyhook")); + Place kitchen = new Place("KITCHEN", + "A triangular room with a TABLE, CHAIRS, CABINETS, CAULDRON, and TRAP DOOR.", + "You are in a KITCHEN of sorts. Directly to your right is a TABLE and two CHAIRS. On the TABLE are three bottles of POTION, one PINK, one CYAN, one PURPLE, and some PARCHMENT. Across from you is a bubbling CAULDRON and on the left wall is a counter and several CABINETS. To your immediate left is a trap door to the BASEMENT with a black lock. The only exit is the RED DOOR.", + "RED"); + kitchen.addItem( + new Item("CABINET", "A wooden CABINET with some plates inside. Atop the plates is a BLACK KEY.")); + kitchen.addItem(new Item("TABLE", + "A nondescript wooden TABLE covered in small cuts. Someone wasn't using a cutting board...")); + kitchen.addItem( + new Item("CHAIRS", "Two wicker CHAIRS. You notice one of the NAILs in the back is coming out.")); + kitchen.addItem(new Item("NAIL", "A rusty NAIL")); + kitchen.addItem(new Item("CAULDRON", "A CAULDRON bubbling with green liquid.")); + kitchen.addItem(new Item("PINK POTION", "A mysterious POTION colored PINK. You do not know what it does.")); + kitchen.addItem(new Item("CYAN POTION", "A mysterious POTION colored CYAN. You do not know what it does.")); + kitchen.addItem(new Item("PURPLE POTION", "A mysterious POTION colored PURPLE. You do not know what it does.")); + kitchen.addItem(new Item("PARCHMENT", + "On this PARCHMENT are three diagrams:\nGreen circle + pink circle = green circle\nGreen circle + cyan circle = green circle \nGreen circle + purple circle = an empty circle")); + kitchen.addItem(new Item("BLACK KEY", "A painted BLACK KEY")); + kitchen.addItem(new Item("BLUE KEY", "A painted BLUE KEY")); + + Place basement = new Place("BASEMENT", "A dank BASEMENT full of storage.", + "The BASEMENT is one large square room with lots of nooks and crannies. There are piles of boxes and old furniture stacked haphazardly around you. This does not seem like a safe place for young nieces to hang about. There is a PAPER NOTE hanging from a string right in front of your face. ", + "BLACK"); + basement.addItem(new Item("PAPER NOTE", + "A PAPER NOTE that reads \'Darling Niece, this room is dark and musty. If you stay down here you will catch a cold, nothing useful to you is down here. p.s. pay no attention to the giant bees\'")); + + Place study = new Place("STUDY", "A cozy STUDY room.", + "An orange square area RUG covers most of the floor and a large BOOKSHELF with some brown books and some orange books that takes up the whole outside wall. There is a big CHAIR in the corner across from the BOOKSHELF and a door that's been painted ORANGE across from you.", + "BLUE"); + study.addItem(new Item("CHAIR", "An overstuffed CHAIR in the corner of the STUDY")); + study.addItem(new Item("BOOKSHELF", + "A BOOKSHELF with some orange books, and some brown. You notice that the orange books are grouped in the center of the BOOKSHELF, and the brown books outline the orange-book-rectangle.")); + study.addItem(new Item("RUG", + "An orange square RUG on the floor of the STUDY. There is a small lump underneath... moving the rug reveals an ORANGE KEY")); + study.addItem(new Item("ORANGE KEY", "A painted ORANGE KEY")); + + Place bedroom = new Place("BEDROOM", "A BEDROOM", + "A BEDROOM with a BED, which has a PILLOW sitting on top. There is also a door painted WHITE across from you. On the wall is a PIECE OF PAPER.", + "ORANGE"); + bedroom.addItem(new Item("PIECE OF PAPER", + "A paper note that reads: \'I'm soft but I'm not a kitten\nI'm rectangular but I am not a loaf of bread\nI have a case but I'm not a detective\nI sometimes have feathers but I'm not a bird\nI'm found beneath a head but I'm not a scarf\nWhat am I?")); + bedroom.addItem(new Item("PILLOW", "A feather PILLOW. Moving it reveals a WHITE KEY underneath")); + bedroom.addItem(new Item("WHITE KEY", "A painted WHITE KEY")); + bedroom.addItem(new Item("BED", "A BED with a PILLOW. There is nothing remarkable about it.")); + + Place bathroom = new Place("BATHROOM", "A small BATHROOM", + " A BATHROOM. There's a TOILET on the far wall. Closer to the door is a SINK with a TRASH BIN underneath and a MIRROR above.", + "WHITE"); + bathroom.addItem(new Item("TOILET", "This wizard should probably clean his TOILET more frequently...")); + bathroom.addItem(new Item("SINK", "A nondescript SINK.")); + bathroom.addItem(new Item("TRASH BIN", + "A small TRASH BIN underneath the bathroom SINK. Moving a piece of tissue reveals a YELLOW KEY!")); + bathroom.addItem(new Item("MIRROR", + "This MIRROR is rather dirty... When you breath on it to try and wipe some grime off, an arrow design is exposed. The arrow points downward...")); + bathroom.addItem(new Item("YELLOW KEY", "A painted YELLOW")); + + Place stairs = new Place("STAIRCASE", "A tall winding STAIRCASE.", + "A tall winding spiral STAIRCASE. At the top of the stairs is a BRASS DOOR.", "YELLOW"); + + Place balcony = new Place("BALCONY", "A BALCONY with a scenic view, and a sleepy old man", + "A balcony with a scenic view, and a sleepy old man", "BRASS"); + ImmutableGraph map = GraphBuilder.undirected() + .immutable() + .putEdge(startPlace, entryway) + .putEdge(entryway, kitchen) + .putEdge(kitchen, basement) + .putEdge(entryway, study) + .putEdge(study, bedroom) + .putEdge(bedroom, bathroom) + .putEdge(entryway, stairs) + .putEdge(stairs, balcony).build(); + return (map); + } + + /** + * Fetches the arraylist of nodes that share an edge with the currentPlace node, + * and repopulates the currentConnections attribute. + */ + + protected void findConnections() { + this.currentConnections = new ArrayList(this.map.adjacentNodes(this.currentPlace)); + } + + /** + * A helpful function for the programmer of the game. A call to this function + * can be placed in the Game.play() loop to explore the current connections in + * the map as the programmer playtests their game to ensure the map is set up + * correctly. + */ + protected void printConnections() { + System.out.println("You are currently in " + this.currentPlace.getName() + + "\n\nThe following places are connected to this location:"); + for (Place room : this.currentConnections) { + System.out.println(room.getName()); + } + } + + /** + * a method that allows the player to move between connected places on the map, + * called from within the Game.play loop when Game.executeAction() finds the + * appropriate keyword. + * + * @param statement The string that the user input to the game. If the + * executeAction() method searched correctly, this contains the + * words "move", and if the user input a valid statement, it + * should also contain the name of the place (or the door color + * the first time the user enters that room) + */ + + protected void move(String statement) { + Place newPlace = null; + for (Place place : this.currentConnections) { + String name = place.getName(); + String keyColor = place.getKeyColor(); + if (statement.contains(name) || statement.contains(keyColor)) { + // loop through each inventory item + for (Item item : this.inventory) { + // is it the key that we need? if yes, overwrite newPlace, because we can go + // there! + if (item.name.contains(keyColor)) { + newPlace = place; + } + } + // For the entryway, no key is needed, so this extra step is necessary because + // the inventory at the moment is 0 + if (place.needsKey == "none") { + newPlace = place; + } + } + + } + // After all the looping, check if newPlace was overwritten (we had a key and + // were next to a door) + if (newPlace != null) { + // If we are good to go, change current places and rewrite current connections + this.currentPlace = newPlace; + // make sure that 'explored' is set to true for the printExploredLocations + // function + this.currentPlace.explored = true; + System.out.println("You have moved to " + newPlace.name); + this.findConnections(); + } else { + System.out.println( + "I'm sorry, you either can't go there yet or misspelled a word. Try again! (If you don't know what to do, try typing \"Help\".) "); + } + if (this.currentPlace.name.contains("BALCONY")) { + this.gameComplete = true; + } + + } + + /** + * a method that allows the player to learn more about an object. + * + * @param statement a string containing the name of the item the player wants to + * learn more about. + */ + + protected void examine(String statement) { + String itemDesc = null; + for (Item obj : this.inventory) { + if (statement.contains(obj.name)) { + itemDesc = obj.shortDesc; + break; + } + } + if (itemDesc == null) { + for (Item obj : this.currentPlace.inventory) { + if (statement.contains(obj.name)) { + itemDesc = obj.shortDesc; + break; + } + } + } + itemDesc = itemDesc == null ? "This item does not appear to be nearby. Make sure you typed its name correctly!" + : itemDesc; + System.out.println(itemDesc); + } + + /** + * a method that prints the players inventory to the console, so the player can + * see what items they are carrying. + */ + protected void printInventory() { + System.out.println("You have the following items in your inventory:"); + for (Item item : this.inventory) { + System.out.println(item.shortDesc); + } + } + + /** + * a method that allows the player add an item to their inventory. This also + * removes the item from the room's inventory. + * + * @param item a string containing the name of the object the player wants to + * add to their inventory. + */ + protected void take(String item) { + boolean itemFound = false; + for (Item obj : this.inventory) { + if (item.contains(obj.name)) { + System.out.println("The item " + obj.name + + " is already in your inventory! If you meant a different item, make sure you've typed its full name in correctly (i.e., \"RED KEY\" instead of \"KEY\")"); + itemFound = true; + break; + } + } + if (itemFound == false) { + for (Item obj : this.currentPlace.inventory) { + if (item.contains(obj.name)) { + this.currentPlace.removeItem(obj); + this.inventory.add(obj); + System.out.println("You have taken " + obj.name); + itemFound = true; + break; + } + } + } + if (!itemFound) { + System.out.println( + "This item does not appear to be nearby... make sure you typed it in correctly! (Hint: Type \'take [item]\')"); + } + } + + /** + * a method that allows the player to remove an item from their inventory and + * adds that item to the inventory of the room they are currently in. + * + * @param item a string containing the name of the item + */ + + protected void drop(String action) { + boolean itemFound = false; + String itemName = ""; + for (Item obj : this.inventory) { + if (action.contains(obj.name)) { + itemName = obj.name; + this.inventory.remove(obj); + this.currentPlace.addItem(obj); + System.out.println("You have dropped the " + obj.name); + itemFound = true; + break; + } + } + if (!itemFound) { + System.out.println("There doesn't appear to be a " + itemName + + " in your inventory. If you think this is an error, make sure you type in the full name of an object!"); + } + } + + /** + * a method allowing the user to pour a potion into the cauldron, revealing the + * blue key. + * + * @param action a string containing the color of the potion they are using. + */ + protected void pourPotion(String action) { + if (action.contains("PINK")) { + System.out.println( + "You pour the PINK POTION into the CAULDRON. A puff of smoke goes up, but once it clears, nothing has changed. Perhaps you should look around for clues?"); + } else if (action.contains("CYAN")) { + System.out.println( + "You pour the CYAN POTION into the CAULDRON. A puff of smoke goes up, but once it clears, nothing has changed. Perhaps you should look around for clues?"); + } else if (action.contains("PURPLE")) { + System.out.println( + "You pour the PURPLE POTION into the CAULDRON. A puff of smoke goes up, and once it clears, you see the cauldron is now empty of liquid. A BLUE KEY lies in the bottom of it."); + } + } + + /** + * a method that is run on all scanned user input while the game is being + * played. It finds the key word for the available actions (move, take, drop, + * etc) and sends that input to the appropriate method. + * + * @param action a string containing what the player wants to do + */ + protected void executeAction(String action) { + if (action.contains("MOVE ")) { + this.move(action); + } else if (action.contains("LOOK AROUND")) { + System.out.println(this.currentPlace.longDesc); + + } else if (action.contains("EXAMINE ")) { + this.examine(action); + } else if (action.contains("TAKE ")) { + this.take(action); + } else if (action.contains("DROP ")) { + this.drop(action); + } else if (action.contains("POTION")) { + this.pourPotion(action); + } else if (action.contains("EXIT")) { + this.stillPlaying = false; + } else if (action.contains("HELP")) { + this.help(); + } else if (action.contains("INVENTORY")) { + this.printInventory(); + } else if (action.contains("PAST")) { + this.printExploredLocations(); + } else { + System.out.println( + "I'm sorry, I do not understand what you wrote. If you don't know what to do, try typing \"Help\"."); + } + } + + /** + * a method that prints out the actions that the player can do as well as how + * the game expects the input to be + * formated. + */ + protected void help() { + System.out.println( + "************** HELP MENU ************** \nYou can call this menu up at any time by typing the command ‘help’ into the console. \nThe action formula this game allows are:\n" + + // + "move to [place]\n" + // + "move to [color] [door]\n" + // + "look around\n" + // + "examine [item]\n" + // + "take [item]\n" + // + "drop [item]\n" + // + "pour [color] potion\n" + // + "exit\n" + // + "print inventory\n" + // + "print past locations\n" + // + "help\n"); + } + + protected void printExploredLocations() { + System.out.println("You have been to all of these locations:"); + for (Place exploredPlace : this.map.nodes()) { + if (exploredPlace.explored) { + System.out.println(exploredPlace.name + ": " + exploredPlace.shortDesc); + } + } + } + + /** + * a method that sets up the game (imports the scanner, prints exposition and + * helpful action reccomendations) and sets up the do...while loop that will + * keep the game running. When the do...while loop ends, it will print out the + * end of game code, and let the player accept or decline the mage's reward + * offer. It also closes the scanner. + */ + public void play() { + Scanner sc = new Scanner(System.in); + System.out.println("\n\n************** WELCOME TO THE MAGE'S TOWER **************\n"); + this.help(); + System.out.println( + "It\'s a sunny day and you are surrounded by beautiful grassland. Ahead is a tower, similar to one most mages build, and beyond that is your destination: Wildeshore City. Due to excellent travel conditions, you\'re running two days early and should arrive by nightfall. \n" + + // + "As you begin to pass by the mage\'s tower you hear a voice from above: \n\"What ho there, traveler! Do you think you could lend an old man a hand?\" \n" + + // + "Looking up, you see a weathered man with a long beard waving down at you from the tower\'s balcony. When he sees that he has your attention, he calls out again:\n" + + // + "\"I seem to be rather stuck up here! You see, I was making a puzzle for my neice but I\'ve locked myself at the top of my tower and dropped the key!\"\n" + + // + "Casting a look around, you indeed see a BRASS KEY in the grass next to the tower. \n" + // + "\"If you could come up and unlock this door, I\'d be forever grateful,\" the mage continues, \"I can even give you a reward if you\'d like.\" \n" + + // + "A reward does sound nice… and you\'re running early.\n" + // + ""); + + System.out.println("What would you like to do? (hint: try looking around for a moment!)"); + do { + executeAction(sc.nextLine().toUpperCase()); + } while (this.stillPlaying && !this.gameComplete); + if (this.gameComplete) { + System.out.println( + "You open the final door, revealing a covered balcony. On the stone floor is an intricate painting of the sun. While most of the building is made of pale yellow stone, the domed ceiling above you is a beautiful robin\'s egg blue decorated with gold accents. In front of you is the old man, who has obviously just woken up at the sound of your entrance. He seems very happy to see you."); + System.out.println( + "\"Well done traveler!\" he says, \"I knew you would crack those puzzles eventually. Now let\'s see, about that reward…\" he pauses for several seconds before seeming to get an idea; \"How about I\'ll make another puzzle for you for when you travel back this way hm?\""); + String acceptPuzzle = ""; + do { + System.out.println("Do you accept his offer? (yes/no)"); + acceptPuzzle = sc.nextLine().toUpperCase(); + } while (!(acceptPuzzle.contains("YES") || acceptPuzzle.contains("NO"))); + if (acceptPuzzle.contains("YES")) { + System.out.println( + "\"Excellent!\" The old man says, rubbing his hands together gleefully. \"I'll try to make the next one even harder, suitable for an adventurer so talented as yourself. Until then...\""); + } else { + System.out.println( + "\"I understand,\" he says, \"surely an adventurer so talented as yourself must be very busy. I thank you sincerely for helping me out of my predicament, and wish you a merry journey forward!\""); + } + System.out.println( + "He spins on the spot, and disappears in a puff of smoke. You make your way to Wildeshore City with only one remaining question: if he could teleport, why didn't he just get down that way?\""); + } + sc.close(); + } + + /** + * the main method that creates the game and runs the play() method on the new + * game. + */ + public static void main(String[] args) { + Game game = new Game(); + game.play(); + } + +} diff --git a/Item.java b/Item.java new file mode 100644 index 00000000..4027c834 --- /dev/null +++ b/Item.java @@ -0,0 +1,21 @@ +/** + * The item class creates items that have names, descriptions, and (if they can only be used a set number of times) + * sets their limited use and how many times they can be used. + * @author tillie + */ +public class Item { + String name; + String shortDesc; + + + public Item(String name, String shortDesc) { + this.name = name; + this.shortDesc = shortDesc; + } + public Item(String desc) { + this.name = desc; + this.shortDesc = desc; + } + + +} diff --git a/Place.java b/Place.java new file mode 100644 index 00000000..58d21bff --- /dev/null +++ b/Place.java @@ -0,0 +1,79 @@ +import java.util.ArrayList; + +/** + * The place class creates the rooms that the player can exist in. These places will be added to the map. The places + * have a name, descriptions, and a boolean stating if it needs a key to be entered. Each place also has an + * inventory that can be added to and taken away from. + */ +public class Place { + public ArrayList inventory; // an arraylist of interactable objects within a given place + public String name; + public String shortDesc; + public String longDesc; + public String needsKey; + public boolean explored; + + + public Place() { + this.inventory = new ArrayList(); + this.name = "name"; + this.shortDesc = "shortDesc"; + this.longDesc = "longDesc"; + this.needsKey = "none"; + this.explored = false; + } + + + public Place(String name, String shortDesc, String longDesc, String needsKey) { + this.inventory = new ArrayList(); + this.name = name; + this.shortDesc = shortDesc; + this.longDesc = longDesc; + this.needsKey = needsKey; + this.explored = false; + } + + public Place(String name, String shortDesc, String longDesc, String needsKey, boolean explored) { + this.inventory = new ArrayList(); + this.name = name; + this.shortDesc = shortDesc; + this.longDesc = longDesc; + this.needsKey = needsKey; + this.explored = explored; + } + + /** + * a getter method that returns the name of the place + * @return a String containing the name of the place + */ + public String getName() { + return(this.name); + } + + /** + * a getter method that returns the color of the key needed to enter a room. + * @return a string containing the color of the key needed to enter a place. + */ + public String getKeyColor() { + return(this.needsKey); + } + + /** + * a method that allows an item to be added to the place's inventory + * @param item an item that will be added to the place's inventory + *note: there is a check that makes sure an item won't be added to a place's inventory twice. + */ + public void addItem(Item item) { + this.inventory.add(item); + } + + /** + * a method that removes an item from the place's inventory. + * @param item an item that will be added to the place's inventory. + */ + public void removeItem(Item item) { + this.inventory.remove(item); + } + + +} diff --git a/README.md b/README.md index c1a995eb..c1461f6e 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,43 @@ - Your final codebase - Your revised annotated architecture diagram - Design justification (including a brief discussion of at least one alternative you considered) + + We ended up with three separate classes(Game, Place, and Item) for our game. In the beginning, we actually had an additional Player class but we decided to integrate it into the Game class because Player was doing the same things the Game needed to do so it made more sense to make one larger Game class then have two slightly smaller classes that did mostly the same thing. The Game class essentially keeps track of the user’s progress and place in the game. It instantiates the entire map of the game, holds all the methods containing the player’s actions, and has a play() method that holds the do…while loop and prints the exposition and ending to the game. The main method also sits in the Game class - for simplicity in the main method, the Game.play() method was constructed so that the only code necessary in the main method was the construction of a Game object, and a call to the Game.play() method. + - A map of your game's layout (if applicable) - `cheatsheet.md` - Completed `rubric.md` ## Additional Reflection Questions - What was your **overall approach** to tackling this project? + + We both knew that this sort of project would take a lot of time so from the first day we set up a weekly flexible meeting time so we would always have at least one chance a week to talk in person outside of class. We spent most of the first few classes just talking about what we hoped to include and what we thought wouldn’t work. This thoughtful approach, even though it slowed down the actual coding aspect of the project, helped us keep a clear idea of the project in mind. We made sure each of us was having a good time by assigning tasks that were enjoyable as well as challenging. For example, Reed did a lot of the storyboarding and creating descriptions for items and rooms as well as coming up with the puzzles the user would interact with along the way, while Tillie spent more time integrating and adapting those ideas into the actual code. + - What **new thing(s)** did you learn / figure out in completing this project? + The biggest “new thing” to learn was definitely Guava maps. There were a lot of different classes to comb through before we could settle on the final one. We even had to change the class last minute from MutableGraph to ImmutableGraph after making a secondary design decision about how the take() method would work (previously thought it would add a connection between nodes if a room had been unlocked, scrapped that idea for the current procedure). Although it didn’t end up being used in the final iteration, we also learned a bit about the Pattern() and Matcher() classes, because there was a moment when we wanted to parse through the user-input action to find the secondary action specifier (i.e. ‘red key’ in ‘take red key’), but realized halfway through implementation that it was much simpler to just test for equality using String.contains(). + - Is there anything that you wish you had **implemented differently**? + + It would have been nice to impose a size limit on the user’s inventory, so that if they took a lot of extraneous stuff, they would be forced to drop some items. Perhaps we could have even imposed a limit that forced the player to think about which keys they no longer needed, adding another layer of thinking ahead. + - If you had **unlimited time**, what additional features would you implement? + + If we had more time, we would have developed a relationship between the items in a room and the description that gets printed out when the user looks around. As is, taking an item does not change the description at all, but it would be more realistic for the Item() class to have some sort of attribute that gets added to the longDesc attribute of a Place() when it is added to the Place’s inventory. + - What was the most helpful **piece of feedback** you received while working on your project? Who gave it to you? + + One piece of feedback we heard a few times (but primarily from Ian Eskesen) during workshop 3 was to make it clearer what interaction options were available to the user. This led us to capitalize every interactable item so that it was more clear to the user what was meant to be examined, picked up, etc. We were slightly concerned that it would be too much “hand holding” but reasoned that meta-knowledge infiltrates even the most open-world games, so it’s probably fine for this small-scale project. + - If you could go back in time and give your past self some **advice** about this project, what hints would you give? - - _If you worked with a team:_ please comment on how your **team dynamics** influenced your experience working on this project. + + We would tell our past selves that they have to consider making a smaller game than what they originally thought of. Our original game concept was about double the size with a whole mirror realm-rescue situation. While it was a great idea, we definitely didn’t have the time to achieve it so it's very good that we ended up cutting it down. Having it be smaller from the start probably would have lessened the collective stress though. + + - _If you worked with a team: please comment on how your **team dynamics** influenced your experience working on this project. + +We had very good communication! Frequent discord messages, meetings, etc. Specifically the frequent meetings were very helpful in keeping each other up to date. Each team member played to their strengths in terms of planning and execution of the game idea. + +Thank you to Reed for the amazing and wonderful idea of not doing a two-layered tower game when we realized how little time we had left…… the puzzle that ended up being executed was much more manageable and fun to play in one sitting!! + +Shout out to Tillie for slaying so much of the code. I would not have been able to complete even a fraction of what they did in the given time by myself. + +Also apologies to Jordan for the many many pull requests… diff --git a/cheatsheet.md b/cheatsheet.md index d5dc4294..ffcfc213 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -2,7 +2,70 @@ This file will contain documentation for all commands available in your game. Note: It's a good idea to also make this list available inside the game, in response to a `HELP` command. +All possible player commands: +move to [place] +move to [color] [door] +look around +examine [item] +take [item] +drop [item] +pour [color] potion +exit +print inventory +print past locations +help # SPOILER ALERT If your game includes challenges that must be overcome to win, also list them below. +All possible player commands: +move to [place] +move to [color] [door] +look around +examine [item] +take [item] +drop [item] +pour [color] potion +exit +print inventory +print past locations +help + +take brass key +Move to entryway +Take red key +Move to red door +Pour purple potion* +(*Note:* here, you can immediately pick up the blue key, but the game will only tell you it is there if you pour the purple potion) +Take blue key +Move to entryway +Move to blue door +Examine rug* +(*Note:* here, you can immediately pick up the orange key, but the game will only tell you it is there if you examine the rug first) +Take orange key +Move to orange door +Examine pillow* +(*Note:* here, you can immediately pick up the white key, but the game will only tell you it is there if you examine the pillow first) +Take white key +Move to white door +Examine trash bin* +(*Note:* here, you can immediately pick up the yellow key, but the game will only tell you it is there if you examine the trash bin first) +Take yellow key +Move to bedroom +Move to study +Move to entryway +Move to yellow door +Move to brass door +Answer “yes” or “no” (this will have no bearing on the completeness of the game, merely a slightly different dialogue from the mage). +[Game is complete] + +*Optional!!* +*While in the kitchen, do:* + +Examine cabinet* +(*Note:* here, you can immediately pick up the black key, but the game will only tell you it is there if you examine the cabinet first) +take black key +move to black door OR move to basement +examine parchment + +*Literally nothing of consequence is in the basement, it is just a fun side area that makes the player think there is something larger and potentially more nefarious (or at least violating of building code) going on here* diff --git a/guava-31.1-jre.jar b/guava-31.1-jre.jar new file mode 100644 index 00000000..16819229 Binary files /dev/null and b/guava-31.1-jre.jar differ diff --git a/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar new file mode 100644 index 00000000..9d5fe16e Binary files /dev/null and b/lib/hamcrest-core-1.3.jar differ diff --git a/lib/junit-4.13.2.jar b/lib/junit-4.13.2.jar new file mode 100644 index 00000000..6da55d8b Binary files /dev/null and b/lib/junit-4.13.2.jar differ diff --git a/rubric.md b/rubric.md index 8bb8f4c8..ef10cb16 100644 --- a/rubric.md +++ b/rubric.md @@ -1,48 +1,50 @@ ## Front-End Design (10 pts) -_____ 2 pts: Game has a **robust, understandable text-based interface** that allows the player to control their movement through the game. Player should be able to enter any command at any time, and if it makes sense in the current context it will be carried out. +**YES** 2 pts: Game has a **robust, understandable text-based interface** that allows the player to control their movement through the game. Player should be able to enter any command at any time, and if it makes sense in the current context it will be carried out. -_____ 2 pts: Submission includes a **cheat sheet** (`cheatsheet.md`) documenting all of the available commands, as well as a **description of the layout** of your game world's underlying physical layout; this can be described in words, or included as a separate image file if you prefer to sketch a map by hand. If your game includes **challenges** that must be overcome to win, also describe them here. +**YES** 2 pts: Submission includes a **cheat sheet** (`cheatsheet.md`) documenting all of the available commands, as well as a **description of the layout** of your game world's underlying physical layout; this can be described in words, or included as a separate image file if you prefer to sketch a map by hand. If your game includes **challenges** that must be overcome to win, also describe them here. -_____ 2 pts: Storyline driving the game is **engaging**, and individual elements of play make sense within the context of the story. +**YES** 2 pts: Storyline driving the game is **engaging**, and individual elements of play make sense within the context of the story. -_____ 2 pts: Game has **multiple possible paths / outcomes** (i.e. gameplay depends on player's choices and is not the same every time). +**YES\*** 2 pts: Game has **multiple possible paths / outcomes** (i.e. gameplay depends on player's choices and is not the same every time). -_____ 1 pt: Gameplay supports **reversible moves** where reasonable (e.g., if you pick up an object, you should be able to put it back down again later, possibly in a different place; if you go north then you should be able to return to the previous location by going south unless something has blocked your return path). +\* The game has one "win path" but it is possible to wander around lost/confused for a while without conequence before finding the win conditions. Also, there's the basement which is just there for fun and has absolutely 0 effect on the game's final outcome. -_____ 1 pt: Some paths through the game have **restricted access** until the player has completed a task or acquired a specific item (i.e. a key to open a door, etc.). +**YES** 1 pt: Gameplay supports **reversible moves** where reasonable (e.g., if you pick up an object, you should be able to put it back down again later, possibly in a different place; if you go north then you should be able to return to the previous location by going south unless something has blocked your return path). + +**YES** 1 pt: Some paths through the game have **restricted access** until the player has completed a task or acquired a specific item (i.e. a key to open a door, etc.). ## Back-End Design (10 pts) -_____ 2 pts: Selected classes(s) are **effective, efficient** at supporting the desired operations and program behavior. +**YES** 2 pts: Selected classes(s) are **effective, efficient** at supporting the desired operations and program behavior. -_____ 2 pts: Design justification includes a discussion of at least one (reasonable) **alternative design** that could have been used, and the reasons why you decided against this alternative. +**YES** 2 pts: Design justification includes a discussion of at least one (reasonable) **alternative design** that could have been used, and the reasons why you decided against this alternative. -_____ 2 pts: The project makes effective use of **Java built-in classes** whenever they are appropriate. +**YES** 2 pts: The project makes effective use of **Java built-in classes** whenever they are appropriate. -_____ 2 pts: The project's design is **extensible** (i.e. someone else could pick up where you left off, adding on or modifying the game without requiring a total rewrite). +**YES** 2 pts: The project's design is **extensible** (i.e. someone else could pick up where you left off, adding on or modifying the game without requiring a total rewrite). -_____ 2 pts: Submission includes an **architecture diagram** describing the relationships between all classes. +**YES** 2 pts: Submission includes an **architecture diagram** describing the relationships between all classes. ## General Items (10 pts): -_____ 4 pts: Program compiles without errors or warnings. +**YES** 4 pts: Program compiles without errors or warnings. -_____ 2 pts: Executes fully & consistently without crashing (exception/freeze). +**YES** 2 pts: Executes fully & consistently without crashing (exception/freeze). -_____ 2 pt: Complies with style guidelines (missing items 1 pt each): +**YES** 2 pt: Complies with style guidelines (missing items 1 pt each): - _____ Classes & class members all have Javadoc header comments. + **YES** Classes & class members all have Javadoc header comments. - _____ Clear and consistent indentation of bracketed sections. + **YES** Clear and consistent indentation of bracketed sections. - _____ Adheres to Java conventions on naming & capitalization. + **YES** Adheres to Java conventions on naming & capitalization. - _____ Methods & variables all have clear and accurate names. + **YES** Methods & variables all have clear and accurate names. - _____ Methods avoid confusing side effects. + **YES** Methods avoid confusing side effects. -_____ 1 pt: All required files included with submission (including completed checklist file). +**YES** 1 pt: All required files included with submission (including completed checklist file). -_____ 1 pt: `readme.md` contains your reflection on the project and responses to all prompts . +**YES** 1 pt: `readme.md` contains your reflection on the project and responses to all prompts .