Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

We need some help with this problem: Our job is to develop a program that plays

ID: 3767430 • Letter: W

Question

We need some help with this problem:

Our job is to develop a program that plays a game of Battleship. The game is intended to be played between one player and the computer.


Basic Rules for the Game:
The game is played on four grids, two for each player (however, since one of the players is the computer, the computer's two grids are hidden from view). The grids are 10x10 square. The individual squares in the grid are identied by letter and number. On the major grid the player arranges ships and records the shots by the opponent. On the minor grid the player records his/her own shots. Before play begins, each player secretly arranges their ships on their major grid. Each ship occupies a number of consecutive squares on the grid, arranged either horizontally, vertically or diagonally (we will ignore Pythagoras for this project). The number of squares for each ship is determined by the type of the ship. The ships cannot overlap (i.e. only one ship can occupy any given square on the grid). The types and numbers of ships allowed are the same for each player.
Although the player may decide their own ship types and sizes

Ship Type Board Symbol Ship Size
Aircraft Carrier A 5
Battleship B 4
Cruiser C 3
Submarine S 3
Patrol Boat P 2
Kayak K 1
Row boat R 1

Requirements:
In particular, your program should satisfy the following requirements:
1. To begin the game the computer will ask how many ships each side is given, or optionally, provide a le name to read in the information.


2. The ships are represented as variables of type ship and stored as a linked list.
typedef struct ship {
char shiptype [20]; // e.g. Aircraft Carrier ,
int shipsize ; // e.q. 5,
int X Location ; // Dynamically allocated array of length shipsize .
int Y Location ; // Dynamically allocated array of length shipsize .
int X Hit ; // Dynamically allocated array of length shipsize .
int Y Hit ; // Dynamically allocated array of length shipsize .
struct ship pt; // pointer to next ship on the list

} ship ;

3. For each ship added a new node is created in the linked list.

4. The player will be given the option to ll out the structure information at the beginning of the game, or read in the information from a file. The information to be entered is:
ship type
ship size
X-location
Y-location
Other attribute information of your choice.

5. The computer will place the same type, and number of ships, at locations of his own choosing.
Use a random X,Y location for the bow of the ship.
The remaining X,Y values must be in a horizontal, vertical, or diagonal sequence.
No X,Y values of the ship may be off grid. Your program must check for this and not allow players to break this
rule.

6. Ship positions may not overlap.

7. The player is given the first turn to shoot, then the computer takes his turn. The game continues in rounds until all
ships of one contestant are destroyed. The player with at least one surviving ship (i.e. one unhit X,Y location on at
least one ship) is declared the winner.

8. Once the game begins each shot is recorded. Both 10x10 grids for the human player are updated with each shot. When a ship is hit the attributes X hit and Y hit are updated. These attributes are used to update the 10x10 grids during play.
On the minor grid a record of each shot is kept, using different symbols for a hit/miss.
On the major grid a record of the computer's shots are recorded. Again, using different symbols for a hit/miss.

9. The computer will choose his shot locations randomly.

10. After each turn the score is updated and displayed. The scoreboard should display (at a minimum)
Each player's name.
The number of hits each player has scored.
The number of missed attempts for each player.
The number of sunk ships each player has scored.

11. Once a ship is destroyed the node must be removed from the linked list. However, even though the ship is removed from the linked list, the major and minor grids continue to display the results of the sunken ship.

12. Your C program must keep track of both player's information. Thus two linked lists are needed, one for each player.

13. At the end of the game the major grids of both player's are revealed.

Optional Features for Extra Credit:
1. Patterned Search. The computer does not shoot randomly but uses a search pattern to determine his next shot. Upon a hit the computer searches the immediate area until a ship is sunk.

2. Sonar. If a submarine is in the game then a player may choose to use sonar. Upon choosing to ping
A single X,Y location of an enemy ship is shown on the player's major grid using a sonar location symbol 'O'.
This symbol remains on the player's major grid for 1 turn only.
Since using sonar reveals position information, the player using sonar gives up a single X, Y location of his/her submarine.
Sonar does not reveal the orientation of the ships. It merely reveals a single X, Y location per player.
A sunk submarine cannot ping so the option is removed if no submarine is present.
A submarine may ping only once per game.
A ping costs the player 1 turn.
Your C program displays the sonar option only when it is an available choice.

3. Abandon Ship. If a large ship (size 3 or greater) is about to be sunk (i.e. has only one remaining unhit X,Y location)
a player may choose to Abandon Ship. Upon abandoning a ship
The ship with the remaining X,Y location is forfeit/sunk; since an abandoned ship cannot participate in the battle.
As a result of the sunk ship it must be removed from the linked list.
The abandon ship turns into two kayaks. Two Kayak nodes, each of size 1, are added to the player's linked list. The X,Y location of the Kayaks are randomly placed on the player's major grid. If the random position generator chooses an X,Y location that has already been used then that Kayak is auto- matically eliminated. i.e. If the X,Y location is already occupied by another ship, or if the X,Y location has been previously targeted then the Kayak is eliminated. The opponent is informed that a player has used his/her turn to abandon ship.The abandon ship option may only be used once per game.

Your C program displays the abandon ship option only when it is an available choice.

Explanation / Answer

Answer :

battleship.h

#ifndef BATTLESHIP_H
#define BATTLESHIP_H

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>

#define ROWS 10
#define COLS 10

#define NUM_OF_SHIPS 5

#define HORIZONTAL 0
#define VERTICAL 1

#define PLAYER_ONE 0
#define PLAYER_TWO 1


#define WATER '~'
#define HIT '*'
#define MISS 'm'

#define CARRIER 'c'
#define BATTLESHIP 'b'
#define CRUISER 'r'
#define SUBMARINE 's'
#define DESTROYER 'd'

#define NORTH 0
#define SOUTH 1
#define WEST 2
#define EAST 3

typedef enum {
   FALSE, TRUE
} Boolean;

typedef enum {
   CARRIER_L = 5,
   BATTLESHIP_L = 4,
   CRUISER_L = 3,
   SUBMARINE_L = 3,
   DESTROYER_L = 2
} ShipType;

typedef struct watercraft {
   char symbol;
   short length;
   char *name;
} WaterCraft;

typedef struct stats {
   int numHits;
   int numMisses;
   int totalShots;
   double hitMissRatio;
} Stats;

typedef struct coordinate {
   int row;
   int column;
} Coordinate;

typedef struct cell {
   char symbol;
   Coordinate position;
} Cell;

void displayScreen (void);
void startGameBoard (Cell gameBoard[][COLS]);
void displayGameBoard (Cell gameBoard [][COLS], Boolean showPegs);
void keepShipOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship, Coordinate position, int direction);
void manualPlaceShipsOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship[]);
void randomPlaceShipsOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship[]);
void updateGameBoard (Cell gameBoard[][COLS], Coordinate target);
void checkBounds (Boolean cardinals[], int bound, int direction);
void Message (char *message);

Boolean checkSunkedShips (short sunkShip[][NUM_OF_SHIPS], short player, char shipSymbol, FILE *stream);
Boolean isValidLocation (Cell gameBoard[][COLS], Coordinate position, int direction, int length);
Boolean convertStringtoPositionOf Game (Coordinate position[], char *stringPosition, int length);
Boolean isWinner (Stats players[], int player);
Coordinate generatePositionOfGame (int direction, int length);
Coordinate getTargetGame(void);
int getRandomNumber (int lowest, int highest);

short checkShotGame (Cell gameBoard[][COLS], Coordinate target);

#endif

battleship.c

#include "battleship.h"

void displayScreen (void) {
   printf ("XXXXX XXXX XXXXXX XXXXXX XX XXXXXX XXXXX XX XX XX XXXX ");
   printf ("XX XX XX XX XX XX XX XX XX XX XX XX XX XX ");
   printf ("XXXXX XX XX XX XX XX XXXX XXXX XXXXXX XX XXXX ");
   printf ("XX XX XXXXXX XX XX XX XX XX XX XX XX XX ");
   printf ("XXXXX XX XX XX XX XXXXXX XXXXXX XXXXX XX XX XX XX ");
   printf (" ");
   printf ("RULES OF THE GAME: ");
   printf ("1. This is a two player game. ");
   printf ("2. Player 1 is you and Player 2 is the computer. ");
   printf ("3. Player 1 will be prompted if user wants to manually input coordinates ");
   printf (" for the game board or have the computer randomly generate a game board ");
   printf ("4. There are five types of ships to be placed by longest length to the ");
   printf (" shortest; [c] Carrier has 5 cells, [b] Battleship has 4 cells, [r] Cruiser ");
   printf (" has 3 cells, [s] Submarine has 3 cells, [d] Destroyer has 2 cells ");
   printf ("5. The computer randomly selects which player goes first ");
   printf ("6. The game begins as each player tries to guess the location of the ships ");
   printf (" of the opposing player's game board; [*] hit and [m] miss ");
   printf ("7. First player to guess the location of all ships wins ");
}


void startGameBoard (Cell gameBoard[][COLS]) {
   int i = 0, j = 0;

   for (i = 0; i < ROWS; i++)
       for (j = 0; j < COLS; j++) {
           gameBoard[i][j].symbol = WATER;
           gameBoard[i][j].position.row = i;
           gameBoard[i][j].position.column = j;
       }
}


void viewGameBoard (Cell gameBoard [][COLS], Boolean showPegs) {
   int i = 0, j = 0;

   printf (" 0 1 2 3 4 5 6 7 8 9 ");

   for (i = 0; i < ROWS; i++) {
       printf ("%d ", i);

       for (j = 0; j < COLS; j++) {
           if (showPegs == TRUE)
               printf ("%c ", gameBoard [i][j].symbol);
           else {
               switch (gameBoard [i][j].symbol) {
                   case HIT: printf ("%c ", HIT); break;
                   case MISS: printf ("%c ", MISS); break;
                   case WATER:
                   default: printf ("%c ", WATER); break;
               }
           }
       }
      
       putchar (' ');
   }
}


void keepShipOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship,
   Coordinate position, int direction) {
   int i = ship.length - 1;

   for (i = 0; i < ship.length; i++) {
       if (direction == HORIZONTAL)
           gameBoard [position.row][position.column + i].symbol = ship.symbol;
       else
           gameBoard [position.row + i][position.column].symbol = ship.symbol;
   }
}

void manualPlaceShipsOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship[]) {
   char stringPosition[11] = "";
   int i = 0, j = 0;

   Coordinate position[5];
   Boolean isValid = FALSE;

   fflush (stdin);

   for (i = 0; i < NUM_OF_SHIPS; i++) {

       while (TRUE) {
           system ("cls");
           viewGameBoard (gameBoard, TRUE);
           printf ("> Please enter the %d cells to place the %s across (no spaces): ", ship[i].length, ship[i].name);
           printf ("> ");
           scanf ("%s", stringPosition);


           if (convertStringtoPosition (position, stringPosition, ship[i].length)) {

               isValid = TRUE;

               for (j = 0; j < ship[i].length; j++) {

                   if (gameBoard[position[j].row][position[j].column].symbol == WATER) {
                       gameBoard[position[j].row][position[j].column].symbol = ship[i].symbol;
                   } else {
                       isValid = FALSE;
                       printf ("> Invalid input! ");

                       if (j != 0)
                           while (j >= 0) {
                               gameBoard[position[j].row][position[j].column].symbol = WATER;
                               j--;
                           }

                       break;
                   }
               }
           } else {
               isValid = FALSE;
               printf ("> Invalid input! ");
           }

           if (isValid == TRUE) break;
       }

   }
}

void randomPlaceShipsOnGameBoard (Cell gameBoard[][COLS], WaterCraft ship[]) {
   Coordinate position;
   int direction = -1;
   int i = 0;

   for (i = 0; i < NUM_OF_SHIPS; i++) {
       while (TRUE) {
           direction = getRandomNumber (0, 1); /* 0 -> horizontal, 1 -> vertical */
           position = generatePosition (direction, ship[i].length);

           if (isValidLocation (gameBoard, position, direction, ship[i].length)) break;
       }

       keepShipOnGameBoard (gameBoard, ship[i], position, direction);
   }
}


void updateGameBoard (Cell gameBoard[][COLS], Coordinate target) {
   switch (gameBoard[target.row][target.column].symbol) {
      
       case WATER:
           gameBoard[target.row][target.column].symbol = MISS;
           break;

      
       case CARRIER:
       case BATTLESHIP:
       case CRUISER:
       case SUBMARINE:
       case DESTROYER:
           gameBoard[target.row][target.column].symbol = HIT;
           break;

       case HIT:
       case MISS:
       default:
           break;
   }  
}


void checkBounds (Boolean cardinals[], int bound, int direction) {
   switch (direction) {
       case NORTH:
           if (bound < 0)
               cardinals[0] = FALSE;
           else
               cardinals[0] = TRUE;
           break;

       case SOUTH:
           if (bound > 9)
               cardinals[1] = FALSE;
           else
               cardinals[1] = TRUE;
           break;

       case WEST:
           if (bound < 0)
               cardinals[2] = FALSE;
           else
               cardinals[2] = TRUE;
           break;

       case EAST:
           if (bound > 9)
               cardinals[3] = FALSE;
           else
               cardinals[3] = TRUE;  
           break;
   }
}

void Message (char *message) {
   char ch = '';

   do {
       printf ("%s", message);
   } while ((ch = getch()) != ' ');
}

Boolean checkSunkedShips (short sunkShip[][NUM_OF_SHIPS], short player, char shipSymbol, FILE *stream) {
   Boolean sunked = FALSE;

   switch (shipSymbol) {
       case CARRIER:
           if (--sunkShip[player][0] == 0) {
               printf ("> Player %d's Carrier sunked! ", player + 1);

              
               fprintf (stream, "Player %d's Carrier sunked! ", player + 1);

               sunked = TRUE;
           }
           break;

       case BATTLESHIP:
           if (--sunkShip[player][1] == 0) {
               printf ("> Player %d's Battleship sunked! ", player + 1);

              
               fprintf (stream, "Player %d's Battleship sunked! ", player + 1);

               sunked = TRUE;
           }
           break;

       case CRUISER:
           if (--sunkShip[player][2] == 0) {
               printf ("> Player %d's Cruiser sunked! ", player + 1);

              
               fprintf (stream, "Player %d's Cruiser sunked! ", player + 1);

               sunked = TRUE;
           }
           break;

       case SUBMARINE:
           if (--sunkShip[player][3] == 0) {
               printf ("> Player %d's Submarine sunked! ", player + 1);

              
               fprintf (stream, "Player %d's Submarine sunked! ", player + 1);

               sunked = TRUE;
           }
           break;

       case DESTROYER:
           if (--sunkShip[player][4] == 0) {
               printf ("> Player %d's Destroyer sunked! ", player + 1);

      
               fprintf (stream, "Player %d's Destroyer sunked! ", player + 1);

               sunked = TRUE;
           }
           break;
   }

   return sunked;
}

Boolean isValidLocation (Cell gameBoard[][COLS], Coordinate position,
               int direction, int length) {
   int i = length - 1;
   Boolean isValid = TRUE;

   for (i = 0; isValid && i < length; i++) {
       if (direction == HORIZONTAL) {
           if (gameBoard [position.row][position.column + i].symbol != WATER &&
               (position.column + i) < COLS)
               isValid = FALSE;
       } else {
           if (gameBoard [position.row + i][position.column].symbol != WATER &&
               (position.row + i) < ROWS)
               isValid = FALSE;
       }
   }

   return isValid;
}

Boolean convertStringtoPositionOfGame (Coordinate position[], char *stringPosition, int length) {
   Boolean flag = TRUE;
   char temp = '';
   int i = 0, j = 0, k = 1;

  
   if (strlen (stringPosition)/2 == length) {
      
       for (i = 0; i < length && flag; i++) {
          
           if (isdigit (stringPosition[j]) && isdigit (stringPosition[k])) {
               position[i].row = stringPosition[j] - '0';
               position[i].column = stringPosition[k] - '0';

               j += 2;
               k += 2;
           } else {
               flag = FALSE;
           }
       }
   } else {
       flag = FALSE;
   }

   return flag;
}

Boolean isWinner (Stats players[], int player) {
   Boolean isWin = FALSE;

   if (players[player].numHits == 17)
       isWin = TRUE;

   return isWin;
}

Coordinate generateGamePosition (int direction, int length) {
   Coordinate position;

   if (direction == HORIZONTAL) {
       position.row = getRandomNumber (0, ROWS);
       position.column = getRandomNumber (0, COLS - length);
   } else {
       position.row = getRandomNumber (0, ROWS - length);
       position.column = getRandomNumber (0, COLS);
   }

   return position;
}

Coordinate getTargetOf Game (void) {
   Coordinate target;

   fflush (stdin);

   printf ("> Enter Target (ex. > 3 4): ");
   printf ("> ");
   scanf ("%d %d", &target.row, &target.column);

   return target;
}
int getRandomNumber (int lowest, int highest) {
   if (lowest == 0)
       return rand () % ++highest;
  
   if (lowest > 0)
       return rand () % ++highest + lowest;
}


short checkGameShot (Cell gameBoard[][COLS], Coordinate target) {
   int hit = -2;

   switch (gameBoard[target.row][target.column].symbol) {
      
       case WATER:
           hit = 0;
           break;

      
       case CARRIER:
       case BATTLESHIP:
       case CRUISER:
       case SUBMARINE:
       case DESTROYER:
           hit = 1;
           break;

       case HIT:
       case MISS:
       default:
           hit = -1;
           break;
   }  

   return hit;
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote