0% found this document useful (0 votes)
410 views

Robo Solution

This document contains C++ code that defines classes for simulating robot and player agents in a 2D grid-based arena. The key classes defined are Robot, Player, and Arena. Robot objects can move randomly on the grid. Player objects can assess danger, move, shoot robots, and be killed. The Arena class represents the overall game space and contains methods for adding/removing agents and querying their positions.

Uploaded by

Ram Lohala
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
410 views

Robo Solution

This document contains C++ code that defines classes for simulating robot and player agents in a 2D grid-based arena. The key classes defined are Robot, Player, and Arena. Robot objects can move randomly on the grid. Player objects can assess danger, move, shoot robots, and be killed. The Arena class represents the overall game space and contains methods for adding/removing agents and querying their positions.

Uploaded by

Ram Lohala
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 13

http://www.cs.ucla.edu/classes/winter11/cs32/Projects/1/cs31p7soln.cpp.

txt

// robots.cpp
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
///////////////////////////////////////////////////////////////////////////
// Manifest constants
///////////////////////////////////////////////////////////////////////////
const int MAXROWS = 20; // max number of rows in the arena
const int MAXCOLS = 40; // max number of columns in the arena
const int MAXROBOTS = 200; // max number of robots allowed
const int UP = 0;
const int DOWN = 1;
const int LEFT = 2;
const int RIGHT = 3;
///////////////////////////////////////////////////////////////////////////
// Auxiliary function declarations
///////////////////////////////////////////////////////////////////////////
int decodeDirection(char dir);
void clearScreen();
///////////////////////////////////////////////////////////////////////////
// Type definitions
///////////////////////////////////////////////////////////////////////////
class Arena; // This is needed to let the compiler know that Arena is a
// type name, since it's mentioned in the Robot declaration.
class Robot
{
public:
// Constructor
Robot(Arena* ap, int r, int c);
// Accessors
int row() const;
int col() const;
// Mutators
void move();
private:
Arena* m_arena;
int m_row;
int m_col;
};
class Player
{
public:
// Constructor
Player(Arena *ap, int r, int c);
// Accessors
int row() const;
int col() const;
int age() const;
bool isDead() const;
// Mutators
string takeComputerChosenTurn();
void stand();
void move(int dir);
bool shoot(int dir);
void setDead();
private:
Arena* m_arena;
int m_row;
int m_col;
int m_age;
bool m_dead;
int computeDanger(int r, int c) const;
};
class Arena
{
public:
// Constructor/destructor
Arena(int nRows, int nCols);
~Arena();
// Accessors
int rows() const;
int cols() const;
Player* player() const;
int robotCount() const;
int nRobotsAt(int r, int c) const;
void display(string msg) const;
// Mutators
bool addRobot(int r, int c);
bool addPlayer(int r, int c);
bool destroyRobot(int r, int c);
bool moveRobots();
private:
int m_rows;
int m_cols;
Player* m_player;
Robot* m_robots[MAXROBOTS];
int m_nRobots;
};
class Game
{
public:
// Constructor/destructor
Game(int rows, int cols, int nRobots);
~Game();
// Mutators
void play();
private:
Arena* m_arena;
};
///////////////////////////////////////////////////////////////////////////
// Robot implementation
///////////////////////////////////////////////////////////////////////////
Robot::Robot(Arena* ap, int r, int c)
: m_arena(ap), m_row(r), m_col(c)
{
if (ap == NULL)
{
cout << "***** A robot must be in some Arena!" << endl;
exit(1);
}
if (r < 1 || r > ap->rows() || c < 1 || c > ap->cols())
{
cout << "***** Robot created with invalid coordinates (" << r << ","
<< c << ")!" << endl;
exit(1);
}
}
int Robot::row() const
{
return m_row;
}
int Robot::col() const
{
return m_col;
}
void Robot::move()
{
// Attempt to move in a random direction; if we can't move, don't move
switch (rand() % 4)
{
case UP: if (m_row > 1) m_row--; break;
case DOWN: if (m_row < m_arena->rows()) m_row++; break;
case LEFT: if (m_col > 1) m_col--; break;
case RIGHT: if (m_col < m_arena->cols()) m_col++; break;
}
}
///////////////////////////////////////////////////////////////////////////
// Player implementations
///////////////////////////////////////////////////////////////////////////
Player::Player(Arena* ap, int r, int c)
: m_arena(ap), m_row(r), m_col(c), m_age(0), m_dead(false)
{
if (ap == NULL)
{
cout << "***** The player must be in some Arena!" << endl;
exit(1);
}
if (r < 1 || r > ap->rows() || c < 1 || c > ap->cols())
{
cout << "**** Player created with invalid coordinates (" << r
<< "," << c << ")!" << endl;
exit(1);
}
}
int Player::row() const
{
return m_row;
}
int Player::col() const
{
return m_col;
}
int Player::age() const
{
return m_age;
}
string Player::takeComputerChosenTurn()
{
// How dangerous is it to stand?
int standDanger = computeDanger(m_row, m_col);
// if it's not safe, see if moving is safer
if (standDanger > 0)
{
int bestMoveDanger = standDanger;
int bestMoveDir = UP; // arbitrary initialization
// check the four directions to see if any move is
// better than standing, and if so, record the best
if (m_row > 1)
{
int d = computeDanger(m_row-1, m_col);
if (d < bestMoveDanger)
{
bestMoveDanger = d;
bestMoveDir = UP;
}
}
if (m_row < m_arena->rows())
{
int d = computeDanger(m_row+1, m_col);
if (d < bestMoveDanger)
{
bestMoveDanger = d;
bestMoveDir = DOWN;
}
}
if (m_col > 1)
{
int d = computeDanger(m_row, m_col-1);
if (d < bestMoveDanger)
{
bestMoveDanger = d;
bestMoveDir = LEFT;
}
}
if (m_col < m_arena->cols())
{
int d = computeDanger(m_row, m_col+1);
if (d < bestMoveDanger)
{
bestMoveDanger = d;
bestMoveDir = RIGHT;
}
}
// if moving is better, move
if (bestMoveDanger < standDanger)
{
move(bestMoveDir);
return "Moved.";
}
}
// If we're not going to move, we may as well shoot at the nearest
// robot. Search the four directions at increasing distances for
// a robot.
bool shot = false;
bool shotSuccess;
for (int k = 1; k < m_arena->rows() || k < m_arena->cols(); k++)
{
if (m_row-k >= 1 && m_arena->nRobotsAt(m_row-k, m_col) > 0)
{
shotSuccess = shoot(UP);
shot = true;
break;
}
if (m_row+k <= m_arena->rows() && m_arena->nRobotsAt(m_row+k, m_col) >
0)
{
shotSuccess = shoot(DOWN);
shot = true;
break;
}
if (m_col-k >= 1 && m_arena->nRobotsAt(m_row, m_col-k) > 0)
{
shotSuccess = shoot(LEFT);
shot = true;
break;
}
if (m_col+k <= m_arena->cols() && m_arena->nRobotsAt(m_row, m_col+k) >
0)
{
shotSuccess = shoot(RIGHT);
shot = true;
break;
}
}
if (shot)
{
if (shotSuccess)
return "Shot and hit!";
else
return "Shot and missed!";
}
// No robots to shoot. Just stand, then.
stand();
return "Stood.";
}
void Player::stand()
{
m_age++;
}
void Player::move(int dir)
{
m_age++;
switch (dir)
{
case UP: if (m_row > 1) m_row--; break;
case DOWN: if (m_row < m_arena->rows()) m_row++; break;
case LEFT: if (m_col > 1) m_col--; break;
case RIGHT: if (m_col < m_arena->cols()) m_col++; break;
}
}
bool Player::shoot(int dir)
{
m_age++;
if (rand() % 3 != 0) // miss with 2/3 probability
return false;
// determine row and column delta for the direction
int rDelta = 0;
int cDelta = 0;
switch (dir)
{
case UP: rDelta = -1; break;
case DOWN: rDelta = +1; break;
case LEFT: cDelta = -1; break;
case RIGHT: cDelta = +1; break;
default: return false; // Bad direction!
}
// check along the direction until we find a robot
// or encounter the edge
int r = row();
int c = col();
do
{
if (m_arena->nRobotsAt(r, c) > 0)
{
m_arena->destroyRobot(r, c); // The shot kills one robot.
return true;
}
r += rDelta;
c += cDelta;
} while (r >= 1 && r <= m_arena->rows() &&
c >= 1 && c <= m_arena->cols());
return false;
}
bool Player::isDead() const
{
return m_dead;
}
void Player::setDead()
{
m_dead = true;
}
int Player::computeDanger(int r, int c) const
{
// danger is the number of robots who might move to
// position r,c. Notice that if r,c is at an edge,
// then a robot at that position is dangerous,
// because it might not be able to move off that spot
// at its turn.
int danger = 0;
if (r > 1)
danger += m_arena->nRobotsAt(r-1, c);
else
danger += m_arena->nRobotsAt(r,c);
if (r < m_arena->rows())
danger += m_arena->nRobotsAt(r+1, c);
else
danger += m_arena->nRobotsAt(r,c);
if (c > 1)
danger += m_arena->nRobotsAt(r, c-1);
else
danger += m_arena->nRobotsAt(r,c);
if (c < m_arena->cols())
danger += m_arena->nRobotsAt(r, c+1);
else
danger += m_arena->nRobotsAt(r,c);
return danger;
}
///////////////////////////////////////////////////////////////////////////
// Arena implementations
///////////////////////////////////////////////////////////////////////////
Arena::Arena(int nRows, int nCols)
: m_rows(nRows), m_cols(nCols), m_player(NULL), m_nRobots(0)
{
if (nRows <= 0 || nCols <= 0 || nRows > MAXROWS || nCols > MAXCOLS)
{
cout << "***** Arena created with invalid size " << nRows << " by "
<< nCols << "!" << endl;
exit(1);
}
}
Arena::~Arena()
{
for (int k = 0; k < m_nRobots; k++)
delete m_robots[k];
delete m_player;
}
int Arena::rows() const
{
return m_rows;
}
int Arena::cols() const
{
return m_cols;
}
Player* Arena::player() const
{
return m_player;
}
int Arena::robotCount() const
{
return m_nRobots;
}
int Arena::nRobotsAt(int r, int c) const
{
int count = 0;
for (int k = 0; k < m_nRobots; k++)
{
const Robot* rp = m_robots[k];
if (rp->row() == r && rp->col() == c)
count++;
}
return count;
}
void Arena::display(string msg) const
{
// Position (row,col) in the arena coordinate system is represented in
// the array element grid[row-1][col-1]
char grid[MAXROWS][MAXCOLS];
int r, c;
// Fill the grid with dots
for (r = 0; r < rows(); r++)
for (c = 0; c < cols(); c++)
grid[r][c] = '.';
// Indicate each robot's position
for (int k = 0; k < m_nRobots; k++)
{
const Robot* rp = m_robots[k];
char& gridChar = grid[rp->row()-1][rp->col()-1];
switch (gridChar)
{
case '.': gridChar = 'R'; break;
case 'R': gridChar = '2'; break;
case '9': break;
default: gridChar++; break; // '2' through '8'
}
}
// Indicate player's position
if (m_player != NULL)
{
// Set the char to '@', unless there's also a robot there,
// in which case set it to '*'.
char& gridChar = grid[m_player->row()-1][m_player->col()-1];
if (gridChar == '.')
gridChar = '@';
else
gridChar = '*';
}
// Draw the grid
clearScreen();
for (r = 0; r < rows(); r++)
{
for (c = 0; c < cols(); c++)
cout << grid[r][c];
cout << endl;
}
cout << endl;
// Write message, robot, and player info
cout << endl;
if (msg != "")
cout << msg << endl;
cout << "There are " << robotCount() << " robots remaining." << endl;
if (m_player == NULL)
cout << "There is no player." << endl;
else
{
if (m_player->age() > 0)
cout << "The player has lasted " << m_player->age() << " steps." <<
endl;
if (m_player->isDead())
cout << "The player is dead." << endl;
}
}
bool Arena::addRobot(int r, int c)
{
// Dynamically allocate a new Robot and add it to the arena
if (m_nRobots == MAXROBOTS)
return false;
m_robots[m_nRobots] = new Robot(this, r, c);
m_nRobots++;
return true;
}
bool Arena::addPlayer(int r, int c)
{
// Don't add a player if one already exists
if (m_player != NULL)
return false;
// Dynamically allocate a new Player and add it to the arena
m_player = new Player(this, r, c);
return true;
}
bool Arena::destroyRobot(int r, int c)
{
for (int k = 0; k < m_nRobots; k++)
{
if (m_robots[k]->row() == r && m_robots[k]->col() == c)
{
delete m_robots[k];
m_robots[k] = m_robots[m_nRobots-1];
m_nRobots--;
return true;
}
}
return false;
}
bool Arena::moveRobots()
{
for (int k = 0; k < m_nRobots; k++)
{
Robot* rp = m_robots[k];
rp->move();
if (rp->row() == m_player->row() && rp->col() == m_player->col())
m_player->setDead();
}
// return true if the player is still alive, false otherwise
return ! m_player->isDead();
}
///////////////////////////////////////////////////////////////////////////
// Game implementations
///////////////////////////////////////////////////////////////////////////
Game::Game(int rows, int cols, int nRobots)
{
if (nRobots > MAXROBOTS)
{
cout << "***** Trying to create Game with " << nRobots
<< " robots; only " << MAXROBOTS << " are allowed!" << endl;
exit(1);
}
// Create arena
m_arena = new Arena(rows, cols);
// Add player
int rPlayer = 1 + rand() % rows;
int cPlayer = 1 + rand() % cols;
m_arena->addPlayer(rPlayer, cPlayer);
// Populate with robots
while (nRobots > 0)
{
int r = 1 + rand() % rows;
int c = 1 + rand() % cols;
// Don't put a robot where the player is
if (r == rPlayer && c == cPlayer)
continue;
m_arena->addRobot(r, c);
nRobots--;
}
}
Game::~Game()
{
delete m_arena;
}
void Game::play()
{
Player* p = m_arena->player();
if (p == NULL)
{
m_arena->display("");
return;
}
string msg = "";
do
{
m_arena->display(msg);
msg = "";
cout << endl;
cout << "Move (u/d/l/r/su/sd/sl/sr/c//q): ";
string action;
getline(cin,action);
if (action.size() == 0)
p->stand();
else
{
switch (action[0])
{
default: // if bad move, nobody moves
cout << '\a' << endl; // beep
continue;
case 'q':
return;
case 'c': // computer moves player
msg = p->takeComputerChosenTurn();
break;
case 'u':
case 'd':
case 'l':
case 'r':
p->move(decodeDirection(action[0]));
break;
case 's':
if (action.size() < 2) // if no direction, nobody moves
{
cout << '\a' << endl; // beep
continue;
}
switch (action[1])
{
default: // if bad direction, nobody moves
cout << '\a' << endl; // beep
continue;
case 'u':
case 'd':
case 'l':
case 'r':
if (p->shoot(decodeDirection(action[1])))
msg = "Hit!";
else
msg = "Missed!";
break;
}
break;
}
}
m_arena->moveRobots();
} while ( ! m_arena->player()->isDead() && m_arena->robotCount() > 0);
m_arena->display(msg);
}
///////////////////////////////////////////////////////////////////////////
// Auxiliary function implementations
///////////////////////////////////////////////////////////////////////////
int decodeDirection(char dir)
{
switch (dir)
{
case 'u': return UP;
case 'd': return DOWN;
case 'l': return LEFT;
case 'r': return RIGHT;
}
return -1; // bad argument passed in!
}
#ifdef _MSC_VER // Microsoft Visual C++
#include <windows.h>
void clearScreen()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
DWORD dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
COORD upperLeft = { 0, 0 };
DWORD dwCharsWritten;
FillConsoleOutputCharacter(hConsole, TCHAR(' '), dwConSize, upperLeft,
&dwCharsWritten);
SetConsoleCursorPosition(hConsole, upperLeft);
}
#else // not Microsoft Visual C++, so assume UNIX interface
#include <iostream>
#include <cstdlib>
#include <cstring>
void clearScreen()
{
static const char* term = getenv("TERM");
static const char* ESC_SEQ = "\x1B["; // ANSI Terminal esc seq: ESC [
if (term == NULL || strcmp(term, "dumb") == 0)
cout << endl;
else
cout << ESC_SEQ << "2J" << ESC_SEQ << "H" << flush;
}
#endif
///////////////////////////////////////////////////////////////////////////
// main()
///////////////////////////////////////////////////////////////////////////
int main()
{
// Initialize the random number generator. (You don't need to
// understand how this works.)
srand(static_cast<unsigned int>(time(0)));
// Create a game
// Use this instead to create a mini-game: Game g(3, 3, 2);
Game g(15, 18, 100);
// Play the game
g.play();
}

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy