Project 4: Battle Them Ships!

Overview

The fourth (and final!) project this summer “pulls out all the stops” and just gives you a problem to solve in C. No starter code, no design advice, nothing but you and what you learned this summer. I hope you’ll produce a bunch of nice programs. Good luck!

You’re free to work with a partner for this project, but you are not required to partner up. If you choose to work with a partner, don’t try to “split” the work, it won’t be successful. The best approach is to get together in person and to actually write code together. Do that! You’ll get more out of it, maybe even a winning program.

Of course we’re going into a completely different domain yet again! Your job is to implement a variation of the classic Battleships game. The exact game rules as well as the various technical constraints are detailed below. The “special twist” is that your program will play against everybody else’s programs in a tournament. The ranking your program achieves in that contest is part of your score. However, the ranking is not the biggest grade component, so winning “at all costs” is not encouraged. Try to write a correct, reliable, and beautiful program that wins through superior strategy. Don’t get too desperate about being “number 1” as that desire has a tendency to backfire.

It is very important that you stick exactly to the data formats defined below! If your program cannot “play” correctly, it will be disqualified. Completely disqualified, not just disqualified from the tournament. Make sure you process all input and output exactly as specified!!

As always, you’re expected to develop (and submit!) a useful testing infrastructure for your project. What exactly that involves depends on how you structure your program, but however you do your testing, we expect to see coverage analysis as before! Your goal is to get 100% line coverage for each source file, but it may not be realistic to achieve that; try to get as close as possible and defend any missing coverage in your README file.

Game Rules

The game is played on a 10x10 square grid on which each player places his or her ships. The ships are one aircraft carrier of size 5, two battleships of size 4, three cruisers of size 3, and four destroyers of size 2. The ships can be placed anywhere, either vertically or horizontally, as long as each ship fits in its entirety. Ships are allowed to touch, but they are not allowed to intersect.

The game proceeds in turns. Player A announces a square on Player B’s grid to attack; player B checks their (secret) setup and replies whether the attack hit a ship or missed all ships; if it is a hit, and if the hit eliminates the last remaining square of a ship, player B has to announce that a ship was sunk; if the last ship of a player was sunk, the attacking player wins; otherwise the roles are switched and player B attacks a square on player A’s grid; and so on.

Technical Details

Your program will communicate through standard input and standard output. The output of your program will be the input to your opponent’s program and vice versa. It is imperative that you follow the format of messages detailed below exactly as given, any match during which your program fails to adhere to the specified format will be counted as a loss for you.

If your program is started as ./battle that means you’re going second; if your program is started as ./battle -f or ./battle --first that means you’re going first. The program who goes first starts by sending a command to the opponent; the program who goes second starts by reading a command from the opponent; after each “message exchange” roles switch unless the game is over.

On Piazza we provide you with a simple tool hacked in Python that can be used to start two Battleship programs and have them talk to each other. The tool is used as follows:

python piper.py programone programtwo

Here programone and programtwo are the two Battleship programs that are playing against each other. You can provide the same name twice, in which case the program will play against itself. As part of starting the programs, piper will will provide the -f option to programone telling it to go first.

The protocol consists of the following messages (in the form of strings):

FIRE column row
MISS
HIT
SUNK size
CONCEDE
CHEAT

The game starts with the program going first sending a FIRE message to attack the given position. Positions are encoded as the letters A to J for the column and the numbers 1 to 10 for the row. For example, the message FIRE C 10 would attack the square in the third column and last row. The response for most attacks will be either HIT if a ship was hit or MISS if no ship was hit; note that the program not attacking right now sends that message, so after sending out FIRE C 10 you need to wait for a reply from the other side. After sending the reply, sides change, and the other side sends, for example, a FIRE A 7 message; and so on.

If an attack sinks a ship, instead of replying HIT you must reply SUNK and give the size of the ship just sunk as an integer; so sinking the aircraft carrier would lead to SUNK 5. Eventually an attack will sink the last ship, in which case you must reply CONCEDE instead of SUNK and the game ends.

The only other way for the game to end “properly” is with a CHEAT message. The program sending that message is accusing the other program of cheating. Once a CHEAT message has been sent or received, both programs stop. If the accusation is correct as determined by the judges, the accusing program wins the round; if the accusation is incorrect, the accused program wins the round.

Really Important Stuff

All messages have to end with a single linefeed character. All letters are upper-case. There’s exactly one space between the parts of a message.

If you cannot parse the command the other program sends, you should print an error message to standard error and exit with a failing status code. If the other program was at fault, your program wins; if your program was at fault, the other program wins.

If at any time a program “gets stuck” and doesn’t send any of the expected commands within a reasonable amount of time (less than a second for sure), it is disqualified.

Your programs are not allowed to store data persistently (on disk, across the network, etc.) between executions.

If your program implements either cheating or cheat detection you must talk about this in your README file to give the judges fair warning without having to read every single line of your code. If your program cheats without disclosing that fact in the README file it will be disqualified.

Deliverables

The exact structure of your project (how many .c and .h files, their names, etc.) is up to you. All we expect is a Makefile that can be used to build your program when we run make without a target. We also expect your executable to be called battle.

Please follow the submission instructions as detailed on Piazza. Make sure that your tarball contains no derived files whatsoever (i.e. no executable files), but allows building all required derived files. Also, be sure to include a Makefile that sets the appropriate compiler flags and builds all programs by default. The Makefile should also have clean and test targets as per usual; the test target should run both system and unit tests; ideally it also runs coverage analysis for you. Finally, make sure to include your name and email address (for both partners if this is a paired project) in every file you turn in (well, in every file for which it makes sense to do so anyway)!

Grading

For reference, here is a short explanation of the grading criteria; some of the criteria don’t apply to all problems, and not all of the criteria are used on all assignments.

Packaging refers to the proper organization of the stuff you hand in, following both the guidelines for Deliverables above as well as the general submission instructions for assignments on Piazza.

Style refers to C programming style, including things like consistent indentation, appropriate identifier names, useful comments, suitable documentation, etc. Simple, clean, readable code is what you should be aiming for. Make sure you follow the style guide posted on Piazza!

Design refers to proper modularization (functions, modules, etc.) and an appropriate choice of algorithms and data structures.

Performance refers to how fast/with how little memory your programs can produce the required results compared to other submissions.

Functionality refers to your programs being able to do what they should according to the specification given above; if the specification is ambiguous, ask for clarification! (It also refers to you simply doing the required work, which may not be programming alone.)

If your programs cannot be built you will get no points whatsoever. If your programs cannot be built without warnings using the required compiler options given on Piazza we will take off 10% (except if you document a very good reason). If your programs cannot be built using make we will take off 10%. If your programs fail miserably even once, i.e. terminate with an exception of any kind or dump core, we will take off 10% (for each such case).