This application simulates the board game battleship for a project.
// battleship.cpp : Defines the entry point for the console application.
// Battleship
// by Richard McGuire based on the board game.
#include
"board.h"
#include
<iostream>
using namespace
std;
bool game_over(Board&
player, Board& cpu){
return(player.fleet_sunk() || cpu.fleet_sunk());
}
int main( /* int argc,
char* argv[] */ ){
enum {CPU, ME};
Board cpu(CPU);
Board player(ME);
cout
<< "Battleship!\n";
cout
<< "Computer setting board, Please wait...\n";
cpu.set_grid();
player.set_grid();
while
(!game_over(player,cpu)){
player.show_grid();
cpu.show_grid();
cpu.attacked(cpu.targeted());
player.attacked(player.targeted());
}
player.show_grid();
cpu.show_grid();
if
(cpu.fleet_sunk())
cout << "*** You win!!! ***\n";
else
cout << "*** Your fleet
was sunk!! ***\n";
return
0;
}
// vessel.h
// Classes for battleship game representing the five types of
ships derived from class Vessel.
#ifndef _VESSEL_H_
#define
_VESSEL_H_
class Vessel{
public:
Vessel(char* ship_type =
"ship", unsigned int ship_length = 2,
unsigned int start_hits
= 0) :
_type(ship_type),
_length(ship_length),
_hits(start_hits) {}
virtual
bool is_sunk() { return(_hits ==
_length);}
virtual
void is_hit() {++
_hits;}
virtual
int hits_taken() {return
_hits;}
virtual
int length() {return _length;}
virtual
char* type() {return
_type;}
private:
unsigned
int _hits;
unsigned
int _length;
char*
_type;
};
class Carrier : public Vessel{
public:
Carrier() :
Vessel("carrier",5) {}
};
class Battleship : public Vessel{
public:
Battleship() :
Vessel("battleship",4) {}
};
class Frigate : public Vessel{
public:
Frigate() :
Vessel("frigate",3) {}
};
class Submarine : public Vessel{
public:
Submarine() :
Vessel("submarine",3) {}
};
class Destroyer : public Vessel{
public:
Destroyer() :
Vessel("destroyer",2) {}
};
#endif
// board.h
// Board for battleship game containing a fleet vetor of ships and a grid.
#ifndef _BOARD_H_
#define
_BOARD_H_
#include
"vessel.h"
#include
<vector>
#include
<algorithm>
using namespace
std;
class Board{
public:
enum {a_carrier,
a_battleship, a_frigate, a_sub, a_destroyer};
enum {GRID_SIZE = 100};
enum {GRID_DIMENSION = 10};
Board(bool is_player)
: player_grid(is_player){
fleet.push_back(carrier);
fleet.push_back(battleship);
fleet.push_back(frigate);
fleet.push_back(submarine);
fleet.push_back(destroyer);
}
bool already_shot(int target){ return(grid[target] == '*' || grid[target] == 'x');}
bool target_grid()
{return(!player_grid);}
void
clear_grid();
void
set_grid();
void
show_grid();
int targeted();
void
attacked(int target);
void
hit(int target, int ship);
void
missed(int target);
void
show_status(int ship);
bool fleet_sunk();
int get_coordinates();
bool will_fit(Vessel*
ship, int placement, int direction);
void
place(Vessel* ship, int
placement, int
direction);
private:
// true if
players grid, false if the CPU's grid.
bool player_grid;
// Note: I
thought about refactoring this into it's own class Grid containing the vector grid and the bool player grid.
char
grid[GRID_SIZE];
vector<Vessel>
fleet;
Carrier carrier;
Battleship battleship;
Frigate frigate;
Submarine submarine;
Destroyer destroyer;
};
#endif
//
methods for class Board.
#include
<vector>
#include
<algorithm>
#include
<iostream>
#include
<ctime>
#include
"board.h"
using namespace
std;
void Board::clear_grid(){
fill(grid, grid +
GRID_SIZE, ' ');
}
int Board::get_coordinates(){
char
letter;
int number;
bool good_coordinates
= false;
while(!good_coordinates){
try{
cout << "Enter Coordinates letter first
(ex. 'b3'): ";
cin >> letter;
cin >> number;
if (strchr( "abcdefghij", letter) == NULL)
throw "1st coordinate must be a letter
a-j\n";
if (number < 0 || number > 9)
throw "2nd coordinate must be
0-9\n";
good_coordinates
= true;
}
catch (const char* error){
cout << error;
}
}
return
((letter - 'a') * GRID_DIMENSION + number);
}
void Board::set_grid(){
int placement;
int direction;
clear_grid();
if
(player_grid) show_grid();
vector<Vessel>::iterator ship = fleet.begin();
while
(ship != fleet.end()){
if (player_grid){
cout <<
"Place your " << ship->type();
cout << "( length = " <<
ship->length() << " )\n";
placement
= get_coordinates();
}
// CPU
random placement
else{
srand(time(NULL));
placement
= rand() % (GRID_SIZE - 1);
}
if (player_grid){
cout << "Enter a direction to face (0 UP,
1 LEFT): ";
cin >> direction;
while (direction <0 || direction > 1){
cout << "Enter 0 for UP, 1 for LEFT:
";
cin >> direction;
}
}
else
direction
= rand() % 2;
if (will_fit(ship,
placement, direction)){
place(ship,
placement, direction);
++ship;
}
else{
if(player_grid)
cout << "\n*** The
"<<ship->type()<<" won't fit there! ***\n";
}
if
(player_grid) show_grid();
}
}
bool Board::will_fit(Vessel*
ship, int placement, int left){
bool fit;
// See if it
will fit in the dimensions of the grid
if
(left){
if ((placement % GRID_DIMENSION) -
ship->length() < -1)
fit =
false;
}
else{
if ((placement / GRID_DIMENSION) -
ship->length() < -1)
fit =
false;
}
// Now see if
any ships are in the way
if
(fit){
for(int index = 0; index < ship->length(); ++index){
if (grid[placement] != ' ')
return false;
if (left)
placement
-= 1;
else
placement
-= 10;
}
}
return(fit);
}
void Board::place(Vessel*
ship, int placement, int left){
for(int index = 0; index <
ship->length(); ++index){
// put
first letter in ship name in the grid to note ship's position
grid[placement]
= ship->type()[0];
if (left)
placement
-= 1;
else
placement
-= 10;
}
}
void Board::show_grid(){
int coordinate;
if
(player_grid)
cout << " Your Fleet\n";
else
cout << "
Target Screen\n";
cout
<< " 0 1 2 3 4 5 6 7 8
9\n";
for(int row=0; row <
GRID_DIMENSION; ++row){
cout << (char)('a'
+ row) << " ";
for(int column=0; column < GRID_DIMENSION; ++column){
coordinate
= row * GRID_DIMENSION + column;
if(player_grid)
cout << grid[coordinate] << "
";
else
//
keep ships hidden in target screen
if (strchr("x
*",grid[coordinate]) == NULL)
cout << " ";
else
cout << grid[coordinate] << "
";
}
cout << '\n';
}
}
int Board::targeted(){
int target = -1;
while
(target < 0){
if (target_grid())
target
= get_coordinates();
else{
target
= rand() % 99;
cout << "Computer fires at "<<
(char)((target / GRID_DIMENSION) + 'a')
<< target % GRID_DIMENSION << "...";
}
if (already_shot(target)){
if (target_grid()) cout << "You have already fired at that
target!\n";
target
= -1;
}
}
return
target;
}
void Board::attacked(int target){
int ship;
switch(grid[target]){
case 'c':
ship
= a_carrier;
break;
case 'b':
ship
= a_battleship;
break;
case 'f':
ship
= a_frigate;
break;
case 's':
ship
= a_sub;
break;
case 'd':
ship
= a_destroyer;
break;
default:
missed(target);
}
hit(target,ship);
}
bool Board::fleet_sunk(){
vector<Vessel>::iterator ship = fleet.begin();
while
(ship != fleet.end()){
if (!ship->is_sunk())
return false;
++ship;
}
return
true;
}
void Board::hit(int target, int ship){
if
(grid[target] != 'x'){
grid[target]
= '*';
fleet[ship].is_hit();
show_status(ship);
}
}
void Board::missed(int target){
cout<<
"*** Missed!! ***\n";
grid[target] =
'x';
}
void Board::show_status(int ship){
if
(fleet[ship].is_sunk())
cout<< "*** The " <<
fleet[ship].type() << " is sunk!!! ***\n";
else
cout<< "*** Hit scored!! ***\n";
}