Program Specification This project is divided into smaller problems that can be completed one at a time. Complete and thoroughly test each part before going on to the next part. Start with the code...

1 answer below »

Program Specification


This project is divided into smaller problems that can be completed one at a time. Complete and thoroughly test each part before going on to the next part. Start with the code provided in the attached zip file. You will add your code to the
battleship.cpp
and
gameSpecs.h
files. The
enemyAI.h
file contains code I wrote to allow the computer to make semi-intelligent moves when playing against the human. Feel free to look over the AI code, learn how it works, and make changes, but be careful not to introduce any bugs. The AI sinks all the ships in an average of 50 turns, so there is room for improvement.


These instructions are long, but that is because I am giving you a lot of helpful details to make it easier for you. Follow these instructions carefully.


Part 1: Defining Types and Constants


The first step in creating your battleship game is to specify the important values used in the program. All of the code for this part must be placed in the
gameSpecs.h
header file between the
#define ___GAME_SPECS___
and
#endif
lines. This custom header will be included in your cpp file and is also used by the provided
enemyAI.h
header file, so it must follow this specification exactly.



  1. First, we need a new data type to store ship placement and hit/miss information. Create an
    enum
    type named
    Tile
    with the following values
    in the following order:
    WATER,
    AIRCRAFT_CARRIER,
    BATTLESHIP,
    SUBMARINE,
    DESTROYER,
    PATROL_BOAT,
    MISS,
    AIRCRAFT_CARRIER_HIT,
    BATTLESHIP_HIT,
    SUBMARINE_HIT,
    DESTROYER_HIT, and
    PATROL_BOAT_HIT.

  2. Create a constant integer named
    BOARD_LENGTH
    that is set to 10, which is the height and width of each of the game boards.

  3. Create a constant integer array named
    SHIP_SIZE
    where the array values are the sizes of each ship. The values must be ordered so that each index in the array corresponds with the matching
    Tile
    value. For example,
    SHIP_SIZE[AIRCRAFT_CARRIER]
    should equal
    5. Since
    WATER == 0, the first element in the array should just be set to
    0.

  4. Create a function named
    tileToSymbol
    that accepts a
    Tile
    and returns a
    char. Use a switch statement for this function. For every
    Tile
    value representing a ship, the first letter in the ship's name should be returned. The letter should be capital unless the value indicates a "hit". For example, if the value is
    PATROL_BOAT, a
    'P'
    is returned. If the value is
    PATROL_BOAT_HIT, the letter
    'p'
    is returned. For
    WATER
    return
    '.'
    and for
    MISS
    return
    '~'. As a precaution, if the parameter value does not match any of the cases, output an error message to the screen and return a blank space.

  5. Create a function named
    shipToString
    that accepts a
    Tile
    and returns a
    string
    value. In this function, use a
    switch
    statement to return the name of the tile without the word "Hit." For example, a parameter value of
    AIRCRAFT_CARRIER
    or
    AIRCRAFT_CARRIER_HIT
    should return
    "Aircraft Carrier". Also, include return values for
    WATER
    and
    MISS. As a precaution, if none of the
    cases are matched, return
    "Error".


That is everything that should be added to
gameSpecs.h; put the rest of your code in
battleship.cpp. Write some temporary test code in
main()
to make sure everything is written correctly.


Part 2: Displaying the Game Boards


Before we display the game boards, we need to create them. We are going to use 2D arrays to store the location of ships, hits, and misses. Our
Tile
type from the previous part comes in handy here. In the
main
function, create two 2D arrays of the type
Tile
that have
BOARD_LENGTH
columns and rows. One array is the board for the player's fleet and the other is for the computer's fleet.


Create a function called
wipeBoard
that accepts a board (2D array of
Tiles) and a single
Tile
value. You do NOT need to pass the length/size of the array as a parameter, because the function may use the global constant
BOARD_LENGTH
that you defined in Part 1. The function should set all values in the array equal to the value of the second parameter. Give the second parameter a default value of
WATER.


Create a function called
displayBoards
with two parameters: (1) the player's board and (2) the enemy's board. The function displays both the player and enemy boards next to each other as shown in the demo video. The boards should be labeled "Enemy's Fleet" and "Your Fleet". Make sure that the board has the proper row letters and column numbers. Make good use of
setw().


The
displayBoards
function only shows three values on the enemy's board: hit (X), miss (~), and unknown (.). However, on the player's board, it should show the player's fleet along with hits and misses (use the
tileToSymbol
function).


In addition to receiving constant references to the two boards, the function should include a third parameter named
showAll
with a default value of
false. If this value is set to
true
the enemy's board should be displayed just like the player's board (with all the ship locations). This extra option is necessary to show the final boards after the game is finished. It is also helpful for debugging your code.


Add temporary code to
main()
that wipes the boards, changes some tile locations in the boards to be different
Tile
values, and then calls
displayBoards(). After you are confident that everything is working correctly, remove the temporary test code and you are ready for the next part.


Sample Output of displayBoards()

Enemy's Fleet Your Fleet 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 910 A . . . . . . . . . . A . P P . . . . . . . B . . . . . . . . . . B A . . . . . . . . . C . . . . . . . . . . C A . . . . . . . . . D . . . . . . . . . . D A . . . . B B B B . E . . . . . . . . . . E A . . . . . . . . . F . . . . . . . . . . F A . . . . D D D . . G . . . . . . . . . . G . . . . . . . . . . H . . . . . . . . . . H S S S . . . . . . . I . . . . . . . . . . I . . . . . . . . . . J . . . . . . . . . . J . . . . . . . . . .

Part 3: Placing the ships on the Boards


We are going to divide the task of placing the ships on the boards into subtasks.




  1. Create a function called
    placeShipHorizontally
    that adds a ship to one row of the board and has five parameters: (1) the
    Tile
    value for the ship to be placed, (2) the size/length of the ship, (3) the row index to place the ship, (4) the left column index of the ship, and (5) a reference to the 2D board array.


    The function is value returning. Before changing any value on the board, the function first checks that the ship's position is valid. That means that the front-left index is NOT less than (0, 0) and the bottom-right position does not go beyond what can fit on the board. It also should check that there are no ships currently on the board that overlap with the placement of the new ship. If the ship placement is not valid, the function should return
    false.


    If the ship placement is valid, the function should properly set the
    Tile
    values to be the ship's value and return
    true.



  2. Create a function called
    placeShipVertically
    that does the same thing as
    placeShipHorizontally, except it places the ship along one column of the board if the placement is valid.

  3. Make sure to test these two functions using
    displayBoards, before continuing.

  4. Create a function called
    placeShipsRandomly
    that places the ships on 1 of the boards. The function should accept one parameter: a 2D board array. The function should first set all the values of the board to
    WATER
    using
    wipeBoard(). Then, iterate over the Tile values from
    AIRCRAFT_CARRIER
    to
    PATROL_BOAT. For each value, the following should be done until the ship is placed in a valid location on the board.

    1. A random top-left position should be generated. Hint: review Example 5-6 of the textbook to see how to generate random numbers in C++. Also, check out this video:
      Random Numbers in C++

    2. At random, a call to
      placeShipVertically
      or
      placeShipHorizontally
      should be performed with the ship type, random top-left position, and the board.

    3. If the ship placement was unsuccessful (the call to the ship placement function returned
      false), then repeat the previous two steps.


    Hint: A
    do...while
    loop is perfect to handle the repetition until a valid position and orientation is randomly generated.

  5. Create a function named
    placePlayersShips
    that accepts one parameter, the player's board. This function should do the following:

    1. Place all the ships randomly on the board using
      placeShipsRandomly

    2. Call
      displayBoards
      to show the player the current layout of his/her fleet. Hint: you can pass the player's board as both parameters of
      displayBoards, since no shots have been fired yet.

    3. Ask the user
      "Do you want to play with this board? (y/n): ". If the user does not enter until
      y,
      Y,
      n
      or
      N,
      prompt the user to
      "Please enter 'y' or 'n': "
      until they do so. If anything else is entered, ignore everything until a
      '\n'
      is reached before asking again.

    4. Repeat these steps to get a new layout of the player's fleet until the player enters
      'y'
      or
      'Y'.



  6. In
    main(), seed the random number generator using
    srand(), call
    placeShipsRandomly()
    to place ships on the enemy board, and call
    placePlayersShips()
    to place the ships on the player's board. Make sure that
    srand()
    is only called once in your program and that is in
    main()
    (not in another function and not in a loop).


Again, make sure to test your code to make sure it works with a range of inputs before continuing. The more code you have left untested, the harder it becomes to track down bugs when they appear.


Part 4: The Player's Turn


First we need to keep track of how many hits are left on each ship before it sinks. In
main(), create two 1D integer arrays of length 6. Initialize their values to be the same as those in the
SHIP_SIZE
array. One array is for the player's ships and the other is for the enemy's ships. Again, the value at the first index will not be used but allows us to use the
Tile
values as indexes in the array.


Create a function called
playersTurn
that has two parameters: the enemy's board and the array of hits remaining for the enemy's ships. The function should return a
string, which will be a message about the player's turn to be displayed. Create a
do...while
loop that prompts the player to
"Enter the coordinates for your shot (e.g. B2): ". Then read in a character for the row and an integer for the column. Convert these values to indexes (you should allow the user to enter lowercase or uppercase row letters). Make sure the calculated indexes are between 0 and 9 (BOARD_LENGTH - 1). Also, make sure that the user has not fired a shot at these coordinates before. If any of these conditions are not met, output an appropriate error message and ask for a new coordinate.


After validating the input, check the location to see if it is a hit or a miss outside of the loop. If it was a hit, update the appropriate value in the hits-remaining array. The function should only display the prompt and any error message. Instead of displaying the results of the shot in the function, return a message containing the following:



  1. The user's shot coordinates (with a capital row letter). Hint: To concatenate the column number to a
    string, you will first need to convert the number to a
    string
    using
    to_string(colNumber), where
    colNumber
    is an
    int
    variable holding the column number.

  2. If it was a hit or a miss, followed by a newline character

  3. Output the following only if the shot sunk a ship. Append to the message the phrase, " You sunk the enemy's ", followed by the name of the ship (use
    shipToString()), followed by an exclamation point, and finally a newline character.


Test this function by calling it in
main().


Part 5: The Game Loop


The final major step is to put it all together in
main(). After you have placed the ships on the board, create a
do...while
loop that contains the following:



  1. Display the two boards.

  2. Have the player make his/her turn.

  3. Display "Your shot: " followed by the message returned by
    playersTurn()
    in the previous step.

  4. Break out of the loop if the enemy's ships are sunk. I suggest creating a function called
    isAllZeros
    that returns
    true
    if all the values in the 1D array are zero. Then you can use this to check the array of shots remaining per ship. (Don't forget to include the array's length as a parameter for generalizability).

  5. Display the boards again.

  6. Call
    enemyTurn(), which is declared in the
    EnemyAI
    namespace of
    enemyAI.h. Display the "Enemy's shot: " followed by the message returned from
    enemyTurn().


After the loop, print a message indicating if the player won or lost. Then display the boards one last time with all the enemy positions revealed.


Part 6: Simple Animations (Extra Credit)


It is a little difficult to see the results of the player and enemy shots because there are so many changes on the screen. To reduce this problem and make things more visually appealing, do the following:



  • Included in your
    battleship.cpp
    file is a function named
    randomCoordinatesAnimation. Take a look at the comments to see what it does and how it works. Use that function right before you display the enemy's shot coordinates, but after the words, "Enemy's shot: ". Check that your output matches the demo video.

  • Create another
    void
    function called
    displayAsIfTyped
    that will display a message by adding characters to the screen one at a time with a little delay between displaying them. This function makes it look like the output is being typed. The function should accept three parameters: a constant string reference containing the message to be typed out, an integer containing the time in milliseconds to be taken to output the whole message (with a default value of 1000), and the last parameter is how long to pause after typing the whole message (default set to 500, which is a half-second). Hint: use
    randomCoordinatesAnimation()
    as an example. You will need to use
    this_thread::sleep_for()
    and
    chrono::milliseconds()
    to pause between characters.

  • Add extra newline characters to the game loop and possibly display the hit information more than once to "clear" the old output.


Submit all the files required to compile your battleship program.

Answered 3 days AfterNov 28, 2021

Answer To: Program Specification This project is divided into smaller problems that can be completed one at a...

Shashi Kant answered on Dec 01 2021
122 Votes
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here