In: Computer Science
In this lab, you will practice the use of array by building an simple maze game, where your task is to control the prince to defeat the monster and save Snow White. You have to work based on the given skeleton code.
Game Description
The Snow White is detained in the maze by the monster, who needs the prince's help to rescure her out from the exit.
The pre-set maze is shown below, with width 11 and height 8. The maze is saved in 1D array in main().
### ###### #P ###### ### # # # # # # W # # # # # ## M # ## ###S #E#
The symbol '#' represents a wall, 'P' is the prince player, 'S' is Snow White, 'M' is the monster, 'W' is the weapon, and 'E' is the exit. Locations of the prince and monster ares stored in an array {x, y}, where x defines column number, y defines row number in main(). Prince 'P' and monster 'M' can only move one step for each move.
The top left of the maze is with coordinates (0,0). The x-coordinate goes positive to the right and y-coordinate goes positive to the bottom. For example, initially the prince 'P' is at coordinate (1,1), the monster 'M' is at coordinate (3,6), and exit 'E' is at coordinate (9, 7). The ascii maze allows the user to input movement (e.g. 'a' left, 'w' up, 'd' right, and 's' down) to control prince 'P'. The monster 'M' is repetitively walking back and forth along the next-to-last line.
When the monster 'M' and prince 'P' can see each other, which means they are in the same line or column, and there is no blocking wall '#' in that straight line/column connecting them, prince 'P' will fight with the monster 'M'. If the weapon 'W' has been fetched by the prince, the monster will be killed and 'M' will disappear from the maze. If not, the prince will be caught and game over.
How to fetch the weapon 'W': The weapon 'W' can be fetched only when the prince 'P' reaches its location. Then, 'W' will disappear from the maze.
How to save Snow White 'S': The Snow White 'S' can be saved only when the prince 'P' reaches its location ('S' will also disappear from the maze after 'P' reaches its location) and take it out from the exit 'E'.
Rules: If the player's movement hits the wall, goes beyond the maze boundary, doesn't fall to the four movement directions or caught by the monster, the prince will be killed and game over. Only when the prince reaches to the exit 'E' after saving Snow White 'S', he wins and game ends.
Hint:
1. We store the status of the monster, weapon, Snow White, ect., in
a bool array status_list in the main function and you should update
it accordingly, such as whether the weapon has been fetched or
not.
2. The position (x, y) can be represented as x + width * y in 1D
array.
3. Please read the main function first to have a general
understanding of the control logic of this game. The code comments
are also important hints.
Tasks
Task 1: Write the function find_pos to store the position of a given symbol in related position array.
Task 2: Write the function is_valid_move to check return if the move is valid or not,including whether the prince's movement hits the wall, goes beyond the maze boundary or doesn't fall to the four movement directions.
Task 3: Write the function update_pos to update the position info.
Task 4: Write the function check_visible to check whether the prince & monster will see each other based on the positions of prince & monster.
Task 5: Fill the function update_maze, which is to update update the position informations, status of prince, monster, weapon & snow white and update the symbols of the maze. There are three missing parts for this incomplete function.
Sample Output
Sample Output for Winning:
*************************************************************** *** Welcome to the maze! Let's start saving our snow white! *** *************************************************************** The prince (P) is in {1, 1} The monster (M) is in {3, 6} The exit (E) is in {9, 7} ### ###### #P ###### ### # # # # # # W # # # # # ## M # ## ###S #E# Your (the prince) current position is at: (1, 1) Please enter your move: (up:w, down:s, left:a, right:d) d ### ###### # P ###### ### # # # # # # W # # # # # ## M # ## ###S #E# Your (the prince) current position is at: (2, 1) Please enter your move: (up:w, down:s, left:a, right:d) d ### ###### # P ###### ### # # # # # # W # # # # # ## M # ## ###S #E# . . . . . . Your (the prince) current position is at: (1, 4) Please enter your move: (up:w, down:s, left:a, right:d) a ### ###### # ###### ### # # # # P # # W # # # # # ## M # ## ###S #E# Your (the prince) current position is at: (0, 4) Please enter your move: (up:w, down:s, left:a, right:d) s ### ###### # ###### ### # # # # # # P # # # # # ## M # ## ###S #E# Your (the prince) current position is at: (0, 5) Please enter your move: (up:w, down:s, left:a, right:d) w ### ###### # ###### ### # # # # P # # # # # # # ## M # ## ###S #E# Your (the prince) current position is at: (0, 4) Please enter your move: (up:w, down:s, left:a, right:d) d ### ###### # ###### ### # # # # P # # # # # # # ## M # ## ###S #E# . . . . . . Your (the prince) current position is at: (3, 4) Please enter your move: (up:w, down:s, left:a, right:d) s ### ###### # ###### ### # # # # # # #P# # # # ## M# ## ###S #E# Your (the prince) current position is at: (3, 5) Please enter your move: (up:w, down:s, left:a, right:d) s ### ###### # ###### ### # # # # # # # # # # # ## P # ## ###S #E# . . . . . . Your (the prince) current position is at: (5, 6) Please enter your move: (up:w, down:s, left:a, right:d) d ### ###### # ###### ### # # # # # # # # # # # ## P # ## ###S #E# Your (the prince) current position is at: (6, 6) Please enter your move: (up:w, down:s, left:a, right:d) s ### ###### # ###### ### # # # # # # # # # # # ## # ## ###P #E# Your (the prince) current position is at: (6, 7) Please enter your move: (up:w, down:s, left:a, right:d) w ### ###### # ###### ### # # # # # # # # # # # ## P # ## ### #E# . . . . . . Your (the prince) current position is at: (8, 6) Please enter your move: (up:w, down:s, left:a, right:d) d ### ###### # ###### ### # # # # # # # # # # # ## P# ## ### #E# Your (the prince) current position is at: (9, 6) Please enter your move: (up:w, down:s, left:a, right:d) s Amazing! You have completed the maze!
=======================================Skeleton Code==============================
#include <iostream> #include <algorithm> using namespace std; // width and height of the maze const int WIDTH = 11; const int HEIGHT = 8; // Given void print_maze(const char maze[]) { for (int i = 0; i < WIDTH * HEIGHT; i++) { cout << maze[i]; if ((i + 1) % WIDTH == 0) cout << endl; } } // Task 1: find the position of a symbol void find_pos(const char maze[], char symbol, int pos[]) { // TODO } // Task 2: check whether the move is valid or not based on the current position, including // 3 situations: 1) hit the wall 2) goes beyond the maze boundary 3) illegal 'move' character, besides the defined 4 control directions. bool is_valid_move(const char maze[], int pos[], char move) { // TODO } // Task 3: update the position info void update_pos(int pos[], char move) { // TODO } // Task 4: check whether the prince & monster will see each other based on the positions of prince & monster bool check_visible(const char maze[], const int prince_pos[], const int monster_pos[]) { // TODO } // Task 5: To update the position informations, status of prince, monster, weapon & snow white and // update the symbols of the maze // Fill in the three missing parts for this incomplete Function // // status_list[] stores the status of the objects in the game // First element: true if the monster 'M' is alive; otherwise false // Second element: false if the weapon 'W' has not been fetched; otherwise true // Third element: false if the Snow White 'S' has not been reached; otherwise true // Last element: true the prince 'P' is alive; otherwise false void update_maze(char maze[], int prince_pos[], char prince_move, int monster_pos[], char& monster_move, bool status_list[]) { // remove 'P' from the old position maze[prince_pos[1] * WIDTH + prince_pos[0]] = ' '; // update the position info of the prince update_pos(prince_pos, prince_move); // update the status of the weapean if (maze[prince_pos[1] * WIDTH + prince_pos[0]] == 'W') // TODO: // fill one line inside the above if statement to update the status of the weapon // update the status of snow white if (maze[prince_pos[1] * WIDTH + prince_pos[0]] == 'S') // TODO // fill one line inside the above if statement to update the status of the snow white // move prince to the new position maze[prince_pos[1] * WIDTH + prince_pos[0]] = 'P'; // assign 'P' to new position if (status_list[0]){ // if the monster is alive maze[monster_pos[1] * WIDTH + monster_pos[0]] = ' '; // remove 'M' if (is_valid_move(maze, monster_pos, monster_move)) update_pos(monster_pos, monster_move); else { monster_move = (monster_move == 'a') ? 'd': 'a'; update_pos(monster_pos, monster_move); } maze[monster_pos[1] * WIDTH + monster_pos[0]] = 'M'; // assign 'M' to new position bool vis = check_visible(maze, prince_pos, monster_pos); if (vis and (!status_list[1])) // TODO: // fill one line inside the above if statement to update the status of the prince 'P' else if (vis and status_list[1]) { status_list[0] = false; maze[monster_pos[1] * WIDTH + monster_pos[0]] = ' '; // remove 'M' } } } int main() { // initial maze definition char maze[HEIGHT*WIDTH] = {'#', '#', '#', ' ', ' ', '#', '#', '#', '#', '#', '#', '#', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', '#', '#', '#', ' ', '#', '#', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', '#', ' ', ' ', 'W', ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '#', '#', ' ', 'M', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', ' ', '#', '#', '#', 'S', ' ', '#', 'E', '#' }; int prince_pos[2], monster_pos[2], exit_pos[2]; // positions of the prince, monster & exit // {x, y}, x defines column number , y defines row number // e.g. prince_pos[0] stores the column number, while prince_pos[1] stores the row number // find the initial position of the prince, monster & exit find_pos(maze, 'P', prince_pos); find_pos(maze, 'M', monster_pos); find_pos(maze, 'E', exit_pos); cout << "***************************************************************" << endl; cout << "*** Welcome to the maze! Let's start saving our snow white! ***" << endl; cout << "***************************************************************" << endl; cout << "The prince (P) is in {" << prince_pos[0] << ", " << prince_pos[1] << "}" << endl; cout << "The monster (M) is in {" << monster_pos[0] << ", " << monster_pos[1] << "}" << endl; cout << "The exit (E) is in {" << exit_pos[0] << ", " << exit_pos[1] << "}" << endl; char prince_move; char monster_move = 'd'; /* Status_list stores the status of the objects in the game First element: true if the monster 'M' is alive; otherwise false Second element: false if the weapon 'W' has not been fetched; otherwise true Third element: false if the Snow White 'S' has not been reached; otherwise true Last element: true the prince 'P' is alive; otherwise false */ bool status_list[] = {true, false, false, true}; // see comments above do { print_maze(maze); cout << endl; cout << "Your (the prince) current position is at: (" << prince_pos[0] << ", " << prince_pos[1] << ")" << endl; cout << "Please enter your move: (up:w, down:s, left:a, right:d) "; cin >> prince_move; if (is_valid_move(maze, prince_pos, prince_move)) { update_maze(maze, prince_pos, prince_move, monster_pos, monster_move, status_list); if (!status_list[3]){ // prince is alive or not cout << "Game Over! Failed." << endl; return 0; } if (!status_list[2] && !(prince_pos[0] == exit_pos[0] && prince_pos[1] == exit_pos[1])) maze[exit_pos[1] * WIDTH + exit_pos[0]] = 'E'; } else { cout << "Game Over! Failed." << endl; return 0; } } while (!(prince_pos[0] == exit_pos[0] && prince_pos[1] == exit_pos[1]) || !status_list[2]); cout << "Amazing! You have completed the maze!" << endl; return 0; }
Working code implemented in C++ and appropriate comments provided for better understanding.
Source code for main.cpp:
#include <iostream>
#include <algorithm>
using namespace std;
// width and height of the maze
const int WIDTH = 11;
const int HEIGHT = 8;
// Given
void print_maze(const char maze[]) {
for (int i = 0; i < WIDTH * HEIGHT; i++) {
cout << maze[i];
if ((i + 1) % WIDTH == 0)
cout << endl;
}
}
// Task 1: find the position of a symbol
void find_pos(const char maze[], char symbol, int pos[]) {
for (int i = 0; i <= WIDTH * HEIGHT; i++) {
if (maze[i] == symbol) {
pos[0] = i % 11;
pos[1] = i / 11;
break;
}
}
}
// Task 2: check whether the move is valid or not based on the
current position, including
// 3 situations: 1) hit the wall 2) goes beyond the maze boundary
3) illegal 'move' character, besides the defined 4 control
directions.
bool is_valid_move(const char maze[], int pos[], char move) {
switch (move) {
case 'w':
if (pos[1] > 0 && maze[(pos[0] + pos[1] * WIDTH) - 11]
!= '#') {
return true;
}
break;
case 'a':
if (pos[0] > 0 && maze[(pos[0] + pos[1] * WIDTH) - 1] !=
'#') {
return true;
}
break;
case 's':
if (pos[1] < 7 && maze[(pos[0] + pos[1] * WIDTH) + 11]
!= '#') {
return true;
}
break;
case 'd':
if (pos[0] < 10 && maze[(pos[0] + pos[1] * WIDTH) + 1]
!= '#') {
return true;
}
break;
default:
break;
}
return false;
}
// Task 3: update the position info
void update_pos(int pos[], char move) {
switch (move) {
case 'w':
pos[1] -= 1;
break;
case 'a':
pos[0] -= 1;
break;
case 's':
pos[1] += 1;
break;
case 'd':
pos[0] += 1;
break;
default:
break;
}
}
// Task 4: check whether the prince & monster will see each
other based on the positions of prince & monster
bool check_visible(const char maze[], const int prince_pos[], const
int monster_pos[]) {
if (prince_pos[0] != monster_pos[0] && prince_pos[1] !=
monster_pos[1]) {
return false;
}
if (prince_pos[0] == monster_pos[0] - 1 || prince_pos[0] ==
monster_pos[0] + 1) {
return true;
}
if (prince_pos[1] == monster_pos[1] - 1 || prince_pos[1] ==
monster_pos[1] + 1) {
return true;
}
if (prince_pos[0] == monster_pos[0] && prince_pos[1] ==
monster_pos[1]) {
return true;
}
if (prince_pos[0] == monster_pos[0]) {
if (monster_pos[0] >= prince_pos[0]) {
for (int i = (prince_pos[0] + WIDTH * prince_pos[1]); i <=
(monster_pos[0] + WIDTH * monster_pos[1]); i += 11) {
if (maze[i] == '#') {
return false;
}
}
}
else {
for (int i = (prince_pos[0] + WIDTH * prince_pos[1]); i >=
(monster_pos[0] + WIDTH * monster_pos[1]); i -= 11) {
if (maze[i] == '#') {
return false;
}
}
}
}
if (prince_pos[1] == monster_pos[1]) {
if (monster_pos[1] >= prince_pos[1]) {
for (int i = (prince_pos[0] + WIDTH * prince_pos[1]); i <=
(monster_pos[0] + WIDTH * monster_pos[1]); i++) {
if (maze[i] == '#') {
return false;
}
}
}
else {
for (int i = (prince_pos[0] + WIDTH * prince_pos[1]); i >=
(monster_pos[0] + WIDTH * monster_pos[1]); i--) {
if (maze[i] == '#') {
return false;
}
}
}
}
return true;
}
// Task 5: To update the position informations, status of
prince, monster, weapon & snow white and
// update the symbols of the maze
// Fill in the three missing parts for this incomplete
Function
//
// status_list[] stores the status of the objects in the game
// First element: true if the monster 'M' is alive;
otherwise false
// Second element: false if the weapon 'W' has not
been fetched; otherwise true
// Third element: false if the Snow White 'S' has not
been reached; otherwise true
// Last element: true the prince 'P' is alive;
otherwise false
void update_maze(char maze[], int prince_pos[], char prince_move,
int monster_pos[], char& monster_move, bool status_list[])
{
// remove 'P' from the old position
maze[prince_pos[1] * WIDTH + prince_pos[0]] = ' ';
// update the position info of the prince
update_pos(prince_pos, prince_move);
// update the status of the weapean
if (maze[prince_pos[1] * WIDTH + prince_pos[0]] == 'W') {
status_list[1] = true;
}
// update the status of snow white
if (maze[prince_pos[1] * WIDTH + prince_pos[0]] == 'S') {
status_list[2] = true;
}
// move prince to the new position
maze[prince_pos[1] * WIDTH + prince_pos[0]] = 'P'; // assign 'P' to
new position
if (status_list[0]) { // if the monster is alive
maze[monster_pos[1] * WIDTH + monster_pos[0]] = ' '; // remove
'M'
if (is_valid_move(maze, monster_pos, monster_move))
update_pos(monster_pos, monster_move);
else {
monster_move = (monster_move == 'a') ? 'd' : 'a';
update_pos(monster_pos, monster_move);
}
maze[monster_pos[1] * WIDTH + monster_pos[0]] = 'M'; // assign 'M'
to new position
bool vis = check_visible(maze, prince_pos, monster_pos);
if (vis && (!status_list[1])) {
status_list[3] = false;
}
else if (vis && status_list[1]) {
status_list[0] = false;
maze[monster_pos[1] * WIDTH + monster_pos[0]] = ' '; // remove
'M'
}
}
}
int main() {
// initial maze definition
char maze[HEIGHT * WIDTH] = { '#', '#', '#', ' ', ' ', '#', '#',
'#', '#', '#', '#',
'#', 'P', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'#', '#', '#', '#', '#', '#', ' ', '#', '#', '#', ' ',
'#', ' ', '#', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#',
' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', '#', ' ', ' ',
'W', ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
'#', '#', ' ', 'M', ' ', ' ', ' ', ' ', ' ', ' ', '#',
'#', '#', ' ', '#', '#', '#', 'S', ' ', '#', 'E', '#' };
char cheat[] = { 'd', 'd', 'd', 'd', 'd', 's', 's', 'a', 'a',
's', 'a', 'a',
'a', 'a', 's', 'w', 'd', 'd', 'd', 's', 's', 'd', 'd', 'd', 's',
'w', 'd', 'd', 'd', 's' };
int cheat_step = 0;
int prince_pos[2], monster_pos[2], exit_pos[2];
// positions of the prince, monster & exit
// {x, y}, x defines column number , y defines row number
// e.g. prince_pos[0] stores the column number, while prince_pos[1]
stores the row number
// find the initial position of the prince, monster &
exit
find_pos(maze, 'P', prince_pos);
find_pos(maze, 'M', monster_pos);
find_pos(maze, 'E', exit_pos);
cout <<
"***************************************************************"
<< endl;
cout << "*** Welcome to the maze! Let's start saving our snow
white! ***" << endl;
cout <<
"***************************************************************"
<< endl;
cout << "The prince (P) is in {" << prince_pos[0]
<< ", " << prince_pos[1] << "}" <<
endl;
cout << "The monster (M) is in {" << monster_pos[0]
<< ", " << monster_pos[1] << "}" <<
endl;
cout << "The exit (E) is in {" << exit_pos[0] <<
", " << exit_pos[1] << "}" << endl;
char prince_move;
char monster_move = 'd';
/*
Status_list stores the status of the objects in the game
First element: true if the monster 'M' is alive; otherwise
false
Second element: false if the weapon 'W' has not been fetched;
otherwise true
Third element: false if the Snow White 'S' has been reached;
otherwise true
Last element: true the prince 'P' is alive; otherwise false
*/
bool status_list[] = { true, false, false, true }; // see comments
above
do {
print_maze(maze);
cout << endl;
cout << "Your (the prince) current position is at: ("
<< prince_pos[0] << ", " << prince_pos[1]
<< ")" << endl;
cout << "Please enter your move: (up:w, down:s, left:a,
right:d) ";
cin >> prince_move;
if (prince_move == 'c') {
prince_move = cheat[cheat_step];
}
if (is_valid_move(maze, prince_pos, prince_move)) {
update_maze(maze, prince_pos, prince_move, monster_pos,
monster_move, status_list);
if (!status_list[3]) { // prince is alive or not
cout << "Game Over! Failed." << endl;
return 0;
}
if (!status_list[2] && !(prince_pos[0] == exit_pos[0]
&& prince_pos[1] == exit_pos[1]))
maze[exit_pos[1] * WIDTH + exit_pos[0]] = 'E';
}
else {
cout << "Game Over! Failed." << endl;
return 0;
}
cheat_step++;
} while (!(prince_pos[0] == exit_pos[0] && prince_pos[1] ==
exit_pos[1]) || !status_list[2]);
cout << "Amazing! You have completed the maze!" <<
endl;
return 0;
}
Sample Output Screenshots: