Developer Manual - felix-elugbaju/Group_B_VirtualEscapeRoom GitHub Wiki

The Developer Manual

Table of Contents

  1. Software Requirements
  2. Software Design
  3. Build Instructions
  4. Preliminary DataTypes
  5. The Object Structure
  6. Game Mechanics
  7. The Command Line Interface
  8. Testing Strategy

Software Requirements

Requirements are classified into three broad categories:

  • Critical: Requirements that are vital for the proper functional behavior of the software and included with release 1 of the software.
  • High: Requirements with a slightly lower priority than Critical. The software will be able to function without these requirements, but these are considered valuable additions.
  • Low: These are general improvements to the software and is considered the lowest priority requirements. The completion of these requirements doesn’t affect the playability of the game as much, and the software is fully functional even without these requirements. These are mostly part of release 2 of the software.

Release 1:
Release 1 will emphasize designing the layout of a single stage with three different challenges. In this release, the game will end when the player successfully solves all three challenges and opens the lock on the door.

  1. The game shall be playable by a single player. [Critical]
  2. The game shall feature cross-platform capabilities. [Critical]
  3. Every stage shall contain a fixed number (3 to 7) of objects. [Critical]
  4. The player shall be able to interact with objects using the command-line interface (CLI). [Critical]
  5. The software shall be able to get, parse, and execute any command from the player in the form of "command arg" (without the quotes). [Critical]
  6. The command "help" shall display a list of common commands. [High]
  • Some example commands may be:
  • “examine objects”
  • "open door"
  • “get item”
  • “use key/code”
  1. The command "ask hint" will provide a hint towards the solution. [High]
  2. Examining an object will give further information that may lead to unique commands. [High]
  3. Common commands, when applicable, shall return suitable results. In contrast, unique commands are situation specific and shall only work once certain conditions are satisfied. [Critical]
  4. The parsing of unsuited commands will be associated with a suitable message indicating that the player is doing something wrong. [Low]
  5. Deciphering all secret messages and solving puzzles and/or riddles in a stage shall give access to a key or a code. [Critical]
  6. Using the correct key or code on the lock shall open the corresponding door. [Critical]

Release 2:
The second release will focus on creating multiple stages in the game and general improvements to the software.
13. Opening the door of one stage will lead to the next stage of the game. [High]
14. The game will have three stages in total. [High]
15. Each stage will be more difficult than the previous one. [High]
16. The total number of hints will be less than the total number of stages to encourage players to use them sparingly. [Low]
17. Some doors might contain multiple locks, and as such, will require the player to acquire the corresponding number of keys and/or codes. [Low]

Changes to Software Requirements 7. The "Ask Hint" Command was removed in lieu of allowing the user to ask for a hint while they are solving the puzzle. The reason for this is provide a hint tailored towards a specific puzzle, which is more useful. 16. Instead of using a fixed number of times a user can ask for a hint, a reward system was implemented at the end of every stage. Using no hints earns the "gold" award, while using all the hints for the puzzle earns the "Lost Explorer" award. The reason for this change was to make completing the entire escape room easier for the user.

Software Design

The design of the entire project is divided into four primary phases, namely Input Handling, Command Execution, Challenge Creation, and Passage Connection. Each of these phases corresponds to a milestone that we intend to reach after the completion of the required subgoals, defined by the processes in the flow chart. Please refer to deliverable 2 for more details.

Build instructions

As specified in the README

In order to compile the program:

Open the command prompt

Navigate to the root directory of the project

Enter "make executable" or "make all" (without the quotes) into the command line

Navigate to the bin directory by entering "cd bin"

The application may now be run by entering "./VER.exe" into the command line

To clean the automatically created object and binary files, enter "make clean" while inside the root directory

Preliminary DataTypes

The type_t datatype

This data type represents what "type" of object exists in the application.
There are 7 types of objects in this application.

  • type location - Corresponds to a stage in which the user is permissible to visit.
  • type visible_object - Corresponds to visible object in which the user may observe via the "look around" command.
  • type hidden_object - These type of objects can only be accessed via examining its parent visible object and then performing additional commands, which are given in the parent object's detailed_description.
  • type usable_object - Corresponds to objects that are usable.
  • type puzzle - This corresponds to an abstraction of a puzzle found in the game that must be in the solved state in order to move from stage to stage. Note this differs from the physical puzzle that the user sees. The physical puzzles are either of type visible_object or type hidden_object.
  • type hint - This is an additional piece of advice that may be accessed in order to help solve a puzzle. Using one or more hints reduces the reward for a player for that stage only.
  • type actor - This is the abstraction of the user. The primary use of this object is to track which location the user is in.

The state_t datatype

This data type represents what is the present "state" of the object of interest in the application.
These states are as follows:

  • open or closed - These states are only valid for doors. Doors are of visible_object datatype and need to be in the open state for the user to successfully go from one location to another. Conversely, the closed state prohibits the user from doing so.

  • confined or unrestricted - These states are only valid for stages, which have data type location. The confined state means that the user is unable to move from that location. If the stage has an unrestricted state, then the user is able to move from that stage at their leisure.

  • solved or unsolved - These states are only valid for puzzles. If the puzzle is incomplete, then it has an unsolved state. Upon the completion of a puzzle by the user, the state is to be changed to solved.

  • hidden or revealed - These states are only valid for keys. Keys can only be in the revealed state after completion of all the puzzles for their corresponding stage. If the puzzles are not completely solved in the stage, then the key will remain in the hidden state. Keys in the hidden state may not be obtained by the user via the get command.

  • used or unused - These states are only valid for hints for puzzles. If the user asks for a hint when they are solving a puzzle, the puzzle's corresponding hint will change from state unused (default) to used. Upon completing each stage, the number of hints in the used state shall impact the stage prize the user receives.

  • regular - This state is a generic state that has no particular significance or meaning.

The Object Structure

An 'object' datatype is comprised of 6 fields. In order, they are:

  • const char *description - If this is a visible object type, then this is the description returned via the look around command. For usable objects, this description is shown once they are in the user's bag.
  • const char *tag - This string is used as an abbreviation of the description field to refer to a specific object. In order to interact with an object, the user must enter a command in the terminal, and use the object's tag as an argument. Example usage: use <silver_key> where the user is to use an object that has the tag of silver_key.
  • type_t type - This field specifies the object's type.
  • state_t state - This field specifies the object's state.
  • const char *detailed_description - This string is returned when the user examines it. This string is to provide detail about the object, which may be a clue to solving a puzzle. If the object is of type hint, then this field must be used as a hint for a particular puzzle.
  • struct object location - This field is used to determine which location the object is located in. The object must exist in one, and only one location.

Game Mechanics

For a broad overview of the mechanics of this game, please see the User Manual

The main() function

The main function will run a continuous loop that will run as long as one of the locations has a state of confined, and as long as the user does not enter the quit command. If the program is unable to access the user input, then the application will quit and exit graciously.

Completing stages, the get_reward function and completing the game.

In order to proceed from one stage to the next, the user must solve puzzles as defined in the User Manual.
The user may solve these puzzles with, or without using a hint. However, to incentivize not using hints,
at the end of each stage, the user will receive a reward. At the end of every puzzle, the application
checks to see if all the puzzles in the particular stage the user is on are solved.
If so, the application will set the state of the key to that particular stage from hidden to
revealed. In addition, it shall invoke the get_reward(int stage) function, that counts all the hints
corresponding to the stage the user is on that are in the used state. If the amount of hints used is
0, then the user receives the gold award. The more hints that are used, the less prestigious award the user receives
for that level.

The Command Line Interface

Parsing User Input

After launching the application, the user is taken to a main menu where they have a choice of executing 10 commands. This input is received from the get_input(void) function.
The input that the user provides is then sent to parse_and_execute(char * input) function.
parse_and_execute(char * input) First, the input is separated into tokens using whitespace as a delimiter. A typical input is two tokens. The first token is known as the command, and the second token is known as the arg. If the parser receives the quit command, the application will exit gracefully, and then quit.

Obtaining an object based on arg

For many commands, it is necessary that the arg is to be a tag of one of the objects defined in the application. In order to get an object with the matching tag, the arg is then passed to the OBJECT_t *get_object(const char *arg) function. This function invokes the bool has_tag(OBJECT_t*obj, const char *arg) which will test an OBJECT *obj to see if its tag is equal to arg. If so, then this function returns true, and get_object returns the object that was passed to the has_tag function.

These other 10 commands are managed in the execution.c file.

Commands

  • look - Description: Invokes execute_look(const char *arg), which does the following based on the value of arg. If arg is equal to around then the screen will display all visible object types in the user's given location. If arg is equal to closely, and if the user is in stage 2, a hidden object will have its detailed description displayed relating to the fourth puzzle. Return Values: Null

  • examine - Description: Invokes execute_examine(const char *arg) which prints the detailed_description of an object with that has its tag equal to arg. Return Values: Null

  • go - Description: Invokes execute_go(const char *arg) which will change the location of the actor to that of arg if the following conditions are met: 1) There exists an object with its tag equal to arg. 2) The type of that object is of type location. 3) The new location is different than the location of the actor. 4) The state of the current location is unrestricted. Return Values: Null

  • get - Description: Invokes execute_get(const char *arg) which will "move" an object that has a tag equal to arg into the user's bag. In order for an object to be "moved", it must be a usable_object type. An object is "moved" via setting its location to that of the actor. The default value of the location of all objects with the type usable_object is otherwise NULL. Return Values: Null

  • use - Description: Invokes execute_use(const char *arg) which will check that an object which has a tag equal to arg, is of type usable_object, and that the object is in the user's bag (See get function above). Return Values: Null

  • open - Description: Invokes execute_open(const char *arg) which will check that an object which has a tag equal to arg, has a location equal to that of the actor, as well as a state of being open. If so, then the current location that the actor is in will change its state from confined (its default) to unrestricted. Return Values: Null

  • bag - Description: Invokes execute_check(void) which invokes a helper function list_objects_at_location(player, usable_object) which determines the objects that are of type usable_object that have the same location of that as the player, which is an object of type actor. In order to change the location of the object, see the get command. Return Values: Null

  • help - Description: Invokes execute_help(void) which prints out a table of the common commands a user may enter. Return Values: Null

  • map - Description: Invokes execute_map(void) which prints out a crude map showing the tags of all the locations the user may be able to go to.

Testing strategy

The strategy we used for this testing is the black box testing which is a functional unit testing method. We were testing different functions especially the non-void functions that return a value and require one or more arguments. We didn't test the void functions since most of them require user input.

Our unit testing made use of the Unity testing framework which is written in C and is a good testing framework for projects written in C. We made use of one of the unity's numerical assertions for integers function which is this function

TEST_ASSERT_EQUAL_INT(expected, actual)

expected: The result you expect.

actual: The function or the variable to be tested.

The function compares the actual and expected results and checks if they are equal to determine if the test passed or failed. We tested each function with the right input to see if it passed and then the wrong input to see if it failed. Expected values were modified in each case to see if what we expected matched the actual results.

  • For example This tests if there is a tag called clock for the clock object
  void test_object_has_tag_function_correct_tag(void)
  {
     TEST_ASSERT_EQUAL_INT(1, object_has_tag(clock, "clock"));
  }

The expected returned value is 1 and the actual value returned is the function object_has_tag(clock, "clock") which should return 1 since there is a tag called clock for the clock object. This test should pass when the expected and actual results are compared This test passed and the result is

test/test.c:108:test_object_has_tag_function_correct_tag:PASS

This test if there is a tag called wine in the clock object

void test_object_has_tag_function_wrong_tag(void)
{
   TEST_ASSERT_EQUAL_INT(0, object_has_tag(clock, "wine"));
}

The expected result is 0 and the actual result is the function object_has_tag(clock, "wine") which should return 0 since there is no tag called clock for the clock object. This test should pass when the expected and actual results are compared This test passed and the result is

test/test.c:110:test_object_has_tag_function_wrong_tag:PASS

All the test cases created pass. We ran a total of 8 tests for the program.
To run the tests, while in the project root directory,

  1. Use "make test" or "make all" to create the "test.exe" binary
  2. Navigate to the bin directory using "cd bin"
  3. Run the "test.exe" file using the "./test.exe" command in the bin folder after creating that executable.

To see the test results, go to the program_output folder and check the "test_result.txt" file containing the results of the different tests that we performed.

⚠️ **GitHub.com Fallback** ⚠️