In: Computer Science
Task
You will write a class called Grid, and test it with a couple of programs. A Grid object will be made up of a grid of positions, numbered with rows and columns. Row and column numbering start at 0, at the top left corner of the grid. A grid object also has a "mover", which can move around to different locations on the grid. Obstacles (which block the mover) and other objects (that can be placed or picked up) are also available. Here is a sample picture of a Grid object in its display format:
0 . . . This is a Grid object with 4 rows and 4 columns (numbered 0 - 3). . . > . The mover '>' is at row 1, column 2, facing east. . . . . The obstacle '#' is at row 3, column 1 . # . . The other item '0' is at row 0, column 0
The @ character indicates that the mover and an item (0) currently occupy the same position on the grid.
Program Details and Requirements
1) Grid class
Download this starter file: grid_starter.h and rename it as grid.h. Your member function prototypes are already given in this file. You will need to add appropriate member data. You will also need to define each of the member functions in the file grid.cpp. You may add whatever member data you need, but you must store the grid itself as a two-dimensional array. Maximum grid size will be 40 rows and 40 columns. (Note that this means dynamic allocation will NOT be needed for this assignment).
Meaning of Grid symbols
. empty spot on the grid 0 an item that can be placed, or picked up # a block (an obstacle). Mover cannot move through it < mover facing WEST > mover facing EAST ^ mover facing NORTH v mover facing SOUTH @ mover occupying same place as item (0)
A printed space ' ' in a grid position represents a spot that the mover has already moved through when the path display is toggled on
public Member function descriptions
You'll need the library cstdlib for the srand and rand functions. While it's not normally the best place to do it, you can go ahead and seed the random number generator here in the constructor in some appropriate way so that it's different for seperate program runs.
If you need a refresher on pseudo-random number generation, see this notes set from COP 3014: http://www.cs.fsu.edu/~myers/c++/notes/rand.html
2) Test Program
Trapped!
Write a main program in a file called trap.cpp that solves the following scenario, using your Grid class:
Giant Mole People have risen from their underground lairs and are taking over the world. You have been taken prisoner and placed in an underground jail cell. Since the Mole People are blind and don't know how to build doors, your cell has one open exit (no door). Since you are deep underground, it is completely dark and you cannot see. Your task is to escape your prison to join the human resistance!
Your program should ask the user to input the number of rows, then columns, for the grid. (Note that this is the ONLY keyboard input for this program). Create a grid with the specified number of rows and columns, using the constructor with two parameters -- (this is the one that should automatically create a fenced-in grid containing one exit and a randomly placed mover). Display the initial grid. Since the placement of the exit and the mover is random, execution of this program will look a little different every time. Your task is to escape the trap! You will need to create an algorithm that will instruct the mover to find its way to the exit. (Hint: Think about how to use the Predicate functions before you move). Upon reaching the exit, you should print a message of success, like "We escaped!", and then output the final position of the mover. Keep the path toggled ON. You only need to display the initial setup grid and the final grid for this program.
General Requirements:
Submit the following files through the web page in the usual manner:
grid.h grid.cpp trap.cpp
// ---------------------------------------
// header file grid.h
// Grid class class Grid { public: // public static class constants, for direction indicators static const int NORTH = 0; static const int WEST = 1; static const int SOUTH = 2; static const int EAST = 3; // public member funcitons Grid(); // build 1 x 1 grid with mover in only // square, facing east Grid(int r, int c); // build grid with r rows, c cols, // blocks around edge with random exit // and random mover position and direction Grid(int r, int c, int mr, int mc, int d); // build empty grid with r rows, c cols, and mover // at row mr, col mc, and facing direction d bool Move(int s); // move forward s spaces, if possible void TogglePath(); // toggle whether or not moved path is shown void TurnLeft(); // turn the mover to the left void PutDown(); // put down an item at the mover's position bool PutDown(int r, int c); // put down an item at (r,c), if possible bool PickUp(); // pick up item at current position bool PlaceBlock(int r, int c); // put a block at (r,c), if possible void Grow(int gr, int gc); // grow the grid by gr rows, gc columns void Display() const; // display the grid on screen // Accessors bool FrontIsClear() const; // check to see if space in front of // mover is clear bool RightIsClear() const; // check to see if space to right of // mover is clear int GetRow() const; // return row of the mover int GetCol() const; // return column of the mover int GetNumRows() const; // return number of rows in the grid int GetNumCols() const; // return number of columns in the grid private: };
grid.cpp
#include<iostream.h>
#include<cstring.h>
#include<iomanip.h>
#include<cstdlib.h>
#include<ctime.h>
#include "grid.h"
Grid::Grid()
// build the grid with mover in only square, facing
east
{
grid = new char* [1];
grid[0] = new char [1];
mover_r = 0;
mover_c = 0;
mover_d = EAST;
path = true;
}
Grid::Grid(int r, int
c)
// build grid with r rows, c cols, blocks around edge with random
exit
// and random mover position and direction
{
if(r < 3 || c < 3)
{
maxRow = 3;
maxCol = 3;
}
else if(r > 40 || c > 40)
{
maxRow = 40;
maxCol = 40;
}
else
{
maxRow = r;
maxCol = c;
}
grid = new char* [maxRow];
for(int i = 0; i < maxRow; i++)
grid[i] = new char [maxCol];
//grid with '#' and '.'
for(int i = 0; i < maxRow; i++)
{
for(int j = 0; j < maxCol;
j++)
{
if(i == 0 || i ==
maxRow-1)
grid[i][j] = '#';
else if(j == 0 ||
j == maxCol-1)
grid[i][j] = '#';
else
grid[i][j] = '.';
}
}
path = true;
srand(time(0));
int r_n = rand() % maxRow,
r_exit = rand() % maxRow,
c_n = rand() % maxCol,
c_exit = rand() % maxCol,
direction = rand() % 4,
edge = rand() % 4;
switch(edge)
{
case NORTH:
grid[0][c_exit] =
' ';
break;
case SOUTH:
grid[maxRow-1][c_exit] = ' ';
break;
case WEST:
grid[r_exit][0] =
' ';
break;
case EAST:
grid[r_exit][maxCol-1] = ' ';
break;
}
//mover placement
mover_r = r_n;
mover_c = c_n;
mover_d = direction;
}
Grid::Grid(int r, int c, int mr, int mc, int d) //make empty grid with r rows, c cols, and mover, at row mr, col mc,
//and facing direction d
{
if(r < 0 || c < 0)
{
maxRow = 1;
maxCol = 1;
}
else if(r > 40 || c > 40)
{
maxRow = 40;
maxCol = 40;
}
else
{
maxRow = r;
maxCol = c;
}
grid = new char* [maxRow];
for(int i = 0; i < maxRow; i++)
grid[i] = new char [maxCol];
path = true;
//set up grid
for(int i = 0; i < maxRow; i++)
for(int j = 0; j < maxCol;
j++)
grid[i][j] =
'.';
if(mr > maxRow)
mr = maxRow-1;
else if(mr < 0)
mr = 0;
if(mc > maxCol)
mc = maxCol-1;
else if(mc < 0)
mc = 0;
mover_r = mr;
mover_c = mc;
mover_d = d;
}
bool Grid::Move(int s) // move forward s spaces, if
possible
{
int temp;
bool flag = false;
switch(mover_d)
{
case NORTH:
if(s > 0)
{
if(mover_r - s >= 0)
{
temp = mover_r;
for(int i = 0; i < s; i++)
{
if( FrontIsClear())
{
flag = true;
if(grid[mover_r][mover_c] != '0')
grid[mover_r][mover_c] = ' ';
mover_r--;
} else flag = false;
}
if(flag == false)
mover_r = temp;
else
return true;
}
}
return
false;
break;
case SOUTH:
if(s > 0)
{
if(mover_r + s <= maxRow)
{
temp = mover_r;
for(int i = 0; i < s; i++)
{
if( FrontIsClear())
{
flag = true;
if(grid[mover_r][mover_c] != '0')
grid[mover_r][mover_c] = ' ';
mover_r++;
} else flag = false;
}
if(flag == false)
mover_r = temp;
else
return true;
}
}
return
false;
break;
case EAST:
if(s >
0)
{
if(mover_c + s <= maxCol)
{
temp = mover_c;
for(int i = 0; i < s; i++)
{
if( FrontIsClear())
{
flag = true;
if(grid[mover_r][mover_c] != '0')
grid[mover_r][mover_c] = ' ';
mover_c++;
} else flag = false;
}
if(flag == false)
mover_c = temp;
else return true;
}
}
return
false;
break;
case WEST:
if(s > 0)
{
if(mover_c - s >= 0)
{
temp = mover_c;
for(int i = 0; i < s; i++)
{
if( FrontIsClear())
{
flag = true;
if(grid[mover_r][mover_c] != '0')
grid[mover_r][mover_c] = ' ';
mover_c--;
} else flag = false;
}
if(flag == false)
mover_c = temp;
else return true;
}
}
return
false;
break;
}
}
void Grid::TogglePath() // toggle whether
or not moved path is shown
{
path = !path;
}
void Grid::TurnLeft()
// turn the mover to the left
{
switch(mover_d)
{
case NORTH:
mover_d =
WEST;
break;
case WEST:
mover_d =
SOUTH;
break;
case SOUTH:
mover_d =
EAST;
break;
case EAST:
mover_d =
NORTH;
break;
}
}
void Grid::PutDown()
// put down an item at the mover's position
{
grid[mover_r][mover_c] = '0';
}
bool Grid::PutDown(int r, int c) // put down an item at (r,c), if
possible
{
if(r < maxRow && c < maxCol &&
grid[r][c] != '#')
{
grid[r][c] = '0';
return true;
}
return false;
}
bool Grid::PickUp() // pick up item at
current position
{
if(grid[mover_r][mover_c] == '0')
{
grid[mover_r][mover_c] = '.';
return true;
}else
return false;
}
bool Grid::PlaceBlock(int r, int c) // put a block at
(r,c), if possible
{
if(r < maxRow && r > 0 && c <
maxCol && c > 0 && grid[r][c] != '#')
{
grid[r][c] = '#';
return true;
}
return false;
}
void Grid::Grow(int gr, int gc) // grow the grid by gr maxRow,
gc columns
{
if(maxRow + gr <= 40)
maxRow += gr;
else
maxRow = 40;
if(maxCol + gc <= 40)
maxCol += gc;
else
maxCol = 40;
char **newGrid = new char * [maxRow];
for(int i = 0; i < maxRow; i++)
newGrid[i] = new char
[maxCol];
for(int i = 0; i < maxRow; i++)
for(int j = 0; j <
maxCol;j++)
newGrid[i][j] = grid[i][j];
for(int i = 0; i < maxRow; i++)
{
for(int j = 0; j <
maxCol; j++)
delete [] &grid[i][j];
delete [] grid[i];
}
delete [] grid;
grid = newGrid;
}
void Grid::Display() const // display the grid on
screen
{
cout << "The Grid:\n";
for(int i = 0; i < maxRow; i++)
{
for(int j = 0; j < maxCol;
j++)
{
if(i == mover_r
&& j == mover_c)
{
if(grid[i][j] == '0')
cout << '@';
else
switch(mover_d)
{
case NORTH:
cout << '^';
break;
case WEST:
cout << '<';
break;
case SOUTH:
cout << 'v';
break;
case EAST:
cout << '>';
break;
}
}
else if(grid[i][j]
== ' ' && path == false)
cout << '.';
else if(path ==
true)
cout << grid[i][j];
cout << "
";
}
cout << endl;
}
}
bool Grid::FrontIsClear() const // check to see if
space in front of mover is clear
{
switch(mover_d)
{
case NORTH:
if(grid[mover_r-1][mover_c] != '#')
return true;
else
return false;
break;
case WEST:
if(grid[mover_r][mover_c-1] != '#')
return true;
else
return false;
break;
case EAST:
if(grid[mover_r][mover_c+1] != '#')
return true;
else
return false;
break;
case SOUTH:
if(grid[mover_r+1][mover_c] != '#')
return true;
else
return false;
break;
}
}
bool Grid::RightIsClear() const
// check to see if space to right of mover is clear
{
switch(mover_d)
{
case NORTH:
if(grid[mover_r][mover_c+1] != '#')
return true;
else
return false;
break;
case WEST:
if(grid[mover_r-1][mover_c] != '#')
return true;
else
return false;
break;
case EAST:
if(grid[mover_r+1][mover_c] != '#')
return true;
else
return false;
break;
case SOUTH:
if(grid[mover_r][mover_c-1] != '#')
return true;
else
return false;
break;
}
}
int Grid:: GetRow() const
// return row of the mover
{
return mover_r;
}
int Grid:: GetCol() const // return
column of the mover
{
return mover_c;
}
int Grid:: GetNumRows()
const
// return number of rows in the grid
{
return maxRow;
}
int Grid:: GetNumCols() const // return number of
columns in the grid
{
return maxCol;
}