Lab 4: C Programming Project
This C programming project focuses on dynamic memory allocation, pointers, file I/O, and string manipulation.
In this lab, you will write a program to play a game named Frigate, which is a one-sided game of Battleship in which the computer hides the ships, and the player must destroy them before s/he runs out of ammunition (the player has a limited number of shells per game).
An example game, including user input, is shown below. While your program does not have to match this example program letter-by-letter, it should provide similar functionality.
unix> ./frigate Welcome to Frigate! How large should I make the grid? 2 The minimum grid size is 5... I'll create one that size. A B C D E +---------- 1 | - - - - - 2 | - - - - - 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (12 shots remaining): b1 B1 is a miss A B C D E +---------- 1 | - m - - - 2 | - - - - - 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (11 shots remaining): 2c C2 is a HIT A B C D E +---------- 1 | - m - - - 2 | - - h - - 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (10 shots remaining): d2 D2 is a HIT A B C D E +---------- 1 | - m - - - 2 | - - h h - 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (9 shots remaining): e2 E2 is a HIT A B C D E +---------- 1 | - m - - - 2 | - - h h h 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (8 shots remaining): B2 B2 is a HIT A B C D E +---------- 1 | - m - - - 2 | c h h h h 3 | - - - - - 4 | - - - - - 5 | - - - - - Enter the coordinate for your shot (7 shots remaining): b5 B5 is a hit A B C D E +---------- 1 | - m - - - 2 | - c c c c 3 | - - - - - 4 | - - - - - 5 | - h - - - ..... Enter the coordinate for your shot (3 shots remaining): 4b B4 is a miss A B C D E +---------- 1 | - m - - - 2 | c h h h h 3 | - h - m - 4 | - m m - - 5 | m h h h b You do not have enough shells left to sink the remaining ships. Here is the original ship locations. A B C D E +---------- 1 | - - f f - 2 | c c c c c 3 | - f f - - 4 | - - - - - 5 | - b b b b You sunk two ships. Play again (y/N)? N You won 0 out of 1 games. Thanks for playing! unix>
The user specifies at the beginning of the game the size of the grid; it will always be square and any size between 5 and 20. The player gets n shells, where n is 1/2 the grid size squared. The number of shells is rounded down to the next smallest integer value.
The computer next randomly places four ships (one carrier of 5 squares, one battleship of 4 squares, and two frigates of 2 squares) randomly inside the grid. Ships must fit inside the grid and cannot be placed on top of one another (there are no submarines in frigate. There's no crying in baseball.)
Coordinates are noted by row/column, where row is a number and column a letter. A player can enter coordinates either row or column first (i.e., 1a or A1). Upper or lower case letters are allowed. White space is not allowed. Coordinates are checked for validity; they must lie within the grid and a player can enter a coordinate only once per game.
A ship is "destroyed" when over 70% of its structure has been hit. When a carrier or battleship is destroyed, its type ("c" or "b") is displayed on the screen filling the rest of the ship's location.
You must create a Makefile for your program (with the name Makefile). I should be able to enter the directory containing your code and type make to trigger compilation. If the Makefile is broken, or if I need to type anything else (or dig into the source code to figure out how to compile your program), zero points will be awarded!
Use the following GCC options in your Makefile to set the compiler to a very picky mode:
- -std=c99 (Use the more modern C99 standard for the C language)
- -Wall and -Wextra (Turn on all warnings and extra warnings. By viewing and fixing issues that generate warnings, you will produce better, safer, C code)
- Warning: Don't delete the existing -c flag in the Makefile example from the previous lab! (It is essential to Makefile operation)
Configure your Makefile so that the name of your program binary is frigate
Makefile grading nodes:
- If your program produces any warning during compilation (with these options), 5 points will be deducted.
- If your program doesn't compile on my virtual machine (and the error is such that your code wouldn't compile on any of your classmate's machines either!), zero points will be awarded.
Requirements: Memory Structures
Use a two-dimensional array of characters to store the current state of the game. In this array, store the '-' character to denote unknown coordinates, 'h' and 'm' to show hits and misses, and when appropriate 'c' and 'b' to show known ships. As the game is played, update this array based on user input.
Because the size of the grid is variable, you must use dynamic memory allocation to store this array. Remember to release dynamic memory before exiting! How can this be accomplished? In C, a two-dimensional array is simply an array of arrays, and you can allocated a single-dimensional array using malloc() or calloc(). This method is documented at the C FAQ site.
Tip: A demo program that uses dynamic memory allocation is provided for your reference. Note that it stores an array of integers, while you will want an array of characters. It can be compiled and run with the command:
unix> gcc dynamic_2d_array.c -std=c99 -o dynamic_2d_array
- I will compile and test your program in a Linux virtual machine that meets the installation process followed at the beginning of the semester. Don't relay on anything that wouldn't be in this default installation!
- You must implement the program in C
- You cannot use global variables.
- You must use both header files (.h) and source files (.c) where appropriate
- You must create a C structure for a datatype called ship that is saved in a header file. The following information (at a minimum) should be contained in this structure
- The letter denoting the type of ship
- The size of the ship in squares
- You must use functions with ship parameters. The actual division of the program into functions is up to you.
- You must include a demo mode for playing a single game. Your program will read from a file the locations to place ships. You will invoke demo mode by passing a parameter to the program which is the filename containing the all the information for the demo. The format for demo_file.txt is below. The first character of each line determines the contents of the rest of the line (the meaning of each character should be self-explanatory). Any line starting with a '#' character is comment and is ignored.
# carrier, row starting at c2 (c2,c3,c4,c5,c6) c r c2 # battleship, column c starting at d1 (d1,e1,f1,g1) b c d1 # frigates, row g starting at g2 and g6 f r g2 f r g6
- All source files must be commented, including your name and email address.
- Use the random and srandom functions to pick coordinates and orientations for each ship. See man random for usage.
- You may wish to use fgets and sscanf instead of scanf to read user input. While it uses two steps instead of one, it can handle a number of potential problems with erroneous user input much more easily.
- Declare the main function as int main(int argc, char *argv[ ]). This will allow you access to command line arguments (see demo_file.txt below).
- Feel free to use fancier text editors or IDEs that auto-indent your code and provide other convenience features. Just note, however, that you still must have a Makefile that allows your project to be compiled by typing make at the command line! (i.e. I will not install any IDEs on my computer, and still should be able to compile your project).
- Geany (fancy code text editor) - install via sudo apt-get install geany
- CodeBlocks (cross-platform IDE) - install via sudo apt-get install codeblocks
Requirements: Test Case
As part of this lab, you must submit a test case that demonstrates your program operation, including both valid and invalid human input. This test case has three components:
- A sample demo file (discussed earlier) which places the ships in known locations
- A sample human input file with grid size 10 which demonstrates a winning game, including invalid coordinates.
- A sample human input file with grid size 9 which demonstrates a losing game.
The sample human input files should be stored in the files human_input1.txt and human_input2.txt. Note that this file is exactly what a person would type at the keyboard while running the program!
The human input file can be run using Unix input redirection. Via this mechanism, your program can automatically read from this file instead of standard input (i.e. the keyboard) with no code changes required! The command to accomplish this is simple:
unix> ./frigate demo_file.txt < human_input.txt
Be sure to test that your test case functions in this manner.
Note: When you use input redirection, the input will not be echoed on the screen in the same way that keyboard input is echoed. It is OK if your program output looks a little strange in this mode. You don't need to adjust your program code to accomodate this.
- Need C programming resources? Visit the class Resources page
- The Instant Online Crossword Puzzle Maker may help you construct creative new sample puzzles for your program.
First, go to the directory that will hold your project.
unix> cd ~/bitbucket/2013_fall_ecpe170/lab04
Second, write your program in this directory!
Here is one way to approach this lab in a step-by-step manner:
- Create a .c file for source code and .h file for header information. Put in a few lines of code - just enough to compile and produce some output.
- Create the Makefile - you'll need this to compile your program! Base this off of the advanced "Makefile-4" from the previous lab, but call it "Makefile" here.
- Test the Makefile
- Add these files to your version control repository, and commit a new changeset. Be careful - don't include any of the temporary files your text editor creates! Those end in a tilde (~).
- Write dynamic memory code - Save the gameboard into dynamic array(s) created based on the demo program code. You might want multiple arrays, one for the gameboard itself, and another with only the ship locations.
- Test dynamic memory code
- Commit a new changeset to version control
- Write the game play logic, prompting the user for input and comparing against the correct answer.
- Test game play logic
- Commit a new changeset to version control
- Write file I/O code for demo mode - read in the demo instruction file and echo the output on the screen (for debugging)
- Test file I/O code
- Commit a new changeset to version control
- ... and so on ...
(1) Check all of your code (including Makefile and test cases) into version control, and push to BitBucket.
Want to test your submission to ensure you don't lose points due to version control errors? You could do a checkout of your repository into a different directory. Then, verify that all files are present and that you can still compile this copy of your project in its new location.
- Warning: Don't be sloppy and add too many files to version control! 5 points will be deducted if intermediary files (i.e. .o object files) end up in your repository.
- Warning: Don't be sloppy and add too few files to version control! Zero points will be awarded if missing source code or Makefiles prevent your program from compiling and running!
- Warning: Make sure your Makefile has the exact name "Makefile", so that I can compile your program simply by typing make in the directory.