/* Filename: homework2.cpp Author: Br. David Carlson and ______________________ Other contributors: References: Date: January 28, 2001 Revised: This program allows the user to repeatedly play a text-based game. The game is played on a 10 by 10 board, where most of the cells are initially covered by fog. One cell in that fog contains a treasure. The goal of the game is to reach that treasure. Several other cells in the fog contain obstacles. The player of the game occupies one cell on the board. A foggy cell is displayed as an X. The player is displayed as ^, <, v, or >, where the arrow points in the direction in which the player can move or shine the spotlight. An obstacle that has been made visible by the spotlight is displayed as an O. If the treasure is made visible by the spotlight, it is shown as a T. The initial board configuration is not always the same; it is somewhat randomly generated. When a game starts, the player is asked to enter the degree of difficulty. This sets the maximum number of moves that the player can make. (Entering E for Easy gives 36 moves, M for Medium gives 24 moves, and H for Hard gives 16 moves.) Input checking is used to force the user to enter a correct letter. The player is repeatedly ask to enter a letter indicating a move: R to turn right 90 degrees, L to turn left 90 degrees, G to go forward, S to shine a spotlight, and Q to quit the game. All letters can be entered in either upper or lower case. Input checking is used to force the user to enter a correct letter. If the choice is G to go forward, the player is asked to enter the number of spaces to move. Input checking is used to force the player to enter a positive number. If the number would move the player off of the board, the move is refused (but still counted in the number of moves made). If the player runs into an obstacle, the player loses and the game is over. If the player runs into the treasure, the game is over and the player wins. If the choice is S to shine the spotlight, the light shines until it reaches the edge or the board, an obstacle, or the treasure, whichever comes first. The light cannot shine through an obstacle or the treasure. Whatever cells the light shines through are cleared of fog and now display as empty cells. If the light shines on an obstacle, it is displayed as an O. If the light shines on the treasure, it is shown as a T. After each move a message is displayed if the player has now won or lost. The remaining number of moves is shown and the current board configuration (as far as it is known to the player) is displayed. */ #include #include #include using namespace std; const int Max = 10; typedef char BoardType[Max][Max]; /* Implementation note: Internally, a BoardType array will be used to store the current configuration of the game, where each cell contains one of the following symbols: X = foggy cell (the player does not know what is in here) o = an obstacle not yet visible to the player (who sees it as an X) O = an obstacle which is visible to the player t = the treasure, not yet visible to the player (who sees it as an X) T = the treasure, when visible to the player ^ = the player, pointing up < = the player, pointing left v = the player, pointing down > = the player, pointing right A blank character is used to represent an empty cell (cleared of fog). */ // Function prototypes: void OneGame(void); int GetDifficulty(void); void Display(BoardType Board, int NumMoves); void OneMove(BoardType Board, int & CurrentX, int & CurrentY, bool & Done); void Initialize(BoardType Board, int & CurrentX, int & CurrentY); int RandInt(int Low, int High); int GetSpaces(void); char GetMove(void); void GoUp(BoardType Board, int & CurrentX, int CurrentY, bool & Done, int Spaces); void GoLeft(BoardType Board, int CurrentX, int & CurrentY, bool & Done, int Spaces); void GoRight(BoardType Board, int CurrentX, int & CurrentY, bool & Done, int Spaces); void GoDown(BoardType Board, int & CurrentX, int CurrentY, bool & Done, int Spaces); void Reveal(BoardType Board); int main(void) { char Reply; do { OneGame(); cout << "Play another game (y/n)? "; cin >> Reply; } while ((Reply == 'Y') || (Reply == 'y')); return 0; } /* Given: nothing. Task: To play one game. Return: nothing. */ void OneGame(void) { BoardType Board; int CurrentX, CurrentY, NumMoves; bool Done; Done = false; NumMoves = GetDifficulty(); Initialize(Board, CurrentX, CurrentY); Display(Board, NumMoves); while ((NumMoves > 0) && (! Done)) { OneMove(Board, CurrentX, CurrentY, Done); NumMoves--; Display(Board, NumMoves); } cout << "Game is over. Here is the final board revealed:" << endl; Reveal(Board); } /* Given: nothing. Task: To ask the user whether the degree of difficulty should be easy, medium, or hard and to figure out the maximum number of moves based on this. Insist on correct input. Return: The maximum number of moves in the function name. */ int GetDifficulty(void) { char Temp; cout << "Degree of difficulty: E)asy M)edium H)ard "; cin >> Temp; Temp = toupper(Temp); while ((Temp != 'E') && (Temp != 'M') && (Temp != 'H')) { cout << "Enter first letter: E)asy M)edium H)ard "; cin >> Temp; Temp = toupper(Temp); } if (Temp == 'E') return 48; else if (Temp == 'M') return 32; else return 16; } /* Given: nothing. Task: To ask the user for the letter representing the move the user wants to make and to insist on a correct letter. Return: This letter (in upper case) in the function name. */ char GetMove(void) { char Temp; cout << "Enter your move: R)ight L)eft S)eachlight G)o Q)uit "; cin >> Temp; Temp = toupper(Temp); while ((Temp != 'R') && (Temp != 'L') && (Temp != 'S') && (Temp != 'G') && (Temp != 'Q')) { cout << "Enter letter: R)ight L)eft S)eachlight G)o Q)uit "; cin >> Temp; Temp = toupper(Temp); } return Temp; } /* Given: nothing. Task: To ask the user for the number of spaces to move ahead and to insist on a positive number. Return: This number in the function name. */ int GetSpaces(void) { int Temp; cout << "Go ahead how many spaces? "; cin >> Temp; while (Temp <= 0) { cout << "Enter a positive integer number of spaces: "; cin >> Temp; } return Temp; } /* Given: Board Array holding current board configuration. NumMoves Number of moves the player has left. Task: To display this board on the screen, but keeping hidden items hidden as X's. Also displays NumMoves. Return: nothing. */ void Display(BoardType Board, int NumMoves) { int Row, Col; char Cell; cout << " "; for (Col = 0; Col < Max; Col++) cout << Col << " "; cout << " Number of moves left: " << NumMoves << endl; for (Row = 0; Row < Max; Row++) { cout << Row << " "; for (Col = 0; Col < Max; Col++) { Cell = Board[Row][Col]; if ((Cell == 'o') || (Cell == 't')) // hidden items cout << 'X' << " "; else cout << Cell << " "; } cout << endl; } } /* Given: Board Array holding current board configuration. Task: To display this board on the screen, including hidden items. Return: nothing. */ void Reveal(BoardType Board) { int Row, Col; cout << " "; for (Col = 0; Col < Max; Col++) cout << Col << " "; cout << endl; for (Row = 0; Row < Max; Row++) { cout << Row << " "; for (Col = 0; Col < Max; Col++) cout << Board[Row][Col] << " "; cout << endl; } } /* Given: Board Array containing current board configuration. CurrentX X position of player. CurrentY Y position of player. Task: To prompt the user to make one move, updating the 3 parameters as a result. Return: Board Updated board configuration. CurrentX Updated X position of player. CurrentY Updated Y position of player. */ void OneMove(BoardType Board, int & CurrentX, int & CurrentY, bool & Done) { char Move, Symbol; int Spaces; Move = GetMove(); Symbol = Board[CurrentX][CurrentY]; if (Move == 'L') //*** Call a function to turn the player left 90 degrees else if (Move == 'R') //*** Call a function to turn the player right 90 degrees else if (Move == 'S') { if (Symbol == '^') //*** Call a function to shine spotlight upward else if (Symbol == '<') //*** Call a function to shine spotlight leftward else if (Symbol == 'v') //*** Call a function to shine spotlight downward else //*** Call a function to shine spotlight righward } else if (Move == 'G') { Spaces = GetSpaces(); if (Symbol == '^') GoUp(Board, CurrentX, CurrentY, Done, Spaces); else if (Symbol == '<') GoLeft(Board, CurrentX, CurrentY, Done, Spaces); else if (Symbol == 'v') GoDown(Board, CurrentX, CurrentY, Done, Spaces); else GoRight(Board, CurrentX, CurrentY, Done, Spaces); } else // Q to quit Done = true; } /* Given: Board Current board configuration. CurrentX Current X coordinate of player. CurrentY Current Y coordinate of player. Done Indicates if games is done. Spaces Number of spaces uses wants to move up. Task: To move the player up this number of spaces, if possible, and update things accordingly. Return: Board Updated board configuration. CurrentX Updated X coordinate of player. Done Indicates if game is now done. */ void GoUp(BoardType Board, int & CurrentX, int CurrentY, bool & Done, int Spaces) { int Row, EndRow; char Ch; if (Spaces > CurrentX) cout << "Move rejected -- you would be off the edge" << endl; else { EndRow = CurrentX - Spaces; for (Row = CurrentX - 1; Row >= EndRow; Row--) { Ch = Board[Row][CurrentY]; if ((Ch == 'O') || (Ch == 'o')) { cout << "You lost. You hit an obstacle" << endl; EndRow = Row; Done = true; break; } else if ((Ch == 'T') || (Ch == 't')) { cout << "You won! You reached the treasure" << endl; EndRow = Row; Done = true; break; } else Board[Row][CurrentY] = ' '; } Board[CurrentX][CurrentY] = ' '; CurrentX = EndRow; Board[CurrentX][CurrentY] = '^'; } } /* Given: Board Current board configuration. CurrentX Current X coordinate of player. CurrentY Current Y coordinate of player. Done Indicates if games is done. Spaces Number of spaces uses wants to move left. Task: To move the player left this number of spaces, if possible, and update things accordingly. Return: Board Updated board configuration. CurrentY Updated Y coordinate of player. Done Indicates if game is now done. */ void GoLeft(BoardType Board, int CurrentX, int & CurrentY, bool & Done, int Spaces) { int Col, EndCol; char Ch; if (Spaces > CurrentY) cout << "Move rejected -- you would be off the edge" << endl; else { EndCol = CurrentY - Spaces; for (Col = CurrentY - 1; Col >= EndCol; Col--) { Ch = Board[CurrentX][Col]; if ((Ch == 'O') || (Ch == 'o')) { cout << "You lost. You hit an obstacle" << endl; EndCol = Col; Done = true; break; } else if ((Ch == 'T') || (Ch == 't')) { cout << "You won! You reached the treasure" << endl; EndCol = Col; Done = true; break; } else Board[CurrentX][Col] = ' '; } Board[CurrentX][CurrentY] = ' '; CurrentY = EndCol; Board[CurrentX][CurrentY] = '<'; } } /* Given: Board Current board configuration. CurrentX Current X coordinate of player. CurrentY Current Y coordinate of player. Done Indicates if games is done. Spaces Number of spaces uses wants to move down. Task: To move the player down this number of spaces, if possible, and update things accordingly. Return: Board Updated board configuration. CurrentX Updated X coordinate of player. Done Indicates if game is now done. */ void GoDown(BoardType Board, int & CurrentX, int CurrentY, bool & Done, int Spaces) { int Row, EndRow; char Ch; if (CurrentX + Spaces >= Max) cout << "Move rejected -- you would be off the edge" << endl; else { EndRow = CurrentX + Spaces; for (Row = CurrentX + 1; Row <= EndRow; Row++) { Ch = Board[Row][CurrentY]; if ((Ch == 'O') || (Ch == 'o')) { cout << "You lost. You hit an obstacle" << endl; EndRow = Row; Done = true; break; } else if ((Ch == 'T') || (Ch == 't')) { cout << "You won! You reached the treasure" << endl; EndRow = Row; Done = true; break; } else Board[Row][CurrentY] = ' '; } Board[CurrentX][CurrentY] = ' '; CurrentX = EndRow; Board[CurrentX][CurrentY] = 'v'; } } /* Given: Board Current board configuration. CurrentX Current X coordinate of player. CurrentY Current Y coordinate of player. Done Indicates if games is done. Spaces Number of spaces uses wants to move right. Task: To move the player right this number of spaces, if possible, and update things accordingly. Return: Board Updated board configuration. CurrentY Updated Y coordinate of player. Done Indicates if game is now done. */ void GoRight(BoardType Board, int CurrentX, int & CurrentY, bool & Done, int Spaces) { int Col, EndCol; char Ch; if (CurrentY + Spaces >= Max) cout << "Move rejected -- you would be off the edge" << endl; else { EndCol = CurrentY + Spaces; for (Col = CurrentY + 1; Col <= EndCol; Col++) { Ch = Board[CurrentX][Col]; if ((Ch == 'O') || (Ch == 'o')) { cout << "You lost. You hit an obstacle" << endl; EndCol = Col; Done = true; break; } else if ((Ch == 'T') || (Ch == 't')) { cout << "You won! You reached the treasure" << endl; EndCol = Col; Done = true; break; } else Board[CurrentX][Col] = ' '; } Board[CurrentX][CurrentY] = ' '; CurrentY = EndCol; Board[CurrentX][CurrentY] = '>'; } } /* Given: nothing. Task: To randomly fill in all positions in the Board array. Return: Board Array filled with a collection of the following: X what is in the location is unknown to user o an obstacle t the treasure ^ the player, facing up < the player, facing left v the player, facing down > the player, facing right CurrentX X position of player CurrentY Y position of player */ void Initialize(BoardType Board, int & CurrentX, int & CurrentY) { int Row, Col, NumObstacles, ObstacleCount, ObstacleLength, Direction, LocationX, LocationY; bool Done; char Symbol; srand((unsigned) time(NULL)); // seed the random number generator for (Row = 0; Row < Max; Row++) for (Col = 0; Col < Max; Col++) Board[Row][Col] = 'X'; NumObstacles = RandInt(5, 6); ObstacleCount = 0; while (ObstacleCount < NumObstacles) { ObstacleLength = RandInt(1, 4); Direction = RandInt(0, 1); LocationX = RandInt(0, 8); LocationY = RandInt(0, 8); if (Direction == 0) // horizontal obstacle { Col = LocationY; while ((Col < LocationY + ObstacleLength) && (Col < Max)) Board[LocationX][Col++] = 'o'; } else // vertical obstacle { Row = LocationX; while ((Row < LocationX + ObstacleLength) && (Row < Max)) Board[Row++][LocationY] = 'o'; } ObstacleCount++; } Done = false; while (! Done) { LocationX = RandInt(0, 9); LocationY = RandInt(0, 9); if (Board[LocationX][LocationY] == 'X') { Board[LocationX][LocationY] = 't'; Done = true; } } Done = false; while (! Done) { CurrentX = RandInt(0, 9); CurrentY = RandInt(0, 9); if (Board[CurrentX][CurrentY] == 'X') { Direction = RandInt(0,3); if (Direction == 0) Symbol = '^'; else if (Direction == 1) Symbol = '<'; else if (Direction == 2) Symbol = 'v'; else Symbol = '>'; Board[CurrentX][CurrentY] = Symbol; Done = true; } } } /* Given: Low The lowest value allowed. High The highest value allowed. Task: To compute a pseudorandom integer in the range from Low to High. Return: The random integer is returned in the function name. */ int RandInt(int Low, int High) { float r; int Width, Temp; Width = High - Low + 1; r = rand(); // put into a float r = r / (RAND_MAX + 1); Temp = r * Width; // put into an int return Low + Temp; }