Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit



PA 6 - Battleship

In this programming assignment, you are asked to implement components of the game battleship. This assignment is designed to help you practice concepts related to structs and dynamic memory allocation.

In addition, the formulation of this assignment is also more open-ended, where the functionality of the program is specified but you must decide for yourself what data structures you want to use. This is done to give you the feel of a real software project, albeit a small one.

 

Summary

If you are unfamiliar with the game Battleship, you can read about the rules or play an online version. For this assignment, you will have to implement a partial game: the positions of the ships are read from a file (e.g., they could have been entered by someone else) and then the user has to try to sink all the ships.

The setup is described in General Instructions, with the details discussed in Assignment Details. Unlike other assignments, there is no breakdown into functions that are tested separately. Instead, your solution is evaluated as a whole. As a result, there is also no strict grading breakdown. Instead, a large number of test inputs is used and each test case touches upon all functionalities. The table below summarizes the key building blocks of your program and roughly their relative grading weight. Note however that if the first parts do not work properly, it will be impossible to test later ones. As such, the relative importance of the first four building blocks is greater than the grading weights alone would suggest.

 

  Building Block 1 - Reading in the ship information

approx.

60 pts

 Building Block 2 - Getting the ship placements

 Building Block 3 - Getting the coordinates for the shots

 Building Block 4 - Detecting when a ship is hit

 Building Block 5 - Detecting when a ship is sunk

approx.

40 pts     

 

General Instructions

Basics

The goal is to build a partial battleship game. In this partial game, the positions of ships are read from a file. The example on the right shows a game board of 6 rows and 8 columns with three ships (of length 1, 2 and 4) in valid positions. In our game, ships can touch, but not overlap. The user is then asked repeatedly to enter the coordinates of a shot. The program needs to figure out if this was a miss or if one of the ships was hit, and print the appropriate messages. Coordinates are as labeled in the figure, starting at (0,0) in the bottom-left corner. For example, the ship of length 1 (the one in red) is at (x,y)-coordinate (2,4).

More details about exactly what you need to implement will be provided in Assignment Details.

 

Starter Code

To get the starter code, execute the following command in your home directory:

$ getStarter PA6

This will create a new subdirectory, called “PA6”, containing the files that are described below.

 

bship.h

We have already implemented several helper functions for you and put them in a library. You can find the function declarations in the header file bship.h, together with a description of what each function does. You do NOT need to implement these helper functions yourself. Instead, you need to call these functions in the program that you are asked to create. We will refer to these functions as needed when detailing the deliverables for your program in Assignment Details. The helper function implementations themselves are hidden from you; they are in the helper.o file, which is also part of your starter code but it is in a binary (i.e., non-readable) format.

In bship.h, you also find the following constants: ROWS, COLUMNS and FLEETSIZE. Their meaning is explained in the comments. We will not change the values of these constants. Nevertheless, you should use these constants rather than their numerical values to make your code more readable.

Finally, the header file also contains the definitions of three structs: Ship, Coordinate and Placement. The comments explain the meaning of each of the fields inside those structs.

You should not make any changes to the bship.h header file.

 

bship.c

This file is currently empty. It is where you need to write your code, including the main(). You can create helper functions, define additional constants and data structures, and include libraries. However, there are a few restrictions.

● You cannot use any string libraries.

● You cannot use global variables

Make sure you include the “bship.h” library.

 

bship_demo

This executable is a demo of what your completed assignment should look like. It also helps you answer questions like “what happens if …”; you can just try it out (so please, do this first before asking us!). Read the entire assignment before you run the demo, so you understand what it is supposed to do.

To execute the demo program, type the command:

./bship_demo

It demonstrates what your code should do, as explained in Assignment Details.

 

The demo program also has the option to show the ship information and the state of the board, to help you visualize what is going on. To see this, you need to run the demo program in a special mode with the command:

./bship_demo -S

This is only done to help you visualize the behavior. Run the demo in this mode first to get a good idea of what the program does. However, it is not something you should implement. You could consider printing similar information in your program to help you with debugging. However, make sure that you delete or comment out these print statements when you submit your assignment.

 

Compiling Your Code

To compile your code, compile bship.c together with helper.o. If you don’t remember how to do this, check out Appendix B. Compiling Code.

Assignment Details

Overview

This programming assignment is structured slightly differently from previous ones. Rather than explicitly specifying functions that you need to write, we only describe the overall functionality of the program, i.e., what it should be able to do. It is up to you to decide how to structure your code to accomplish this overall functionality (BTW, there is more than one way to do this). Consequently, the file bship.c is completely empty. The only thing we have specified is some of the data structures and helper functions in bship.h and helper.o to interface with the user and eventually our grading program (see Starter Code earlier).

To describe the functionality that you need to implement, we will break it down into a set of building blocks, which will be discussed next. This will also contain all the details of what interface functions to use from the ones listed in bship.h.

To solidify your understanding of what you are asked to build, check out the bship_demo that is included in the starter code. It shows exactly what your code needs to do. If any of the descriptions of the building blocks are unclear, just see what the demo program does. This should answer most of your questions.

 

Read through the entire set of building blocks first before starting to code. Knowing the complete functionality is essential in figuring out what data structures to use and how to organize your code. For example, we don’t tell you how to represent the board or keep track of the information. That is something you must decide. Take some time to plan your approach before you start! Also, make sure you build your program step-by-step and debug it as you go. As always, use divide-and-conquer and top-down modular design when developing your solution.

 

For grading your work, we will run your code for various test cases, which includes different ships (although FLEETSIZE will always be 3), ship placements and shots entered by the user. Because the building blocks are interdependent, it is difficult to separate the point values and our test cases will test several functionalities at the same time. It is therefore crucial to get at least the most basic elements of the assignment correct, as it impacts our ability to test any other functionalities that are built on top of it. The best thing to do is to verify that your code behaves as the demo program does.

As always, your code needs to compile correctly for it to be graded. We have created a test program so you can verify that your code works with our grading scripts. This is detailed in Testing your Code.

Building Block 1 - Reading in the ship information

First you need to retrieve the information about the names and sizes of the different ships that are used in the game. This information is in the file ship_info.txt. You can view/modify this file in your text editor to test out different values.

This file contains a line for each ship, with data about that ship. There will alway be exactly FLEETSIZE number of ships in this ship_info.txt file, without any duplicates. The data provided for each ship is, in this order: the ship index (an integer number from 0 to FLEETSIZE-1, see explanation below), the ship name (a valid string; the name is never more than 19 characters long) and the ship length (a positive integer).

We have created a function initialize_ships()that reads the information from this file and places it in an array of type Ship. Each element of this array contains the information for the corresponding ship in the file. The ship index (i.e., the first column in ship_info.txt) specifies the index in this array where the info for that ship will be placed. Remember, there are always exactly FLEETSIZE ships.

The initialize_ships() function is implemented in helper.o. This means that you don’t need to implement this function yourself. Its prototype is defined in bship.h. You just need to call this function properly in your code: pass in an array of type Ship (of size FLEETSIZE) and the function will fill this array with the information of the different ships as found in the ship_info.txt file. Once you call the function correctly, you can print out the content of the Ship data structure and confirm how this relates to the information in the file.

Note that for grading, we may change the information in the ship_info.txt file, to ships with different names and different sizes. However, there will always be exactly FLEETSIZE ships listed.

 

Building Block 2 - Getting the ship placements

Next, you need to read where to place the ships on the game board. This information is stored in the file ship_placement.txt, which contains a line for each ship that needs to be placed on the board. Each line has the following information for a ship: the ship index, orientation, and x and y coordinate.

●  ship_index: The index of the ship in the array of ships from Building Block 1 - Reading in the ship information and thus an integer between 0 and FLEETSIZE-1.

● orientation: Either H for horizontal or V for vertical.

● x and y: The x- and y-coordinates of the bottom-left corner of the ship (the bottom or left corner of the ship, depending on whether its orientation is vertical or horizontal).

From the example in Basics, to place the green ship (assuming it is at index 1 in the array, i.e., it had a ship index of 1 in the ship_info.txt file), the line in ship_placement.txt would be: 1 H 3 2

Each ship is placed at most once, which means that there are at most FLEETSIZE lines in the file. It is possible, however, that only a subset of all the ships is listed, which means that not all ships need to be placed on the board. Also, the order in which the ships are listed in ship_placement.txt does not need to be the same as the one in the ships_info.txt. Again, you can view/modify the ship placement file in your text editor to test out different placements.

To read the data from ship_placement.txt file into your program, you need to use the function get_placement_one_ship(). This function is also part of the library we created for you (i.e., it is  implemented in helper.o and its prototype is specified in bship.h). The function get_placement_one_ship() only provides the placement information of a single ship at a time. Each time you call it, it returns the information of the next ship in the file. You therefore need to call it multiple times to place all the ships that are listed in the file.

The function passes the information back by means of the pointer to the Placement struct (which will be filled with the orientation and coordinates of the ship) and by returning the index of the ship. When there is no more ship to be read in the file, it returns -1 instead. Remember that it is possible that fewer than FLEETSIZE ships need to be placed.

You may assume that the placements listed in ship_placement.txt are always valid. This means that the ships fit on the board and do not overlap. You therefore do not need to check for this in your code.

 

Building Block 3 - Getting the coordinates for the shots

Use the ask_shot() function to ask the user for an (x,y)-coordinate to shoot at. Again, it is already implemented for you as part of our library (i.e., it is  included in helper.o and its prototype is specified in bship.h). The user needs to enter the x and y values separated by a comma. For example, to shoot at (x,y) equal to (2,3), enter: 2,3. The function returns this information as a struct of type Coordinate. You may assume that the user will always enter a valid coordinate, i.e., one that is within the board. So, again, you do not need to check for that in your code.

Call ask_shot() repeatedly until the user enters *, at which point the program should finish. If the user enters *, the function will return (-1,-1) as the coordinate. Make sure that your program finishes when the user enters * (otherwise, it might run forever, which is a problem for grading). When the program finishes, you need to call the function msg_end(), which will signal that the game is over.

 

Building Block 4 - Detecting when a ship is hit

When a shot strikes one of the ships on the board in a spot where it had not been hit before, call the function msg_hit(). Otherwise, i.e., if this is not at a coordinate that is part of a ship or this coordinate was hit already, call the function msg_miss().

The function msg_hit() needs to be passed one argument: the name of the ship that was hit.

 

Building Block 5 - Detecting when a ship is sunk

A ship is sunk when the last hit caused it to have been hit now in all its positions. A ship can only be sunk once.

When a ship is sunk, you need to call the function msg_sunk(). As a function argument, pass it a string stored in a dynamic array. It is important that you use a dynamic array for this, because our msg_sunk()function frees the memory. The content of the string should be “The ship that was sunk is a NAME." with NAME replaced by the name of the ship that was sunk. Do not forget the period at the end of the message. Remember that you cannot include a string library! For the dynamic memory allocation, if not enough memory is available, the program should end immediately.

When the last ship was sunk, the program should finish. In that case, also call the function msg_end(), which signals that the game is over.

 

 

Submitting

Testing your Code

To verify that your code is compatible with our grading script, run the following command in your PA6 directory: :

$ makeTest PA6

This will create the executable test_ship. It only tests a simple example and is not meant to help you verify whether your code does the right thing. You need to do more extensive testing on your own. Note that if you make changes to your code, you need to execute makeTest PA6 again, as otherwise the executable will not have been compiled with your latest code.

When running test_bship, it will show ship data that it supposedly read from ship_info.txt and ship_placement.txt. However, this data is not actually read from these files, but rather baked into the test program itself (as will be done during grading). So changing your ship_info.txt and ship_placement.txt will have no effect on this test case.

 

How to interpret the output:

When running test_bship, it shows the sequence of ask_shot() inputs that were used for testing, with the value between [ ] just a sequence number. The results for the various messages in response to the corresponding shots are shown next (the sequence number enables you to match which response corresponds to which shot). Here, “--” stands for “not applicable”; it means that this function was not called in response to that shot.

To further illustrate this, consider the example below. This reported output:

Shot coordinates entered: [0] 1,1   [1] 2.4   [2]  *

Hit or miss (your answer): [0]  M    [1]  H     [2] Program ends

Ship name if hit (your answer): [0] --  [1] rowboat  [2] --

Message if ship sunk (your answer): [0] --  [1] The ship that was sunk is a rowboat.  [2] --

End of game (your answer): [0] --     [1] --     [2]  Game ends

 

is a shorthand for representing this actual sequence of events:

ask_shot: Where do you want to shoot (as x,y)?  1,1  [0]

msg_miss: Not a successful hit [0]

ask_shot: Where do you want to shoot (as x,y)?  2,4  [1]

msg_hit: Successful hit (ship name: rowboat) [1]

msg_sunk: The ship that was sunk is a rowboat. [1]

ask_shot: Where do you want to shoot (as x,y)?  * [2]

msg_end: The game has ended [2]

 

 

We will use the same shorthand when we will give you the grading feedback.

Note that when you run test_bship, you will also see two dotted lines. Anything between those lines is printed by your code. Before submitting, you should remove or comment out these print statements.

 

Submission Instructions

To submit your assignment, run the following command:

$ submit PA6

This will submit your bship.c file. Make sure you have commented out or deleted any print statements that you used for debugging. The only things that are shown should be the result of the library functions that we created for you.