Info Lectures Assignments Office Hours Hall of Fame Notes
Info Lectures Assignments Office Hours Hall of Fame Notes

Amazing Adventures

Assigned: 2022-02-02
Due Date: 2022-02-08 by 11:59PM U.S. Central Time

Assignment

Get your copy of the assignment here

You may encounter "Non-managed pom.xml file found". You should select "Add as Maven Project"

This week's assignment is a creative exercise where you get to build a text adventure game! In the previous assignment, we asked you to find a JSON and parse it. This time, you'll actually be creating the JSON to our specifications and using it in a console adventure game.

Note: For this week's assignment, you should only work in the adventure directory in the student folder; ignore the server directory for now. Similarly, don't modify any of the given files in the resources folder.

Gradescope

There is no autograder for this assignment, but you still must submit your GitHub repository to Gradescope.

Goals

Instructions

Background

The Adventure Game is a classic video game genre that generally features a protagonist exploring a map and solving puzzles. From Wikipedia:

Initial adventure games developed in the 1970s and early 1980s were text-based, using text parsers to translate the player's input into commands. As personal computers became more powerful with better graphics, the graphic adventure-game format became popular, initially by augmenting player's text commands with graphics, but soon moving towards point-and-click interfaces. Further computer advances led to adventure games with more immersive graphics using real-time or pre-rendered three-dimensional scenes or full-motion video taken from the first- or third-person perspective.

You'll be designing a text-based adventure game, where the user will input commands and your game engine will parse them into actions. You'll send back the feedback in text form to the user.

You'll also be designing a map for the game (no, not a Map<K, V>; the normal kind of map). Your map should have rooms with paths/connections to other rooms, and there should be a goal room that when reached, the player wins the game. However, you can also interpret this to be more of a story-based format where "paths" represent dialogue options; you have a lot of freedom here so long as you can interact with the world or story in some meaningful way.

Part 0 - Designing JSON

It's time to put your JSON knowledge to the test. Hardcoding all of the rooms & game data into your codebase is inflexible and cluttered, so we will instead use JSON to store data about your map, items in your game, etc. To help get you started, we've provided a sample JSON with a couple of objects filled in: rooms, directions, and an outer layout object. There are three object types described in the given JSON:

Direction

{
  directionName : String
  room          : String        // the String name of the room this direction points to
}

Room

{
  name		    : String
  description	: String
  directions	: Direction[]
}

Layout

{
  startingRoom	: String        // the String name of the room the player starts in
  endingRoom    : String        // the String name of the room the player must reach to win
  rooms		    : Room[]
}

These three are enough to define rooms that your player can traverse by specifying what direction they wish to move in. However, we'd like to add a little extra ingredient. For this week, your game should handle in-game items! An item has a name and any other properties you'd like to add to it. Rooms can store items (representing the item is present in the room). With all of this information, you need to add items to your JSON, as points will be lost if you hardcode items in the code. There is not one correct way to do this, but you'll need to figure out how to modify the given schema to include items on your own.

The example JSON provided is a bit boring... so we want you to create your own adventure map JSON! Try to come up with something creative and with at least a couple more rooms than the example JSON. Feel free to theme it to your interests, e.g.: a favorite show or video game. Using the example JSON as a guide should prove very helpful; just don't forget to add in items.

You could complete this part at any time, but we recommend doing it before you get too deep into your design.

Part 1 - Loading Game Data

You just finished a JSON schema with all the data that your game needs, but now you need to load it for your game engine to consume.

The first thing you should tackle is creating POJOs corresponding to the objects in your JSON. The three objects described in the section above correlate nicely to Java objects, but the design for the Item object is up to you.

You should have experience loading JSON from the last assignment; in this assignment, you may use GSON or Jackson again to preform this task. However, this time loading JSON is part of your application, so you must handle & test it. Pay attention to what happens when:

, and be sure to handle these cases gracefully.

Part 2 - The Game Engine

You now need to write the brains of your game. Once again, we are giving you a lot of freedom in how exactly you accomplish this, but we have some basic interactions we would like to see. The game should accept input from the user in the console, and should output data back to the console.

Because you are requesting user input, it would be helpful to have a prompt. A prompt is a small string that gets printed at the beginning of the line in the console to indicate that the user should type input. Before you request input from the user, we'd like you to print this prompt: "> " (a greater than sign followed by a space). To accomplish this, think about what System.out.print does differently than System.out.println.

Below are the interactions your game must support. Note that the examples are collapsed for ease of reading purposes, but they represent exactly how we want your console interaction to work, so pay close attention to them.

Quitting

If the input is either quit or exit, then the game should wrap-up and the program should exit.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> quit

Moving Around

If the input matches the pattern go <direction_name>, then the current room that the user is in should change to the room in that direction.

Whenever a room is visited, it should print the room's information, including its name, description, possible directions, and items.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> go East
You are in the west entry of Siebel Center. You can see the elevator, the ACM office, and hallways to the north and east.
From here, you can go: West, Northeast, North, or East
Items visible: sweatshirt, key

If the user inputs an invalid direction, then the game should inform them it can't go that way by saying: I can't go "<direction_name>"!

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> go Eastward
I can't go "Eastward"!

Reaching the ending room should result in a special win-room description being displayed (this could be some "win" text; it's up to you), and the program should exit.

Click to see an example
You are in your room, in front of your computer.
From here, you can go: log in to Zoom
Items visible: keyboard, mouse
> go log in to Zoom
You've made it on time to code review; you win!

Examining a Room

If the input is examine, the game should repeat the information about the room, including its name, description, possible directions, and items.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> examine
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin

Items

If the input matches the pattern take <item_name>, the room should attempt to give that item to the user.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> take coin
> examine
You are on Matthews, outside the Siebel Center
From here, you can go: East

If no such item exists in the room, then the game should respond with There is no item "<item_name>" in the room.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> take icard
There is no item "icard" in the room.

If the input matches the pattern drop <item_name>, the user should remove an item from their inventory and place it in the room.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> drop icard
> examine
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin, icard

If the user doesn't have the item, the game should respond with You don't have "<item_name>!".

If the room already has that item, the game should add another copy of the item.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> drop proof that P=NP
You don't have "proof that P=NP"!
> drop coin
> examine
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin, coin

Duplicate items are treated as equals in our specification. If you extend your game to give items with the same name unique properties (like two iron pickaxes with different durabilities), you should define an order for which gets picked up first, or provide a follow-up prompt to the user to choose which they specifically want.


User-Friendly Commands

Your goal should be to design a consistent yet user-friendly experience for your players. As such, you should be able to handle casing errors and extra whitespace.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: East
Items visible: coin
> go       East
You are in the west entry of Siebel Center. You can see the elevator, the ACM office, and hallways to the north and east.
From here, you can go: West, Northeast, North, or East
Items visible: sweatshirt, key
> TAKE SWEaTSHIRt
> examine
You are in the west entry of Siebel Center. You can see the elevator, the ACM office, and hallways to the north and east.
From here, you can go: West, Northeast, North, or East
Items visible: key

Note you don't need to worry about whitespace handling for stored values like direction names, item names, etc, as shown below.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: up and out, East
Items visible: coin
> go   up    and   out
I can't go "up    and   out"!

Unknown Commands

If the user types anything that doesn't match the above specification, then you should inform the user that they typed an invalid command.

Click to see an example
You are on Matthews, outside the Siebel Center
From here, you can go: up and out, East
Items visible: coin
> fly airplane
I don't understand "fly airplane"!

[Optional For This Week] Custom Feature

Next week, you will be extending this assignment further. One of the tasks you will be working on is a custom feature for your game. Note, this is not due this week, but if you finish early on the above specifications, you can get a head start on next week. You have a lot of freedom on what this custom feature can be; however, the feature cannot be trivial to implement. It cannot be a slight variation of a required command nor can it rely on the code used in those commands for the most part.

Here are a few examples of valid custom features to inspire you:

Testing

Testing might seem a little bit nebulous for a large user-facing project like this. Certain designs will be more testable than others, so try to think about how you can design your classes & methods to be easily testable. You should be able to isolate smaller units of your total operation into unit tests.

Deliverables and Grading

For the project to be considered complete, your submission must:

As always, many points on this assignment are made up of aspects of your physical code and your design. Keep using correct style conventions according to the Google Java Style Guide, and think about how you can make a large application like this modular.

We're also paying a lot of attention to Object Decomposition on this assignment, as you will be working with a variety of objects. Make sure you are placing methods in the classes where they make the most sense, and also make sure data flows through your objects in a clean, extensible manner.

Assignment Rubric [updated]

Click here to view

Note! New items in bold

Readability and flexibility of code

  • Modularity: each method should perform one distinct task
  • It should be easy to read through each method, follow its control flow, and verify its correctness
  • The code should be flexible/ready for change (no magic numbers, no violations of DRY)

Object decomposition

  • Choice of classes to create

    • Classes should be coherent units and have clear purposes
    • Classes should not be too “big” or be responsible for too much functionality
      • If a “big” class contains things which aren’t closely related, it may be appropriate to break off part of it into a new class. (This is similar to decomposing long functions into modular units.)
    • If a group of global/static functions are all operating on the same data/object, they should probably be bundled together into a class
    • As an example, the information stored in parallel arrays is often closely related, so it’s usually good design to group the information into a class and combine the parallel arrays into a single array
  • Placement of methods

    • Functionality should be placed in the class that it's most related to
  • Member variables stored by each class

    • Classes should store their data using the most intuitive data structure
    • No "missing" member variables
    • No member variables which should be local variables
    • No redundancy / storing multiple copies of the same data in different formats
  • Encapsulation

    • Appropriate access modifiers
    • Member variables should generally only modified by member functions in the same class
    • The interface of a class should be intuitive/abstract, and external code should only interact with the class via the interface
      • By intuitive, we mean that it should be easy to understand and use the class, and there shouldn’t be any hidden assumptions about how the class should be used
      • By abstract, we mean that an external client shouldn’t need to worry about the internal details of the class
    • No unnecessary getters/setters
    • In Java, getters should not return a mutable member variable

Documentation

  • Specifications
    • Specifications are required for all functions which are part of the public interface of a class
    • Specifications should precisely describe the inputs and outputs of a function, and should also describe what the function does (e.g. mutating state of object)
    • Specifications should also be formatted properly (e.g. follow Javadoc style for Java assignments)
  • Inline comments should not describe things which are obvious from the code, and should describe things which need clarification

Naming

  • Semantics: names should effectively describe the entities they represent; they should be unambiguous and leave no potential for misinterpretation. However, they should not be too verbose.
  • Style: names should follow the Google Java/C++ Style Guide

Layout

  • Spacing should be readable and consistent; your code should look professional
    • Vertical whitespace should be meaningful
      • Vertical whitespace can help create paragraphs
      • Having 2+ empty lines in a row, or empty lines at the beginning or end of files, is usually a waste of space and looks inconsistent
    • Horizontal whitespace should be present where required by the Google Style Guide
  • Lines should all be under 100 characters; no horizontal scrolling should be necessary

Testing

  • You should make sure all types of inputs and outputs are tested.
    • If category A of inputs is likely to cause different behavior than category B, then you should test inputs from both categories
  • Boundary/edge cases often cause different/unexpected behavior, and thus, they should be tested
  • Your tests should ensure that the application state is correctly updated. For example, if a function mutates an object, you can’t just check that the return value is correct. You must also ensure that the object reflects those changes.
  • Your tests should cover all of the functionality that you’ve implemented. In other words, every line of code should be exercised by some test case, unless the assignment documentation says otherwise
  • Each individual test case should only serve one coherent purpose. Individual test cases should not have assertions testing unrelated things
  • Your tests, like your code, should be organized and easy to understand. This includes:
    • Easy to verify thoroughness / all possibilities covered
    • Easy to verify the correctness of each test case
    • Clear categories of test cases, where similar tests are grouped together
      • In Java, this can be accomplished by inserting comments to separate groups
    • Test case names make the purpose of each test case clear
      • Here is one possible way to name test methods in JUnit
    • Different test files for different source files

Process

  • Commit modularity
    • Code should be checked-in periodically/progressively in logical chunks
    • Unrelated changes should not be bundled in the same commit
  • Commit messages
    • Should concisely and accurately describe the changes made
    • Should have a consistent style and look professional
      • First word of the message should be a verb, and it should be capitalized

Presentation

  • Arrived on time with all necessary materials and ready to go
  • Good selection of topics to focus on
  • Logical order of presentation
  • Appropriate pacing and engagement of the fellow students
  • Speaking loud enough and enunciating clearly

Participation

  • Each student should contribute at least one meaningful comment or question for every other student who presents in his/her code review
  • Students must behave respectfully to moderator and other students

Weightings

Your grades for each section of the rubric will be weighted as follows:

  • Readability and flexibility of code (15%)
  • Object decomposition (20%)
  • Documentation (10%)
  • Naming (10%)
  • Layout (5%)
  • Testing (20%)
  • Process (10%)
  • Presentation (5%)
  • Participation (5%)