C++ Hướng đối tượng, Con trỏ, delay

Threads: C++

 Hướng dẫn học C++ từ Cơ bản đến nâng cao 

Goal

Finish implementation of the MazeEscape class such that the code already implemented in main() executes properly. Main() will test your class's doEscape() method to recursively find a path out of the Maze for an "Avatar" character that starts from the upper left corner (row, col == 1,1). Your doEscape() method will search all possible paths in the Maze for your Avatar's location, until it finds an "Escape Room". At no time will your Avatar character be allowed to travel through a wall (or leave the boundaries of the maze).

Background

You will be given a fully implemented Room class, which represents a single room in your maze.

You must develop a MazeEscape class which will have a private data member maze which will be a 2D array of Room pointers.
Your maze will always be of dimension rowCount rows by colCount columns. To help you manage your code, your MazeEscape class will also have 2 private data members of type integer called rowCount and colCount . You should use these member variables any time you iterate through your 2D array maze .

Your MazeEscape constructor will initialize each of the maze's Room pointers to point to a new, dynamically created instance of a Room class (the Room class has been written for you).

  • Each position of the maze 2D array will need to be assigned a pointer to a Room instance.
  • Each Room instance will be configured by you, via its constructor (already written for you), to decide if that room is blocked (is a wall), or not, and also whether that room is an exit (or not). Only one room in your entire maze will be marked as the "exit". This exit room is how you will escape from the maze.
  • You will configure each room by consulting a position in a single configuration string that will be passed to your MazeEscape constructor. Each character of the configuration string will be either a hash '#' (blocked by a wall), a dash '-' (not blocked), or an 'x' (exit). You will use each letter in the configuration string to determine how you will call the Room constructor for each corresponding room.
  • The configuration string that is passed to your MazeEscape constructor will hold one character per position of the 2D array. So a 2x2 Maze will require a 4 character string; a 5x5 maze will require a 25 character string, etc. For example "######---##---##--x######" would represent 5 rows of 5 characters, which comprise a simple maze with the exit in the in position maze[ 3 ] [ 3 ] 2D array (remember that our 2D array starts counting its row and columns at zero, and the wall takes up positions maze[4][4])
#####
#---#
#---#
#--x#
#####
  • and a 11 x 11 maze:
###########
#     #   #
# # ##### #
# #     # #
# # # # # #
# # # #   #
### ### # #
# # # # # #
# # # ### #
#     #  x#
###########
  • You can build your own maze configuration strings here (for fun): https://www.dcode.fr/maze-generator
  • You will use each successive character from the configuration string to configure each new room's constructor.
  • You can assume that each configuration string passed to your MazeEscape constructor will have the correct number of characters (you do not need to worry about the string being too long or too short for your maze array).
  • Once you have constructed and assigned a Room instance to each pointer of your 2D array a based on the configuration string , you will print your maze, using the printMaze() method which you will write.
  • Your printMaze(int avatarRow, int avatarCol ) Method will print the entire 2D Array by calling each Room's printRoom() method (already written for you) from each pointer in the Maze's 2D Array. You do not need to worry about how each room is printed, since the printRoom() method will handle that for you. But you must call the printRoom() method for each room pointed to by each position of the 2D maze array. The only time you will not call the printRoom() method is if the row, col location you are currently printing is the same as the avatarRow, avatarCol location passed to your printMaze() method as its 1st and 2nd argument. These integer values represent the current location of the avatar; that is, the current location that your doEscape() method is considering (or location 1,1, when you call printMethod from your MazeEscape constructor).
  • Once you have printed the Maze you will call your doEscape() method which will recursively search the maze from the upper left corner of the 2D array at position (row==1, col==1), until your doEscape() method encounters a Room that represents the exit.

Already Complete

You do not need to write these items - they have been completed for you:

  1. main() is already complete and is ready to create an instance of your class multiple times with increasingly complex max configurations, to see if you can escape each maze.
  2. Room class is already complete and is ready to be used by your MazeEscape class

The Room Class

The Room class has been fully written for you. The Room class represents one of each of the rooms in the Maze.

The Room class has the following public data members:

  • bool isBlocked : a boolean value that indicates if the Room instance is blocked (meaning it is a wall). Rooms that are blocked will be printed with a hash #. Your doEscape() method cannot "travel through" blocked rooms.
  • bool wasVisited : a boolean value that indicates if the Room instance was visited by you during your recursive doEscape() method.You must mark each room you visit during your doEscape() recursive calls to avoid "becoming lost in the maze" (that is, to avoid an infinite "oblivion" recursion situation).
  • bool isExit : a boolean value that indicates if the Room instance represents an exit. Your recursive doEscape() method will search for any Room with this member set to true in order to "escape the maze".

The Room class has the following constructor and public methods (already written for you)

  • Room( bool isBlocked, bool isExit) : The constructor accepts two booleans which indicate if the room is blocked (true or false), or if the room is an exit (true or false). Note, a room that is blocked cannot be an exit, so you will never call the Room constructor with true and true. Here are the different ways you can create a room dynamically
  1. Room * roomPtr1 = new Room( true, false ); // a blocked room (a wall)
  2. Room * roomPtr2 = new Room( false, true); // an exit
  3. Room * roomPtr3 = new Room( false, false); // an open room you can visit
  • void printRoom() : a method that prints a character to represent either a blocked room '#' (hash), an unblocked, unvisted room ' ' (blank), or an unblocked room which you have already visited '+' (plus), or an exit 'x'.

Note: you can use "new" to create a new Room and to assign that pointer to a position in the maze 2D array in the MazeEscape class described below.

The MazeEscape class

The MazeEscape class has been started for you, but you must finish it.

The class has the following private data members:

  • maze[ rowCount ] [ colCount ]: a 2D array of POINTERS to Rooms (NOT a 2D array of instances of Rooms), that will be used to hold the address of each respective Room instance you create in the MazeEscape constructor (very much like Peg Jump)
  • static const int rowCount : the number of rows in maze
  • static const in colCount : the number of columns in the maze.

Overview of Your Task List

  1. You must write the constructor for the MazeEscape class. Your constructor must create one Room instance for each pointer in the 2D maze array.
  2. You must write the destructor for the MazeEscape class. Your destructor must delete the Room instances you created in the constructor
  3. You must write the printMaze() method for MazeEscape class. The printMaze() method is called once by your constructor using row & column arguments (1,1) to represent the current position of the avatar. You must call printMaze() after your constructor creates all the necessary Room instances and before your constructor calls the doEscape() method. Note that printMaze() It is also called by your doEscape() method at the beginning of each call to doEscape() method, using the current row and column arguments passed to the doEscape() method.
  4. You must write the recursive doEscape() method for MazeEscape class. doEscape() is called once by your constructor using the row and column values of (1,1) to represent the starting position of the avatar. You will call doEscape() after your constructor creates all the necessary Room instances and stores their pointers in the 2D maze array, and after your constructor prints the initial configuration of the maze.

MazeEscape constructor Details

  1. Accepts one string argument that represents the "key" character for each Room in the maze.
  2. Must create a new dynamic instance of a Room for each position of the maze, by passing it the appropriate boolean arguments for its construction.
    • A hash '#' in the current string location means a blocked Room (a wall)
    • A x 'x' in the current string location means an exit from the maze (you "escape the maze" if you reach this room)
    • A dash '-' in the current string location means an empty room (one that you can move into)
  3. Must call the printMethod() method and pass it (1,1) as its 1st and 2nd arguments, to represent the starting location of the Avatar.
  4. Must call the doEscape() method and pass it (1, 1 ) as the 1st and 2nd arguments, to represent the starting location of the Avatar.

MazeEscape :: printMaze() method Details

  1. To print the maze, you must loop through the 2D maze and call the printRoom() method for each pointer in the maze.
  2. Unless the current avatarRow and avatarCol arguments that were passed to the printMaze() method, in which case you will simply print a captical 'A' to represent the Avatar's location
  3. You must pause briefly at the end of you printMaze() method before continuing, using the following line of code:
  • this_thread :: sleep_for( chrono::milliseconds(500)); // Do not remove: this pauses briefly so you can see your next move
  • Note that you can increase 500 (which represents 1/2 a second) to 1000 (1 second) or more, to slow down your simulation while debugging.

MazeEscape :: doEscape() method Details

  1. Return false immediately if the row argument passed to doEscape is not in a legal range
  2. Return false immediately if the col argument passed to doEscape is not in a legal range
  3. Return false immediately if the room identified by [row][col] was already visited
  4. Otherwise, Mark that the room identified by [row][col] as visited
  5. If the current row, col location is blocked, return false (the current position is blocked by a wall)
  6. Print the entire maze by calling the printMaze() method you wrote above, passing it the current row, col position of the Avatar
  7. If the current row, col location is an exit, return true (you escaped!)
  8. Otherwise, mark that the current row,col Room as visited
  9. Try to recurse left by calling doEscape with the avatar location moved one column to the left of its current column; return true if doEscape returns true;
  10. Try to recurse right by calling doEscape with the avatar location moved one column to the right of its current column; return true if doEscape returns true;
  11. Try to recurse up by calling doEscape with the avatar location moved one row "above" its current row; return true if doEscape returns true;
  12. Try to recurse down by calling doEscape with the avatar location moved one row "below" its current row; return true if doEscape returns true;
  13. Return false, because you are blocked by all horizontal and vertical directions

~MazeEscape Destructor Details

  1. You must delete the dynamically allocated Room instances that were created by your constructor.

Special Requirements && Restrictions

  • Each Room must match the configuration indicated by the configuration string passed to your MazeEscape constructor.
  • In your MazeEscape constructor, you must use a nested for loop (an inner loop and an outer loop) to initialze the maze 2D array.
  • In your MazeEscape doEscape() method, you must employ recursion to find a room that is marked as an exit.
  • You may not use the "exit" command in your doEscape method().

Scoring - 100 points possible

PENDING

Bonus - 10 points possible

PENDING

Submission

  • Please submit your repl link on canvas

Sample Ouput

  • First call to the printMaze() method:
###########
#A    #   #
# # ##### #
# #     # #
# # # # # #
# # # #   #
### ### # #
# # # # # #
# # # ### #
#     #  x#
###########
  • Second call to the printMaze() method: (yours may look different)
###########
#+    #   #
#A# ##### #
# #     # #
# # # # # #
# # # #   #
### ### # #
# # # # # #
# # # ### #
#     #  x#
###########
  • Third call to the printMaze() method: (yours may look different)
###########
#+    #   #
#+# ##### #
#A#     # #
# # # # # #
# # # #   #
### ### # #
# # # # # #
# # # ### #
#     #  x#
###########
  • Fourth call to the printMaze() method: (yours may look different)
###########
#+    #   #
#+# ##### #
#+#     # #
#A# # # # #
# # # #   #
### ### # #
# # # # # #
# # # ### #
#     #  x#
###########
  • 2nd to Last call to the printMaze() method: (yours may look different)
###########
#+++  #+++#
#+#+#####+#
#+#+++++#+#
#+#+#+#+#+#
#+#+#+#+++#
###+###+#+#
#+#+#+#+#+#
#+#+#+###A#
#+++++#  x#
###########
  • Last call to the printMaze() method: (yours may look different)
###########
#+++  #+++#
#+#+#####+#
#+#+++++#+#
#+#+#+#+#+#
#+#+#+#+++#
###+###+#+#
#+#+#+#+#+#
#+#+#+###+#
#+++++#  A#
###########
Well done!  You escaped the maze!

Please login or register to see more...

Tags: C++, OOP

Reviews

Please login or register to comment