Battleship

 

This application simulates the board game battleship for a project.

 

Listing:  battleship.cpp

 

// 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;

}

 

Listing: vessel.h

 

// 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

 

Listings:  board.h and board.cpp

 

// 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";

}

 

 

Hosted by www.Geocities.ws

1