In this assignment, you will build on code that reads an in-game map (or dungeon) from...
Fantastic news! We've Found the answer you've been seeking!
Question:
Transcribed Image Text:
In this assignment, you will build on code that reads an in-game map (or "dungeon") from a file into a dynamic 2D array. Then, you must update the map as the player moves the character through the dungeon. The player's goal is to pick up the treasure and go to the level's exit. Additionally, you will need to implement magic amulets that resize the dungeon size as well as monsters that chase the player. Objectives Create and store values into a 2D dynamic array using loop iteration, and then delete once it is no longer needed. Resize a 2D dynamic array without memory leaks. Code and call functions with pass by reference. Update variables passed into functions as references and check conditions to determine game state. 1. Download and extract the starter code into your programming environment. Confirm that the starter code consists of the following files: a. dungeoncrawler.cpp: b. logic.cpp: c. logic.h d. helper.cpp: You must not edit this file. You must edit this file for the homework. You must not edit this file, but you must read it. You must not edit this file. e. helper.h: You must not edit this file, but you must read it. 2. Compile and run the initial state of the starter code with the following command line. a. g++ -std=c++17 -Wall - Wextra -pedantic-errors -Weffc++ -fsanitize=undefined, address *.cpp 3. Confirm that the initial state of the starter code executes without errors and with only warnings related to unused variables/parameters. Go ahead and submit the starter code to Mimir so you can take a look at the test cases. 4. Read code documentation of and familiarize with the code in the logic.h file. These will be used in editing the logic.cpp file. a. Player Struct: holds the values of the adventurer's position in the grid, as well as a count of treasure acquired across all levels of dungeon. b. Tile Status Constants: these constants hold values for representing the tile type on the dungeon map. c. Movement Status Flag Constants: these constants hold values for representing the player's movement status flags. d. User Keyboard Input Constants: these constants hold values for representing the user's keyboard inputs. 5. Make sure to familiarize yourself with the input files for the program. a. See Appendix A for information about the map text files. b. Note that we have provided most of the file handling already. Step 1. Write Code for createMap (...) Function 1. Open logic.cpp and locate the createMap function. Make sure to read the block comment describing the function. 2. Dynamically allocate a 2D char array with maxRow rows and maxCol columns. Initialize each array element to TILE_OPEN. 3. Return a pointer to the array. Step 2. Write Code for deleteMap (...) Function 1. Open logic.cpp and locate the deleteMap function. Make sure to read the block comment describing the function. 2. Deallocate the 2D char array pointed at by the pointer map, and make sure not to leak memory! (Hint: what should the parameter maxRow be used for?) Step 3. Write Code for resizeMap(...) Function 1. Open logic.cpp and locate the resizeMap function. Make sure to read the block comment describing the function. * 2. Dynamically allocate a 2D array with (2 maxRow) rows and (2 maxCol) columns using your createMap function. Visually, we can divide this 2D array into four maxRowxmaxCol subarrays: A C * B D 3. Copy the contents of the array map into the subarray A exactly (including the adventurer). Copy the contents of the array map into each of the subarrays B, C, and D, except for the adventurer, which should be replaced by TILE_OPEN. 4. Deallocate the original map using your deleteMap function and update any variables as necessary. 5. Return a pointer to the new array. Step 4. Write Code for doPlayerMove (...) Function 1. Open logic.cpp and locate the doPlayerMove function. Make sure to read the block comment describing the function. You will be returning a status from logic.h that gives the result of the attempted move. 2. The next position is determined by nextRow and nextColumn. a. If the next position places the adventurer outside the bounds of the array or on an unpassable tile (a pillar or a monster), set the status to STATUS_STAY and update nextRow and nextCol to be the adventurer's current position (i.e., the adventurer did not move). Remember to check that nextRow and nextCol are within bounds before using them to check a tile's value (short circuit evaluation might be useful, see zyBook 1.49). b. If the next position is on a treasure tile, set the appropriate status and increment the adventurer's treasure by one. C. If the next position is on an amulet tile, set the appropriate status. d. If the next position is on a door (to the next level), set the appropriate status. e. If the next position is on an exit (to the whole dungeon) and the adventurer has at least one piece of treasure, set the appropriate status. If the adventurer has no treasure treat the door as you would a pillar. 3. Update the map by updating the adventurer's position to the next position, setting the new position to TILE_PLAYER and the adventurer's old position to TILE_OPEN. 4. Return the appropriate status flag. Step 5. Write Code for doMonsterAttack(...) Function 1. Open logic.cpp and locate the doMonsterAttack function. Make sure to read the block comment describing the function. 2. The logic for the monster Al is as follows: a. Starting from the tile above the adventurer's location and working upward, check each individual tile to see if there is a monster on the tile. b. c. If there is a monster on a tile, move the monster one tile closer to the adventurer. Continue to check until you have reached the top of the map or reach a pillar (monsters can't see through pillars) 3. Repeat the same logic with down, left, and right (in that order). Make sure all monsters that are supposed to move do so before you go to the next step (Step 4). 4. The adventurer is killed if a monster moves onto their tile (check if the player position now contains a monster), return true (adventurer killed, game over) if so, otherwise return false (the monsters did not attack the adventurer, yet...). Testing Your Code (AKA Playing the Game) Sample Dungeons Included in the starter code from Mimir is a folder of sample dungeon levels. You will find the 4 tutorial levels, 2 levels for the "easy" dungeon, and 3 levels for the "hard" dungeon. Moving these files into the same directory as your dungeoncrawler.cpp main file will allow you to play the dungeon and test your code. See Appendix B for more information about playing the game. As an example, to play the hard dungeon, you would enter "hard 3" at the beginning prompt. You may want to test with the tutorial or easy dungeon. The hard dungeon is not for the faint of heart! Can you escape it²? Of course, feel free to create your own levels! Review Appendix A for information about the level file structure. Appendix A: Input Map Text File This assignment will involve reading a text file that contains information of the dungeon map's internal representation. This text file consists of three parts: The first number in Line 3 represents the map tile at (0, 0), where the first value is the row position and the second value is the column position. Refer to the tile status constants in logic.h for more details. The following is an example text file for a 5×3 tile representation of a dungeon map. ΠΜΣιιιΘ ● Line 1: Map Dimensions. This line contains two values for representing the map's number of rows and number of columns, respectively. Line 2: Player Starting Location. This line contains two values for representing the player's starting row and column, respectively. Lines 3+: These lines contain the individual tile information of the dungeon map as char values. O 5 3 30 M + + - + tA O ● Line 1; The map has 5 rows and 3 columns. Line 2: The player will start at map location (3, 0), where 3 is the row position and 0 is the column position. Remember that indexing starts from 0, so the top left corner will be map location (0, 0). Lines 3-7: The map's internal representation for each map tile. O Note #1: Whitespace for lines 3 and after are purely for aesthetic purposes, so you must not assume that line breaks represent the actual map dimensions or that there will be spaces in between the char values. O O O Note #2: In previous assignments you used column-major order when working with 2D arrays and PPM files, which is the norm in the graphics community. In this assignment you will be using row-major ordering when working with your 2D arrays, as this is how a C++ program will typically order a multidimensional array. Note #3: Each level of a dungeon has its own map stored in a different file, each named according to the dungeon name followed by the level number. For example, if the dungeon is named "tutorial" and has four levels, the files will be "tutorial1.txt”, “tutorial2.txt”, “tutorial3.txt”, and “tutorial4.txt". Note #4: Only the final level will have an exit (an ! symbol); all the other levels have doors (a ? symbol) to the next level. Appendix B: Gameplay Loading a Game Each game starts with a printout of the instructions, followed by a prompt for the dungeon name and the number of levels in the dungeon. Here our dungeon is called tutorial and it has 4 levels (user input in dark red): Good day, adventurer! Your goal is to get the treasure and escape the dungeon! SYMBOLS --- --- O +₂ ? ! : That is you, the adventurer! : These are treasures. Lots of money! : These magical amulets resize the level. : These are monsters; avoid them! --- : These are unpassable obstacles. : A door to another level. : A door to escape the dungeon. CONTROLS w, a, s, d: Keys for moving up, left, down, and right. e : Key for staying still for a turn. q : Key for abandoning your quest. Please enter the dungeon name and number of rooms: tutorial 4 Navigating the Dungeon Our dungeon crawler uses the WASD³ method of controlling the in-game adventurer: w and s move the adventurer up one row and down one row respectively, while a and d move the adventurer left one column and right one column respectively. Entering e will cause the adventurer to stay still for a turn. Tiles with unpassable obstacles (a pillar) cannot be moved onto, and are represented by the + symbol. The door to the next level is represented by the ? symbol, while the door out of the dungeon (and thus the game) is represented by the ! symbol. Level 1 + O + ? + Enter command (w,a,s,d: move, e: stay still, q: quit): s + + O + ? | +--- -+ You have moved to row 1 and column Enter command (w,a,s,d: move, e: stay still, q: quit): s + + + o ? + You have moved to row 2 and column 0 Enter command (w,a,s,d: move, e: stay still, q: quit): de + O -+ You have moved to row 2 and column 1 You go through the doorway into the unknown beyond... Treasure Dungeons are dangerous places, so why would you put up with all that risk for no reward? Tiles with treasure on them are represented by the $ symbol. Pick up a piece of treasure by moving the adventurer to that tile. Upon exiting, the game will tell you how much treasure was picked up by the adventurer across all levels. But make sure you don't leave empty-handed, since the door out of the dungeon (represented by the ! symbol) won't open if you don't have at least one piece of treasure! Level 2 O $ ? Enter command (w,a,s,d: move, e: stay still, q: quit): de O ? You have moved to row 1 and column 2 Well done, adventurer! You found some treasure. You now have 1 treasure. Enter command (w,a,s,d: move, e: stay still, q: quit): de ? | O | +- -+ You have moved to row 1 and column 3 Enter command (w,a,s,d: move, e: stay still, q: quit): W + ? | | O + You have moved to row 0 and column 3 Enter command (w,a,s,d: move, e: stay still, q: quit): du +- o | +- -+ You have moved to row 0 and column 4 You go through the doorway into the unknown beyond... Monsters So what makes dungeons so dangerous anyway? The monsters kept in them to guard the treasure of course! Monsters are represented by the symbol M, and will chase any adventurer in their line of sight (i.e., if the adventurer is a rook's move from them). Thankfully, they are slow and move only one tile per turn, and cannot see over unpassable obstacles, allowing the adventurer to hide behind them. The adventurer is quick enough that he can get through a door before a monster attacks on the next turn, but won't be able to pick up an item and then withstand an attack. Monster attacks are lethal, and being killed by the monster will cause you to lose the game. The adventurer is not strong enough to attack a monster, so the only strategy is to run away. Monsters are powerful, and will destroy any (passable) obstacle in their path - including treasure, amulets, and even doors! Make sure that the monsters don't destroy the only way out... Magic Amulets The dungeon also holds many ancient and mysterious artifacts, such as magic amulets. Magic amulets are represented by the @symbol. Picking up an amulet will cause the level to double in size, with three additional copies of the level (without additional adventurers, but with additional monsters and items) appearing below, to the right, and diagonally below and right of the level. Unfortunately, the amulet is destroyed in the process and isn't copied as well. Level 4 +-- | o | + + | @ + Enter command (w,a,s,d: move, e: stay still, q: quit): s + O | @ + +- -+ You have moved to row 1 and column 0 + + | O Enter command (w,a,s,d: move, e: stay still, q: quit): su +- --+ + + + + + + ! + | + | ! + + | + ! | You have moved to row 2 and column 0 The magic amulet sparkles and crumbles into dust. The ground begins to rumble. Are the walls moving? Enter command (w,a,s,d: move, e: stay still, q: quit): S + + + + + ! + + O + + + + You have moved to row 3 and column 0 Enter command (w,a,s,d: move, e: stay still, q: quit): d + + ! + + | + ! | + ! + + + + + + + You have moved to row 3 and column 1 Enter command (w,a,s,d: move, e: stay still, q: quit): w + + + + + + + O + ! + + ! + + + ! | + + You have moved to row 2 and column 2 Congratulations, adventurer! You have escaped the dungeon! You escaped with 1 treasure and in 16 total moves. Quitting the Game You can quit the game at any time by entering the symbol q. Just be careful, as there is no way to save your progress. HN34567 1 2 8 9 logic.cpp #ifndef HELPER_H #define HELPER_H #include "logic.h" X dungeoncrawler.cpp x // constant value for tile width in console output const int DISPLAY_WIDTH = 3; // function signatures, do not change void printInstructions(); #endif helper.cpp X 10 11 12 void outputMap (char** board, const int maxRow, const int maxCol); 13 14 void outputStatus(const int status, const Player& player, int moves); 15 16 17 logic.h X helper.h X MUNKA brea ** 1 #ifndef LOGIC_H 2 #define LOGIC_H 3 4 9 10 #define INFO (X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE__<<") 5 #include <iostream> 6 #include <fstream> 7 #include <string> 8 using std::cin, std::cout, std::endl, std::string, std::ifstream; 11 12 13 14 15 16 17 1/ 18 18 19 20 20 24 21 22 22 22 23 21 24 25 26 26 27 28 29 30 31 32 32 22 33 24 34 35 36 37 38 39 40 41 42 43 44 45 46 47 47 48 49 logic.cpp 50 51 52 53 54 55 56 57 58 59 co // Player object container struct Player { int row = 0; int col = 0; int treasure = 0; X }; // constants for tile status const char TILE_OPEN const char TILE_PLAYER const char TILE_TREASURE const char TILE_AMULET const char TILE_MONSTER const char TILE_PILLAR const char TILE_DOOR const char TILE_EXIT = ''; = '0'; = '$'; = '@'; = 'M'; = '+'; = '?'; const int STATUS_MOVE = 1; const int STATUS_TREASURE = 2; const int STATUS_AMULET = 3; const int STATUS_LEAVE = 4; const int STATUS_ESCAPE = 5; dungeoncrawler.cpp x // constants for user's keyboard const char INPUT_QUIT const char INPUT_STAY const char MOVE_UP const char MOVE_LEFT const char MOVE_DOWN const char MOVE_RIGHT // constants for movement status flags const int STATUS_STAY = 'q'; = 'e'; = 'w'; = 'a'; = 's'; = 'd'; // blank tile // tile for player's current location // tile for unpassable pillar location // tile for hazard that enlarges the dungeon // tile for monster current location helper.cpp // tile for unpassable pillar location // tile for door to the next room // tile for exit door out of dungeon "<<_LINE_<<") " << #X << " = " << X << endl; // flag indicating player has stayed still // flag indicating player has moved in a direction // flag indicating player has stepped onto the treasure // flag indicating player has stepped onto an amulet inputs X // flag indicating player has left the current room // flag indicating player has gone through the dungeon exit // quit command // no movement // up movement // left movement // down movement // right movement // function signatures, do not change char** loadLevel(const string fileName, int& maxRow, int& maxCol, Player& player); void getDirection (char input, int& nextRow, int& nextCol); char** createMap (int maxRow, int maxCol); void deleteMap (char** board, int maxRow); char** resizeMap (char* map, int& maxRow, int& maxCol); int doPlayerMove (char** map, int maxRow, int maxCol, Player& player, int& nextRow, int& nextCol); bool doMonsterAttack (char** map, int maxRow, int maxCol, Player& player); #endif logic.h 1 2 3 4 5 6 7 8 9 10 11 ខជន២១–២១៩ឥ៩៧៩ដង ដកពីភពអត២តឥន្ធ ទី១ ២ ខ ទ ជ ផ ព ភ មា ន ភ ន ន ៩ ៨ ៨២៩២៩ 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 } // do not change 29 void outputMap (char** map, const int maxRow, const int maxCol) { 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 logic.cpp #include <iostream> #include "helper.h" using std::cout, std::endl; 66 67 // do not change void printInstructions() { cout << endl; cout << } cout << 0 cout << " $ cout << @ cout << "M cout << +, cout << " ? cout << ! cout << cout << " W, cout << e cout << " cout << " cout << endl; cout << "Good day, adventurer!" cout << "Your goal is to get the treasure and escape the dungeon!" SYMBOLS " cout << q | } cout << "+"; cout << endl; | -, | } X // output top border cout << "+"; for (int i = 0; i < maxCol * DISPLAY_WIDTH; ++i) { cout << "-"; : These are monsters; avoid them!" : These are unpassable obstacles." : A door to another level." : A door to escape the dungeon." CONTROLS --_" a, s, d: Keys for moving up, left, down, and right." Key for staying still for a turn." dungeoncrawler.cpp x : That is you, the adventurer!" : These are treasures. Lots of money!" : These magical amulets resize the level." for (int i = 0; i < maxRow; ++i) { // output left border cout << "|"; } else { : : Key for abandoning your quest." } cout << " "; // output inner blocks for (int j = 0; j < maxCol; ++j) { // output current block cout << " "; if (map[i][j] == TILE_OPEN) { cout << " "; cout << "+"; cout << endl; cout <<map[i][j]; } // output right border cout << "|"; cout << endl; } // output bottom border cout << "+"; for (int i = 0; i < maxCol * DISPLAY_WIDTH; ++i) { cout << "-"; helper.cpp << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; COORNARNEFNTT88 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 89 90 91 92 93 94 95 96 97 98 99 // do not change void outputStatus(const int status, const Player& player, int moves) { if (status != STATUS_STAY) { cout << "You have moved to row " << player.row << " and column " << player.col << endl; } | } switch (status) { case STATUS_STAY : cout << "You stayed at row" << player.row << "and column " << player.col << endl; cout << "You didn't move. Are you lost?" << endl; break; case STATUS_MOVE : case STATUS_TREASURE : cout << "Well done, adventurer! You found some treasure." << endl; cout << "You now have " << player.treasure <<< (player.treasure > 1 ? " treasures." : " treasure.") << endl; break; break; case STATUS_AMULET : cout << "The magic amulet sparkles and crumbles into dust." << endl; cout << "The ground begins to rumble. Are the walls moving?" << endl; break; case STATUS_LEAVE : cout << "You go through the doorway into the unknown beyond..." << endl; break; case STATUS_ESCAPE : cout << "Congratulations, adventurer! You have escaped the dungeon!" << endl; cout << "You escaped with " << player.treasure <<< (player.treasure > 1 ? " treasures cout << "and in " << moves << " total moves." << endl; break; } cout << endl; ; " treasure "); logic.cpp 1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include "helper.h" 5 #include "logic.h" 6 using std::cin, std::cout, std::endl, std::string, std::ifstream; 7 8 9 10 11 12 13 14 15 HHAHAAN~~~~~~≈28-235SMERTE 16 17 18 19 20 21 24 26 27 29 30 31 33 34 36 37 39 40 41 int main() { X dungeoncrawler.cpp × // display greeting message printInstructions(); string dungeon; int total_rooms; Player player; cout << "Please enter the dungeon name and number of levels: "; cin >> dungeon >> total_rooms; // declare variables int maxRow = 0; int maxCol = 0; int nextRow = 0; int nextCol = 0; helper.cpp int total_moves = 0; for(int current_room = 1; current_room <= total_rooms; current_room++) { cout << "Level " << current_room << endl; string fileName = dungeon + std::to_string(current_room) + ".txt"; // create map, or quit if map load error char** map = loadLevel(fileName, maxRow, maxCol, player); if (map == nullptr) { cout << "Returning you back to the real word, adventurer!" << endl; return 1; } // display map outputMap (map, maxRow, maxCol); ◄► 41 42 43 44 45 TO 46 TO 47 M 48 49 49 50 50 31 51 52 53 55 54 34 55 39 30 56 57 58 58 „:♫nnib:t❀❀RF~^*^ºFºr:⠀≈⠀⠀456⠀⠀:¯¯ 59 60 61 62 63 04 05 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 199 89 90 91 92 93 logic.cpp // move player char input = 0; int status = 0; while (true) { dungeoncrawler.cpp X } // get user input cout<<"Enter command (w,a,s,d: move, e: stay still, q: quit): "; cin >> input; // quit game if user inputs quit if (input == INPUT_QUIT) { cout << "Thank you for playing!" << endl; deleteMap (map, maxRow); return 0; } // increment dungeon movement counter total_moves++; if (input == INPUT_STAY) { status = STATUS_STAY; } else { helper.cpp // reprompt if invalid command if (input != MOVE_UP && input != MOVE_LEFT && input != MOVE_DOWN && input != MOVE_RIGHT && input != INPUT_STAY) { cout << "I did not understand your command, adventurer!" << endl; continue; } // quit game if user escapes if (status== STATUS_ESCAPE) { X getDirection (input, nextRow, nextCol); // move player to new location index, if possible, and get player status status = doPlayerMove (map, maxRow, maxCol, player, nextRow, nextCol); outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); deleteMap (map, maxRow); return 0; // translate from the character input to a direction // we will use the player's current location and pass-by-reference to find the intended next location nextRow=player.row; nextCol=player.col; } // go to next level if user goes through door if (status == STATUS_LEAVE) { logic.h outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); break; } // move monsters, end if player is caught X helper.h 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 } } // move monsters, end if player is caught if (doMonsterAttack(map, maxRow, maxCol, player)) { } // use amulet if (status == STATUS_AMULET) { } outputMap (map, maxRow, maxCol); cout << "You died, adventurer! Better luck next time!" << endl; deleteMap (map, maxRow); return 0; map = resizeMap (map, maxRow, maxCol); // display map and status outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); } return 0; // delete map deleteMap (map, maxRow); ← 7 8 9 10 11 12 13 14 15 16 17 18 1 2 3 #define INFO (X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE_<<") " << #X << " = " << X << endl; 4 #define INFO_STRUCT(X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE_<<") " << #X << " = {"' << X. row << "," << X.col << "," << X.treasure << "}" << endl; 5 6 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 logic.cpp #include "logic.h" 39 40 41 42 43 44 45 *This function is provided; do not change * Load representation of the dungeon level from file into the 2D map. * Calls createMap to allocate the 2D array. * @param fileName * @param } dungeoncrawler.cpp x File name of dungeon level. * @param Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object by reference to set starting position. * @param * @return 2D dynamic array representation of dungeon map with player's location. */ char** loadLevel(const string fileName, int& maxRow, int& maxCol, Player& player) { INFO(maxRow); INFO (maxCol); ifstream ifs (fileName); if (!ifs.is_open()) { maxRow maxCol player } ifs >> maxRow >> maxCol; ifs >> player.row >> player.col; } cout << "ERROR: Unable to open: " << fileName << endl; return nullptr; char** dungeon = createMap (maxRow, maxCol); if (dungeon == nullptr) { cout << "ERROR: Map did not load." << endl; return nullptr; } for (int i = 0; i < maxRow; i++) { helper.cpp } for (int j = 0; j < maxCol; j++) { ifs >> dungeon [i][j]; if (i == player.row && j = player.col) { dungeon [i][j] = TILE_PLAYER; return dungeon; logic.h X helper.h 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 logic.cpp } /** * This function is provided; do not change * Translate the character direction input by the user into row or column change. * That is, updates the nextRow or nextCol according to the player's movement direction. * @param input * @param nextRow nextCol Character input by the user which translates to a direction. Player's next row on the dungeon map (up/down). Player's next column on dungeon map (left/right). * @param */ void getDirection (char input, int& nextRow, int& nextCol) { switch (input) { } case MOVE_UP: nextRow--; break; } case MOVE_DOWN: nextRow++; break; case MOVE_LEFT: nextCol--; break; } case MOVE_RIGHT: nextCol++; break; * TODO: Student implement this function * Allocate the 2D map array. * Initialize each cell to TILE_OPEN. dungeoncrawler.cpp x * @param maxRow * @param maxCol * @return 2D map array for the dungeon level, holds char type. */ char** createMap (int maxRow, int maxCol) { INFO (maxRow); INFO (maxCol); return nullptr; helper.cpp Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). /** * TODO: Student implement this function * Deallocates the 2D map array. * @param map * @param maxRow */ void deleteMap (char** map, int maxRow) { INFO (map); INFO (maxRow); return; logic.h Dungeon map. Number of rows in the dungeon table (aka height). 90 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 /** * TODO: Student implement this function * Resize the 2D map by doubling both dimensions. * Copy the current map contents to the right, diagonal down, and below. * Do not duplicate the player, and remember to avoid memory leaks! * You can call your createMap and deleteMap functions to help with this one! * @param * @param map maxRow maxCol * @param * @return An updated 2D map that has twice as many columns and rows in size. */ char** resizeMap (char** map, int& maxRow, int& maxCol) { INFO (map); INFO (maxRow); INFO(maxCol); } Dungeon map. Number of rows in the dungeon table (aka height), to be doubled. Number of columns in the dungeon table (aka width), to be doubled. return nullptr; /** * TODO: Student implement this function * Checks if the player can move in the specified direction and performs the move if so. * Cannot move out of bounds or onto TILE_PILLAR or TILE_MONSTER. * Cannot move onto TILE_EXIT without at least one treasure. * If TILE TREASURE, increment treasure by 1. * Remember to update the map tile that the player moves onto and return the appropriate status. * You can use the STATUS constants defined in logic.h to help! * @param map * @param * @param * @param maxRow maxCol player nextRow nextCol * @param * @param * @return Player's movement status after updating player's position. */ } Dungeon map. Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object to by reference to see current location. Player's next row on the dungeon map (up/down). Player's next column on dungeon map (left/right). int doPlayerMove (char** map, int maxRow, int maxCol, Player& player, int& nextRow, int& nextCol) { INFO (map); INFO (maxRow); INFO (maxCol); INFO_STRUCT (player); INFO (nextRow); INFO(nextCol); return -1; // update to use STATUS consts from logic.h! 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 /** * TODO: Student implement this function * Update monster locations: * We check up, down, left, right from the current player position. * If we see an obstacle, there is no line of sight in that direction, and the monster does not move. * If we see a monster before an obstacle, the monster moves one tile toward the player. * We should update the map as the monster moves. * At the end, we check if a monster has moved onto the player's tile. Dungeon map. * @param map * @param maxRow * @param maxCol Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object by reference for current location. * @param player * @return Boolean value indicating player status: true if monster reaches the player, false if not. */ bool doMonsterAttack(char** map, int maxRow, int maxCol, Player& player) { } INFO (map); INFO (maxRow); INFO (maxCol); INFO_STRUCT (player); // check up // check down // check left // check right // check if any monster is on player return false; 1 2 3 4 5 9 7 8 9 easy1.txt 75 51 I I | I I | + + + + | I I ΙΣΤΙ I - I X HEMAFOTOG 1 2 3 4 5 6 7 8 9 10 hard3.txt 88 22 M - M - - M - $ + + $ + ! M + M - M - @ I H~3456 1 2 4 hard3.txt 33 00 @ + + - + tutorial4.txt In this assignment, you will build on code that reads an in-game map (or "dungeon") from a file into a dynamic 2D array. Then, you must update the map as the player moves the character through the dungeon. The player's goal is to pick up the treasure and go to the level's exit. Additionally, you will need to implement magic amulets that resize the dungeon size as well as monsters that chase the player. Objectives Create and store values into a 2D dynamic array using loop iteration, and then delete once it is no longer needed. Resize a 2D dynamic array without memory leaks. Code and call functions with pass by reference. Update variables passed into functions as references and check conditions to determine game state. 1. Download and extract the starter code into your programming environment. Confirm that the starter code consists of the following files: a. dungeoncrawler.cpp: b. logic.cpp: c. logic.h d. helper.cpp: You must not edit this file. You must edit this file for the homework. You must not edit this file, but you must read it. You must not edit this file. e. helper.h: You must not edit this file, but you must read it. 2. Compile and run the initial state of the starter code with the following command line. a. g++ -std=c++17 -Wall - Wextra -pedantic-errors -Weffc++ -fsanitize=undefined, address *.cpp 3. Confirm that the initial state of the starter code executes without errors and with only warnings related to unused variables/parameters. Go ahead and submit the starter code to Mimir so you can take a look at the test cases. 4. Read code documentation of and familiarize with the code in the logic.h file. These will be used in editing the logic.cpp file. a. Player Struct: holds the values of the adventurer's position in the grid, as well as a count of treasure acquired across all levels of dungeon. b. Tile Status Constants: these constants hold values for representing the tile type on the dungeon map. c. Movement Status Flag Constants: these constants hold values for representing the player's movement status flags. d. User Keyboard Input Constants: these constants hold values for representing the user's keyboard inputs. 5. Make sure to familiarize yourself with the input files for the program. a. See Appendix A for information about the map text files. b. Note that we have provided most of the file handling already. Step 1. Write Code for createMap (...) Function 1. Open logic.cpp and locate the createMap function. Make sure to read the block comment describing the function. 2. Dynamically allocate a 2D char array with maxRow rows and maxCol columns. Initialize each array element to TILE_OPEN. 3. Return a pointer to the array. Step 2. Write Code for deleteMap (...) Function 1. Open logic.cpp and locate the deleteMap function. Make sure to read the block comment describing the function. 2. Deallocate the 2D char array pointed at by the pointer map, and make sure not to leak memory! (Hint: what should the parameter maxRow be used for?) Step 3. Write Code for resizeMap(...) Function 1. Open logic.cpp and locate the resizeMap function. Make sure to read the block comment describing the function. * 2. Dynamically allocate a 2D array with (2 maxRow) rows and (2 maxCol) columns using your createMap function. Visually, we can divide this 2D array into four maxRowxmaxCol subarrays: A C * B D 3. Copy the contents of the array map into the subarray A exactly (including the adventurer). Copy the contents of the array map into each of the subarrays B, C, and D, except for the adventurer, which should be replaced by TILE_OPEN. 4. Deallocate the original map using your deleteMap function and update any variables as necessary. 5. Return a pointer to the new array. Step 4. Write Code for doPlayerMove (...) Function 1. Open logic.cpp and locate the doPlayerMove function. Make sure to read the block comment describing the function. You will be returning a status from logic.h that gives the result of the attempted move. 2. The next position is determined by nextRow and nextColumn. a. If the next position places the adventurer outside the bounds of the array or on an unpassable tile (a pillar or a monster), set the status to STATUS_STAY and update nextRow and nextCol to be the adventurer's current position (i.e., the adventurer did not move). Remember to check that nextRow and nextCol are within bounds before using them to check a tile's value (short circuit evaluation might be useful, see zyBook 1.49). b. If the next position is on a treasure tile, set the appropriate status and increment the adventurer's treasure by one. C. If the next position is on an amulet tile, set the appropriate status. d. If the next position is on a door (to the next level), set the appropriate status. e. If the next position is on an exit (to the whole dungeon) and the adventurer has at least one piece of treasure, set the appropriate status. If the adventurer has no treasure treat the door as you would a pillar. 3. Update the map by updating the adventurer's position to the next position, setting the new position to TILE_PLAYER and the adventurer's old position to TILE_OPEN. 4. Return the appropriate status flag. Step 5. Write Code for doMonsterAttack(...) Function 1. Open logic.cpp and locate the doMonsterAttack function. Make sure to read the block comment describing the function. 2. The logic for the monster Al is as follows: a. Starting from the tile above the adventurer's location and working upward, check each individual tile to see if there is a monster on the tile. b. c. If there is a monster on a tile, move the monster one tile closer to the adventurer. Continue to check until you have reached the top of the map or reach a pillar (monsters can't see through pillars) 3. Repeat the same logic with down, left, and right (in that order). Make sure all monsters that are supposed to move do so before you go to the next step (Step 4). 4. The adventurer is killed if a monster moves onto their tile (check if the player position now contains a monster), return true (adventurer killed, game over) if so, otherwise return false (the monsters did not attack the adventurer, yet...). Testing Your Code (AKA Playing the Game) Sample Dungeons Included in the starter code from Mimir is a folder of sample dungeon levels. You will find the 4 tutorial levels, 2 levels for the "easy" dungeon, and 3 levels for the "hard" dungeon. Moving these files into the same directory as your dungeoncrawler.cpp main file will allow you to play the dungeon and test your code. See Appendix B for more information about playing the game. As an example, to play the hard dungeon, you would enter "hard 3" at the beginning prompt. You may want to test with the tutorial or easy dungeon. The hard dungeon is not for the faint of heart! Can you escape it²? Of course, feel free to create your own levels! Review Appendix A for information about the level file structure. Appendix A: Input Map Text File This assignment will involve reading a text file that contains information of the dungeon map's internal representation. This text file consists of three parts: The first number in Line 3 represents the map tile at (0, 0), where the first value is the row position and the second value is the column position. Refer to the tile status constants in logic.h for more details. The following is an example text file for a 5×3 tile representation of a dungeon map. ΠΜΣιιιΘ ● Line 1: Map Dimensions. This line contains two values for representing the map's number of rows and number of columns, respectively. Line 2: Player Starting Location. This line contains two values for representing the player's starting row and column, respectively. Lines 3+: These lines contain the individual tile information of the dungeon map as char values. O 5 3 30 M + + - + tA O ● Line 1; The map has 5 rows and 3 columns. Line 2: The player will start at map location (3, 0), where 3 is the row position and 0 is the column position. Remember that indexing starts from 0, so the top left corner will be map location (0, 0). Lines 3-7: The map's internal representation for each map tile. O Note #1: Whitespace for lines 3 and after are purely for aesthetic purposes, so you must not assume that line breaks represent the actual map dimensions or that there will be spaces in between the char values. O O O Note #2: In previous assignments you used column-major order when working with 2D arrays and PPM files, which is the norm in the graphics community. In this assignment you will be using row-major ordering when working with your 2D arrays, as this is how a C++ program will typically order a multidimensional array. Note #3: Each level of a dungeon has its own map stored in a different file, each named according to the dungeon name followed by the level number. For example, if the dungeon is named "tutorial" and has four levels, the files will be "tutorial1.txt”, “tutorial2.txt”, “tutorial3.txt”, and “tutorial4.txt". Note #4: Only the final level will have an exit (an ! symbol); all the other levels have doors (a ? symbol) to the next level. Appendix B: Gameplay Loading a Game Each game starts with a printout of the instructions, followed by a prompt for the dungeon name and the number of levels in the dungeon. Here our dungeon is called tutorial and it has 4 levels (user input in dark red): Good day, adventurer! Your goal is to get the treasure and escape the dungeon! SYMBOLS --- --- O +₂ ? ! : That is you, the adventurer! : These are treasures. Lots of money! : These magical amulets resize the level. : These are monsters; avoid them! --- : These are unpassable obstacles. : A door to another level. : A door to escape the dungeon. CONTROLS w, a, s, d: Keys for moving up, left, down, and right. e : Key for staying still for a turn. q : Key for abandoning your quest. Please enter the dungeon name and number of rooms: tutorial 4 Navigating the Dungeon Our dungeon crawler uses the WASD³ method of controlling the in-game adventurer: w and s move the adventurer up one row and down one row respectively, while a and d move the adventurer left one column and right one column respectively. Entering e will cause the adventurer to stay still for a turn. Tiles with unpassable obstacles (a pillar) cannot be moved onto, and are represented by the + symbol. The door to the next level is represented by the ? symbol, while the door out of the dungeon (and thus the game) is represented by the ! symbol. Level 1 + O + ? + Enter command (w,a,s,d: move, e: stay still, q: quit): s + + O + ? | +--- -+ You have moved to row 1 and column Enter command (w,a,s,d: move, e: stay still, q: quit): s + + + o ? + You have moved to row 2 and column 0 Enter command (w,a,s,d: move, e: stay still, q: quit): de + O -+ You have moved to row 2 and column 1 You go through the doorway into the unknown beyond... Treasure Dungeons are dangerous places, so why would you put up with all that risk for no reward? Tiles with treasure on them are represented by the $ symbol. Pick up a piece of treasure by moving the adventurer to that tile. Upon exiting, the game will tell you how much treasure was picked up by the adventurer across all levels. But make sure you don't leave empty-handed, since the door out of the dungeon (represented by the ! symbol) won't open if you don't have at least one piece of treasure! Level 2 O $ ? Enter command (w,a,s,d: move, e: stay still, q: quit): de O ? You have moved to row 1 and column 2 Well done, adventurer! You found some treasure. You now have 1 treasure. Enter command (w,a,s,d: move, e: stay still, q: quit): de ? | O | +- -+ You have moved to row 1 and column 3 Enter command (w,a,s,d: move, e: stay still, q: quit): W + ? | | O + You have moved to row 0 and column 3 Enter command (w,a,s,d: move, e: stay still, q: quit): du +- o | +- -+ You have moved to row 0 and column 4 You go through the doorway into the unknown beyond... Monsters So what makes dungeons so dangerous anyway? The monsters kept in them to guard the treasure of course! Monsters are represented by the symbol M, and will chase any adventurer in their line of sight (i.e., if the adventurer is a rook's move from them). Thankfully, they are slow and move only one tile per turn, and cannot see over unpassable obstacles, allowing the adventurer to hide behind them. The adventurer is quick enough that he can get through a door before a monster attacks on the next turn, but won't be able to pick up an item and then withstand an attack. Monster attacks are lethal, and being killed by the monster will cause you to lose the game. The adventurer is not strong enough to attack a monster, so the only strategy is to run away. Monsters are powerful, and will destroy any (passable) obstacle in their path - including treasure, amulets, and even doors! Make sure that the monsters don't destroy the only way out... Magic Amulets The dungeon also holds many ancient and mysterious artifacts, such as magic amulets. Magic amulets are represented by the @symbol. Picking up an amulet will cause the level to double in size, with three additional copies of the level (without additional adventurers, but with additional monsters and items) appearing below, to the right, and diagonally below and right of the level. Unfortunately, the amulet is destroyed in the process and isn't copied as well. Level 4 +-- | o | + + | @ + Enter command (w,a,s,d: move, e: stay still, q: quit): s + O | @ + +- -+ You have moved to row 1 and column 0 + + | O Enter command (w,a,s,d: move, e: stay still, q: quit): su +- --+ + + + + + + ! + | + | ! + + | + ! | You have moved to row 2 and column 0 The magic amulet sparkles and crumbles into dust. The ground begins to rumble. Are the walls moving? Enter command (w,a,s,d: move, e: stay still, q: quit): S + + + + + ! + + O + + + + You have moved to row 3 and column 0 Enter command (w,a,s,d: move, e: stay still, q: quit): d + + ! + + | + ! | + ! + + + + + + + You have moved to row 3 and column 1 Enter command (w,a,s,d: move, e: stay still, q: quit): w + + + + + + + O + ! + + ! + + + ! | + + You have moved to row 2 and column 2 Congratulations, adventurer! You have escaped the dungeon! You escaped with 1 treasure and in 16 total moves. Quitting the Game You can quit the game at any time by entering the symbol q. Just be careful, as there is no way to save your progress. HN34567 1 2 8 9 logic.cpp #ifndef HELPER_H #define HELPER_H #include "logic.h" X dungeoncrawler.cpp x // constant value for tile width in console output const int DISPLAY_WIDTH = 3; // function signatures, do not change void printInstructions(); #endif helper.cpp X 10 11 12 void outputMap (char** board, const int maxRow, const int maxCol); 13 14 void outputStatus(const int status, const Player& player, int moves); 15 16 17 logic.h X helper.h X MUNKA brea ** 1 #ifndef LOGIC_H 2 #define LOGIC_H 3 4 9 10 #define INFO (X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE__<<") 5 #include <iostream> 6 #include <fstream> 7 #include <string> 8 using std::cin, std::cout, std::endl, std::string, std::ifstream; 11 12 13 14 15 16 17 1/ 18 18 19 20 20 24 21 22 22 22 23 21 24 25 26 26 27 28 29 30 31 32 32 22 33 24 34 35 36 37 38 39 40 41 42 43 44 45 46 47 47 48 49 logic.cpp 50 51 52 53 54 55 56 57 58 59 co // Player object container struct Player { int row = 0; int col = 0; int treasure = 0; X }; // constants for tile status const char TILE_OPEN const char TILE_PLAYER const char TILE_TREASURE const char TILE_AMULET const char TILE_MONSTER const char TILE_PILLAR const char TILE_DOOR const char TILE_EXIT = ''; = '0'; = '$'; = '@'; = 'M'; = '+'; = '?'; const int STATUS_MOVE = 1; const int STATUS_TREASURE = 2; const int STATUS_AMULET = 3; const int STATUS_LEAVE = 4; const int STATUS_ESCAPE = 5; dungeoncrawler.cpp x // constants for user's keyboard const char INPUT_QUIT const char INPUT_STAY const char MOVE_UP const char MOVE_LEFT const char MOVE_DOWN const char MOVE_RIGHT // constants for movement status flags const int STATUS_STAY = 'q'; = 'e'; = 'w'; = 'a'; = 's'; = 'd'; // blank tile // tile for player's current location // tile for unpassable pillar location // tile for hazard that enlarges the dungeon // tile for monster current location helper.cpp // tile for unpassable pillar location // tile for door to the next room // tile for exit door out of dungeon "<<_LINE_<<") " << #X << " = " << X << endl; // flag indicating player has stayed still // flag indicating player has moved in a direction // flag indicating player has stepped onto the treasure // flag indicating player has stepped onto an amulet inputs X // flag indicating player has left the current room // flag indicating player has gone through the dungeon exit // quit command // no movement // up movement // left movement // down movement // right movement // function signatures, do not change char** loadLevel(const string fileName, int& maxRow, int& maxCol, Player& player); void getDirection (char input, int& nextRow, int& nextCol); char** createMap (int maxRow, int maxCol); void deleteMap (char** board, int maxRow); char** resizeMap (char* map, int& maxRow, int& maxCol); int doPlayerMove (char** map, int maxRow, int maxCol, Player& player, int& nextRow, int& nextCol); bool doMonsterAttack (char** map, int maxRow, int maxCol, Player& player); #endif logic.h 1 2 3 4 5 6 7 8 9 10 11 ខជន២១–២១៩ឥ៩៧៩ដង ដកពីភពអត២តឥន្ធ ទី១ ២ ខ ទ ជ ផ ព ភ មា ន ភ ន ន ៩ ៨ ៨២៩២៩ 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 } // do not change 29 void outputMap (char** map, const int maxRow, const int maxCol) { 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 logic.cpp #include <iostream> #include "helper.h" using std::cout, std::endl; 66 67 // do not change void printInstructions() { cout << endl; cout << } cout << 0 cout << " $ cout << @ cout << "M cout << +, cout << " ? cout << ! cout << cout << " W, cout << e cout << " cout << " cout << endl; cout << "Good day, adventurer!" cout << "Your goal is to get the treasure and escape the dungeon!" SYMBOLS " cout << q | } cout << "+"; cout << endl; | -, | } X // output top border cout << "+"; for (int i = 0; i < maxCol * DISPLAY_WIDTH; ++i) { cout << "-"; : These are monsters; avoid them!" : These are unpassable obstacles." : A door to another level." : A door to escape the dungeon." CONTROLS --_" a, s, d: Keys for moving up, left, down, and right." Key for staying still for a turn." dungeoncrawler.cpp x : That is you, the adventurer!" : These are treasures. Lots of money!" : These magical amulets resize the level." for (int i = 0; i < maxRow; ++i) { // output left border cout << "|"; } else { : : Key for abandoning your quest." } cout << " "; // output inner blocks for (int j = 0; j < maxCol; ++j) { // output current block cout << " "; if (map[i][j] == TILE_OPEN) { cout << " "; cout << "+"; cout << endl; cout <<map[i][j]; } // output right border cout << "|"; cout << endl; } // output bottom border cout << "+"; for (int i = 0; i < maxCol * DISPLAY_WIDTH; ++i) { cout << "-"; helper.cpp << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; << endl; COORNARNEFNTT88 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 89 90 91 92 93 94 95 96 97 98 99 // do not change void outputStatus(const int status, const Player& player, int moves) { if (status != STATUS_STAY) { cout << "You have moved to row " << player.row << " and column " << player.col << endl; } | } switch (status) { case STATUS_STAY : cout << "You stayed at row" << player.row << "and column " << player.col << endl; cout << "You didn't move. Are you lost?" << endl; break; case STATUS_MOVE : case STATUS_TREASURE : cout << "Well done, adventurer! You found some treasure." << endl; cout << "You now have " << player.treasure <<< (player.treasure > 1 ? " treasures." : " treasure.") << endl; break; break; case STATUS_AMULET : cout << "The magic amulet sparkles and crumbles into dust." << endl; cout << "The ground begins to rumble. Are the walls moving?" << endl; break; case STATUS_LEAVE : cout << "You go through the doorway into the unknown beyond..." << endl; break; case STATUS_ESCAPE : cout << "Congratulations, adventurer! You have escaped the dungeon!" << endl; cout << "You escaped with " << player.treasure <<< (player.treasure > 1 ? " treasures cout << "and in " << moves << " total moves." << endl; break; } cout << endl; ; " treasure "); logic.cpp 1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include "helper.h" 5 #include "logic.h" 6 using std::cin, std::cout, std::endl, std::string, std::ifstream; 7 8 9 10 11 12 13 14 15 HHAHAAN~~~~~~≈28-235SMERTE 16 17 18 19 20 21 24 26 27 29 30 31 33 34 36 37 39 40 41 int main() { X dungeoncrawler.cpp × // display greeting message printInstructions(); string dungeon; int total_rooms; Player player; cout << "Please enter the dungeon name and number of levels: "; cin >> dungeon >> total_rooms; // declare variables int maxRow = 0; int maxCol = 0; int nextRow = 0; int nextCol = 0; helper.cpp int total_moves = 0; for(int current_room = 1; current_room <= total_rooms; current_room++) { cout << "Level " << current_room << endl; string fileName = dungeon + std::to_string(current_room) + ".txt"; // create map, or quit if map load error char** map = loadLevel(fileName, maxRow, maxCol, player); if (map == nullptr) { cout << "Returning you back to the real word, adventurer!" << endl; return 1; } // display map outputMap (map, maxRow, maxCol); ◄► 41 42 43 44 45 TO 46 TO 47 M 48 49 49 50 50 31 51 52 53 55 54 34 55 39 30 56 57 58 58 „:♫nnib:t❀❀RF~^*^ºFºr:⠀≈⠀⠀456⠀⠀:¯¯ 59 60 61 62 63 04 05 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 199 89 90 91 92 93 logic.cpp // move player char input = 0; int status = 0; while (true) { dungeoncrawler.cpp X } // get user input cout<<"Enter command (w,a,s,d: move, e: stay still, q: quit): "; cin >> input; // quit game if user inputs quit if (input == INPUT_QUIT) { cout << "Thank you for playing!" << endl; deleteMap (map, maxRow); return 0; } // increment dungeon movement counter total_moves++; if (input == INPUT_STAY) { status = STATUS_STAY; } else { helper.cpp // reprompt if invalid command if (input != MOVE_UP && input != MOVE_LEFT && input != MOVE_DOWN && input != MOVE_RIGHT && input != INPUT_STAY) { cout << "I did not understand your command, adventurer!" << endl; continue; } // quit game if user escapes if (status== STATUS_ESCAPE) { X getDirection (input, nextRow, nextCol); // move player to new location index, if possible, and get player status status = doPlayerMove (map, maxRow, maxCol, player, nextRow, nextCol); outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); deleteMap (map, maxRow); return 0; // translate from the character input to a direction // we will use the player's current location and pass-by-reference to find the intended next location nextRow=player.row; nextCol=player.col; } // go to next level if user goes through door if (status == STATUS_LEAVE) { logic.h outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); break; } // move monsters, end if player is caught X helper.h 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 } } // move monsters, end if player is caught if (doMonsterAttack(map, maxRow, maxCol, player)) { } // use amulet if (status == STATUS_AMULET) { } outputMap (map, maxRow, maxCol); cout << "You died, adventurer! Better luck next time!" << endl; deleteMap (map, maxRow); return 0; map = resizeMap (map, maxRow, maxCol); // display map and status outputMap (map, maxRow, maxCol); outputStatus (status, player, total_moves); } return 0; // delete map deleteMap (map, maxRow); ← 7 8 9 10 11 12 13 14 15 16 17 18 1 2 3 #define INFO (X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE_<<") " << #X << " = " << X << endl; 4 #define INFO_STRUCT(X) cout << "[INFO] ("<<_FUNCTION_<<":"<<_LINE_<<") " << #X << " = {"' << X. row << "," << X.col << "," << X.treasure << "}" << endl; 5 6 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 logic.cpp #include "logic.h" 39 40 41 42 43 44 45 *This function is provided; do not change * Load representation of the dungeon level from file into the 2D map. * Calls createMap to allocate the 2D array. * @param fileName * @param } dungeoncrawler.cpp x File name of dungeon level. * @param Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object by reference to set starting position. * @param * @return 2D dynamic array representation of dungeon map with player's location. */ char** loadLevel(const string fileName, int& maxRow, int& maxCol, Player& player) { INFO(maxRow); INFO (maxCol); ifstream ifs (fileName); if (!ifs.is_open()) { maxRow maxCol player } ifs >> maxRow >> maxCol; ifs >> player.row >> player.col; } cout << "ERROR: Unable to open: " << fileName << endl; return nullptr; char** dungeon = createMap (maxRow, maxCol); if (dungeon == nullptr) { cout << "ERROR: Map did not load." << endl; return nullptr; } for (int i = 0; i < maxRow; i++) { helper.cpp } for (int j = 0; j < maxCol; j++) { ifs >> dungeon [i][j]; if (i == player.row && j = player.col) { dungeon [i][j] = TILE_PLAYER; return dungeon; logic.h X helper.h 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 logic.cpp } /** * This function is provided; do not change * Translate the character direction input by the user into row or column change. * That is, updates the nextRow or nextCol according to the player's movement direction. * @param input * @param nextRow nextCol Character input by the user which translates to a direction. Player's next row on the dungeon map (up/down). Player's next column on dungeon map (left/right). * @param */ void getDirection (char input, int& nextRow, int& nextCol) { switch (input) { } case MOVE_UP: nextRow--; break; } case MOVE_DOWN: nextRow++; break; case MOVE_LEFT: nextCol--; break; } case MOVE_RIGHT: nextCol++; break; * TODO: Student implement this function * Allocate the 2D map array. * Initialize each cell to TILE_OPEN. dungeoncrawler.cpp x * @param maxRow * @param maxCol * @return 2D map array for the dungeon level, holds char type. */ char** createMap (int maxRow, int maxCol) { INFO (maxRow); INFO (maxCol); return nullptr; helper.cpp Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). /** * TODO: Student implement this function * Deallocates the 2D map array. * @param map * @param maxRow */ void deleteMap (char** map, int maxRow) { INFO (map); INFO (maxRow); return; logic.h Dungeon map. Number of rows in the dungeon table (aka height). 90 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 /** * TODO: Student implement this function * Resize the 2D map by doubling both dimensions. * Copy the current map contents to the right, diagonal down, and below. * Do not duplicate the player, and remember to avoid memory leaks! * You can call your createMap and deleteMap functions to help with this one! * @param * @param map maxRow maxCol * @param * @return An updated 2D map that has twice as many columns and rows in size. */ char** resizeMap (char** map, int& maxRow, int& maxCol) { INFO (map); INFO (maxRow); INFO(maxCol); } Dungeon map. Number of rows in the dungeon table (aka height), to be doubled. Number of columns in the dungeon table (aka width), to be doubled. return nullptr; /** * TODO: Student implement this function * Checks if the player can move in the specified direction and performs the move if so. * Cannot move out of bounds or onto TILE_PILLAR or TILE_MONSTER. * Cannot move onto TILE_EXIT without at least one treasure. * If TILE TREASURE, increment treasure by 1. * Remember to update the map tile that the player moves onto and return the appropriate status. * You can use the STATUS constants defined in logic.h to help! * @param map * @param * @param * @param maxRow maxCol player nextRow nextCol * @param * @param * @return Player's movement status after updating player's position. */ } Dungeon map. Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object to by reference to see current location. Player's next row on the dungeon map (up/down). Player's next column on dungeon map (left/right). int doPlayerMove (char** map, int maxRow, int maxCol, Player& player, int& nextRow, int& nextCol) { INFO (map); INFO (maxRow); INFO (maxCol); INFO_STRUCT (player); INFO (nextRow); INFO(nextCol); return -1; // update to use STATUS consts from logic.h! 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 /** * TODO: Student implement this function * Update monster locations: * We check up, down, left, right from the current player position. * If we see an obstacle, there is no line of sight in that direction, and the monster does not move. * If we see a monster before an obstacle, the monster moves one tile toward the player. * We should update the map as the monster moves. * At the end, we check if a monster has moved onto the player's tile. Dungeon map. * @param map * @param maxRow * @param maxCol Number of rows in the dungeon table (aka height). Number of columns in the dungeon table (aka width). Player object by reference for current location. * @param player * @return Boolean value indicating player status: true if monster reaches the player, false if not. */ bool doMonsterAttack(char** map, int maxRow, int maxCol, Player& player) { } INFO (map); INFO (maxRow); INFO (maxCol); INFO_STRUCT (player); // check up // check down // check left // check right // check if any monster is on player return false; 1 2 3 4 5 9 7 8 9 easy1.txt 75 51 I I | I I | + + + + | I I ΙΣΤΙ I - I X HEMAFOTOG 1 2 3 4 5 6 7 8 9 10 hard3.txt 88 22 M - M - - M - $ + + $ + ! M + M - M - @ I H~3456 1 2 4 hard3.txt 33 00 @ + + - + tutorial4.txt
Expert Answer:
Answer rating: 100% (QA)
Heres an example in C Function to create and store values in a 2D dynamic array void create2DArrayin... View the full answer
Related Book For
Income Tax Fundamentals 2013
ISBN: 9781285586618
31st Edition
Authors: Gerald E. Whittenburg, Martha Altus Buller, Steven L Gill
Posted Date:
Students also viewed these electrical engineering questions
-
COM 204 WU001 nterwnsyeE Homework: Online Assignment, Chapter 4 & 5 varinderjeet kaur 06/11/21 222 PM ori Score: 0 of 8 pts Save 3 of 5 (0 complete) HW Score: 0%, 0 of 35 pts P4-37A (similar to)...
-
Southgate Inc.'s alphabetized adjusted trial balance on December 31, 2015 is below. a) Calculate net income (loss) for the year ending December 31, 2015. Please make sure your final answer(s) are...
-
Consider the following I/O scenarios on a single-user PC. a. A mouse used with a graphical user interface b. A tape drive on a multitasking operating system (assume no device preallocation is...
-
Marquis Company uses a weighted-average perpetual inventorysystem. August 2, 22 units were purchased at $3 per unit. August 18, 27 units were purchased at $5 per unit. August 29, 24 units were sold....
-
If interest rates are expected to increase, should investors look to long-term bonds or short-term securities? Explain.
-
Andrea is an employee of Fern Corporation. She also has her own business working as a life coach. For 2015, Andrea's wages from Fern were $210,000. Her self-employment income was $30,000. a. Compute...
-
In a recent study involving 42 men, the mean body temperature of the men was found to be 96.8F, with a standard deviation of 0.61. Random samples of size 30 are drawn from this population, and the...
-
Sye Chase started and operated a small family architectural firm in 2016. The firm was affected by two events: (1) Chase provided $25,000 of services on account, and (2) he purchased $2,800 of...
-
Thank you! Problem 1 The analyst is analyzing the ?nancial statements of another Yettobe corporation (the state?? ments are in million dollars). Its stock is currently traded at $50 and it has 20 m...
-
Calculate the molar volume of saturated liquid and the molar volume of saturated vapor by the Redlich/Kwong equation for one of the following and compare results with values found by suitable...
-
Pet Food Company bonds pay an annual coupon rate of 10.51 percent. Coupon payments are paid semiannually. Bonds have 13 years to maturity and par value of $1,000. Compute the value of Pet Food...
-
T Ltd has issued 100 000 bonds with a face value of $100 each. The coupon rate of interest is 5%. After a certain date, the holders have the option of converting the bonds to a fixed number of...
-
Having travelled halfway to the end of a journey at an average speed of 1 5 km / h , how fast must you traverse the rest of the trip in order to have average speed of 2 0 . 0 km / h ? Be sure to...
-
Where will you see errors in the following code: (Select only 3) A.java X 1 package test; 2 3 public class A { 4 private int i; 5 60 7 8 9 100 11 12 13 14 15} 16 int j; int A() { } void changeVal() {...
-
EXAMPLE 4-10 How Much Is a Lifetime Oil Change Offer Worth? "Make your best deal with us on a new automobile and we'll change your oil for free for as long as you own the car!" If you purchase a car...
-
Marco Company shows the following costs for three jobs worked on in April. Job 306 Job 307 Job 388 Balances on March 31 Direct materials used (in March) Direct labor used (in March) $ 30,200 21,200...
-
1- What do you think was the most significant thing kadra took back from her trip to Syria? 2- Did you expect Khadra to rebel against her strict religious upbringing before she did?...
-
Estimate a range for the optimal objective value for the following LPs: (a) Minimize z = 5x1 + 2x2 Subject to X1 - x2 3 2x1 + 3x2 5 X1, x2 0 (b) Maximize z = x1 + 5x2 + 3x3 Subject to X1 + 2x2 +...
-
Jim is fired from his job as a waiter and decides to take an extended trip to Europe. After touring Europe for 3 months, Jim returns to look for a new job as a waiter. Are his job-hunting expenses...
-
Ulysses and Penelope are married and file separate returns for 2012. Penelope itemizes her deductions on her return. Ulysses' adjusted gross income was $17,400, his itemized deductions were $2,250,...
-
On September 14, 2012, Jay purchased a passenger automobile that is used 75 percent in his accounting business. The automobile has a basis for depreciation purposes of $35,000, and Jay uses the...
-
Referring to information in Brief Exercise 14-18, assume that Henry Inc. sold its holdings of Container Corporation bonds on July 2, 2020, for \(\$ 4,800\). Record the sale of the debt investment,...
-
On January 1, 2020, Sharp Company purchased \(\$ 50,000\) of Sox Company \(5 \%\) bonds, at a time when the market rate was \(6 \%\). The bonds mature on December 31, 2024, and pay interest...
-
Assume the same facts as in Brief Exercise 14-16, except that Sharp Company does not intend to trade the bonds or to hold them until maturity. a. Prepare the entry for the purchase of the debt...
Study smarter with the SolutionInn App