Create a console-based Battleship game in C++ with:
- A Ship base class and five derived classes (Carrier, Battleship, Cruiser, Submarine, Destroyer).
- A Grid class for managing a 10×10 layout of cells (ship placement, hits, misses).
- A Player base class and two derived classes: HumanPlayer and AiPlayer.
- Turn-by-turn gameplay until one player’s entire fleet (all five ships) is sunk.
- Display each player’s board after every move to show updated hits and misses.
- Members
char* name;
int size;
int hitsTaken;
- Functions
Ship(const char* shipName, int shipSize);
Initializesname
andsize
.virtual ~Ship();
Cleans up allocated memory forname
.virtual void takeHit();
IncrementshitsTaken
and prints"<ShipName> got hit!"
.
Checks ifhitsTaken >= size
.bool isSunk() const;
Returns true ifhitsTaken >= size
.
Each calls the base Ship
constructor with a unique name and size:
- Carrier (size = 5)
- Battleship (size = 4)
- Cruiser (size = 3)
- Submarine (size = 3)
- Destroyer (size = 2)
- Purpose: Manages a 10×10 layout of cells for placing ships and marking hits or misses.
- Members
char cells[10][10];
For instance,'~'
for empty,'S'
for ship,'X'
for hit,'M'
for miss.
- Functions
Grid();
Initializescells
(e.g., set all to'~'
).bool isTileOccupied(int row, int col) const;
Returns true if the cell indicates a ship or a previously hit cell.bool inBounds(int row, int col, int shipSize, bool horizontal) const;
Checks if placing a ship of lengthshipSize
at(row, col)
horizontally/vertically stays within the 10×10 grid.void placeShip(int row, int col, int shipSize, bool horizontal, char symbol);
Marks each relevant cell withsymbol
(e.g.,'S'
) if valid.void markHit(int row, int col);
Markscells[row][col]
as'X'
.void markMiss(int row, int col);
Markscells[row][col]
as'M'
.char getCell(int row, int col) const;
Returnscells[row][col]
.- Optional: A function such as
printGrid()
to display the current state ofcells
.
- Members
char* playerName;
Ship* ships[5];
(five pointers to the different derived Ships)Grid grid;
(a 10×10 grid)
- Functions
Player(const char* name);
InitializesplayerName
and constructsgrid
.virtual ~Player();
Cleans upplayerName
andShip
pointers.virtual void placeAllShips();
Must place the five ships ontogrid
.- For each ship, choose
(row, col)
and orientation. - Check
grid.inBounds(...)
andgrid.isTileOccupied(...)
. - If valid, use
grid.placeShip(...)
; otherwise retry.
- For each ship, choose
virtual void makeMove(Player* opponent);
Chooses(row, col)
to attack onopponent->grid
.- If
opponent->grid.getCell(...)
is a ship, find the correctShip
, calltakeHit()
, thenopponent->grid.markHit(...)
. - Otherwise
opponent->grid.markMiss(...)
. - After the attack, print both players’ grids so you can see updated hits/misses.
- If
bool allShipsSunk() const;
Returns true if all five ships are sunk.- Optional:
void displayMyGrid()
orvoid displayGrid()
to print the grid to the console.
- Overrides
void placeAllShips();
- Prompts user for
(row, col)
and orientation for each of the five ships. - Uses
grid.inBounds(...)
andgrid.isTileOccupied(...)
to validate. - Calls
grid.placeShip(...)
if valid.
- Prompts user for
void makeMove(Player* opponent);
- Prompts user for
(row, col)
to attack. - Checks
opponent->grid.getCell(...)
to see if it’s a ship. - Calls the relevant
Ship
’stakeHit()
, marks hits or misses, and prints the grids.
- Prompts user for
- Overrides
void placeAllShips();
- Automatically chooses
(row, col)
and orientation (random or pattern). - Uses
grid.inBounds(...)
andgrid.isTileOccupied(...)
to ensure validity. - Calls
grid.placeShip(...)
if valid; otherwise tries again.
- Automatically chooses
void makeMove(Player* opponent);
- Automatically picks
(row, col)
(random or pattern). - Checks
opponent->grid.getCell(...)
. - Calls the correct
Ship
’stakeHit()
, marks a hit/miss, prints both grids afterward.
- Automatically picks
- Helper
int AiPlayer::getRandomCoordinate() {
// Ensure srand(...) is called in main
return std::rand() % 10;
}
(Remember to call std::srand(std::time(nullptr))
once in main
.)
- Members
Player* player1;
Player* player2;
- Functions
Game(Player* p1, Player* p2);
Assigns two player objects (e.g.,HumanPlayer
vs.AiPlayer
).void setup();
Callsplayer1->placeAllShips();
, thenplayer2->placeAllShips();
.void start();
- Loop until one side is fully sunk:
player1->makeMove(player2);
- Check
player2->allShipsSunk()
. player2->makeMove(player1);
- Check
player1->allShipsSunk()
.
- Announce the winner when a fleet is sunk.
- Loop until one side is fully sunk:
bool isGameOver() const;
Returns true ifplayer1->allShipsSunk()
orplayer2->allShipsSunk()
.
- Implement Ship Hierarchy
- Base
Ship
+ five derived classes (Carrier, Battleship, Cruiser, Submarine, Destroyer). takeHit()
prints"<ShipName> got hit!"
and incrementshitsTaken
.
- Implement Grid
- 10×10
cells
. isTileOccupied
,inBounds
,placeShip
,markHit
,markMiss
, etc.
- Implement Player Classes
HumanPlayer
for user input on ship placement and attacks.AiPlayer
automates those steps.- Validate placement and record hits/misses.
- Always print both players’ grids after each move.
- Implement Game
- Create two
Player
objects (e.g.,HumanPlayer
,AiPlayer
) inmain()
. setup()
places ships.start()
loops until a fleet is sunk, printing results along the way.
- Test Thoroughly
- Check that ships cannot overlap or exceed grid boundaries.
- Verify hits, misses, and correct sinking behavior.
- Confirm final winner is announced correctly.
- Header & Source Files
- For
Ship
(base + derived),Grid
,Player
(base + derived), andGame
, plus amain.cpp
.
- Working Program
- Must compile and run, showing a complete session.
- Print boards after each attack to track progress.
- Memory Management
- Properly
delete
dynamic allocations (names, ship pointers, etc.) to avoid leaks.