CS 302, Program 4

Program 4, Spring 2014: BattleSweeper

  P4 TEAMS DUE before 4:00 PM on Friday, May 2nd
  P4 CODE DUE before 4:00 PM on Friday, May 9th
  NO LATE PROGRAMS WILL BE ACCEPTED!

[ P4 Announcements | Overview | Game Play | Program | Javadoc | Getting Started | Milestones | Testing | Submission ]

P4 Announcements

Corrections, clarifications, and other announcements regarding this programming assignment will be found in this section:

Overview:

Assignment Goals

  • Create a program that conforms to a specified user interface
  • Practice using 2-dimensional arrays
  • Practice using ArrayLists
  • Use command-line arguments with a Java program
  • Read and write data from external files
  • Implement an entire program from scratch (no code skeleton!)
  • Design and implement at least two (2) instantiable classes

Background

Unlike the classic board game Battleship, which is purely guesswork between two players, the BattleSweeper game you're about to design and implement is a one-person logic puzzle. The player is given a grid of cells and the number of cells in each row and column which contain a ship (or a portion of a ship). With that information and a few revealed squares, it's possible to reason out the exact location of every ship on the board.

Game Play

Objective: Find all of the ships in puzzle grid. Play starts after the user selects a puzzle from the  Play a puzzle menu item.  Menu descriptions follow this section.

The play of a particular puzzle starts with the display of a grid of characters representing the intial board condition.  Initially, most of the cells are unknown and marked with '?' character. The numbers on the top and side of the grid tell you how many ship pieces are in that row or column. Ships are only aligned horizontally or vertically - no diagonal ships. Also, ships never touch each other, horizontally, vertically, nor diagonally.

The numbers on the top and right side of the board indicate how many ship pieces are in those columns and rows. The letters on the left and bottom of the board are for the user's reference while playing - the user will enter a row/column combination by typing in the letters that correspond to the cell they wish to access.

The contents of the cells will be as follows:

  • . : water
  • o : single-cell ship
  • < > : two-cell ship, oriented horizontally (a vertical ship would be a '^' above a 'v')
  • < + > : three-cell ship, oriented horizontally (a vertical ship would be a '^', a '+', and a 'v')
  • ? : unknown cell
  • S: guessed ship (Note: Ship parts are indicated with the character S only while the puzzle is in the process of being solved. Once the puzzle has been solved, the S characters will be replaced with actual ship characters indicating which ship was found there.)

Let's walk through how you'd play the game after the user loads a puzzle and selects that puzzle to play.

Here's a sample initial board setup:

Since row d and column i both have 0 ship parts, they must be entirely water.  Enter each row,column location and set to water.  Once all locations in row d and column i have been set to water, the board looks like this:

Since row f and column k have only 1 ship part, which is already shown at f,k, the rest of f and k must be water. After setting the remaining locations in row f and column k to water, the board looks like this:

Because ships cannot be adjacent diagonally, the cells e,j and e,l must be water. After setting those locations, the board looks like this:

Row a and column j each have three ship parts in them and only three unknown cells, so they must all be ships. After setting those locations to [s]hip, the board looks like this showing S where any ship part was set:

Row b and column l each have one ship part in them already, so the rest of b and l must be water.

At this point, the rest of the unknown cells must be ships, so we fill them in and the puzzle reveals itself as correctly solved!

The BattleSweeper Program

Because implementing a single BattleSweeper puzzle does not require all of the programming skills we wish you to learn, you'll be implementing a program that can also read and write files and save information about the players who play the game. 

At the start, your BattleSweep program will:

  1. OPTIONAL: Read a file with player information and load that data for players who played previously. 

    This occurs before the play starts and only occurs if the program is run using a single command line argument that is a valid filename.  These two documents should help you implement this part if you choose.
    • Instructions for configuring Eclipse to use command-line arguments. (PDF)
    • Instructions for reading the player information from a file. (TXT)

  2. REQUIRED: Display a Main Menu and implement the options as described in the following.

The Main Menu

The main menu and user prompt should look like this:

                === BATTLESWEEPER MAIN MENU ===

                1. List player information
                2. Load a new puzzle
                3. Play a puzzle
                4. Quit

                >

The > below the menu is a very simple user prompt. The user typed the number of their selection after the prompt. If they make an invalid choice, simply display the prompt again (no error message necessary).

Main Menu option details

  1. List player information looks like this (for example):
                    === BATTLESWEEPER PLAYERS ===
    
                    HBS: puzzle1 puzzle2
                    DEB: puzzle1 puzzle3
                    JIM: puzzle2 puzzle1 puzzle3
                    BEC: puzzle2
    This menu option screen is purely informational (and has no prompt), and is laid out as follows:
                    === BATTLESWEEPER PLAYERS ===
    
                    IN1: <puzzle> <puzzle> ...
                    IN2: <puzzle> <puzzle> ...
                    IN3: <puzzle> <puzzle> ...
                    ...
                    IN4: <puzzle> <puzzle> ...

    It is a list of the player information.  For each player that solved a puzzle, the players' intitals, followed by a colon : character, followed by a space-separated list of the names of the puzzles they have solved.

    The players in this list should be in the order that they first solved a puzzle, and the puzzle list for each player should be in the order that the player first solved those puzzles. Note: if a player solves the same puzzle multiple times, it should only appear ONCE in the player's puzzle list.

    If no players have solved any puzzles yet, just display the === BATTLESWEEPER PLAYERS === header.

                    === BATTLESWEEPER PLAYERS ===
    

    Once the player information has been displayed (or not), return to the main menu (don't wait for user input).

  2. Load a new puzzle prompts the user for a filename as shown here:
                    === LOAD A PUZZLE ===
    
                    Enter a filename: puzzle4.txt
    The user enters the name of a file with a valid puzzle data configuration.  The user input shown is: puzzle4.txt .  The program then attempts to load the file as a new puzzle. If the file is found and the puzzle configuration is read successfully, return to the main menu.

    If the file does not exist, print Error: file puzzle4.txt not found and return to the main menu. Note: puzzle4.txt would be replaced with the name of the file the user attempted to load.

    Your BattleSweeper program does not have to handle the case where the file exists and can be read, but the file does not contain a valid puzzle configuration.  Example of a valid puzzle configuration file: puzzle1.txt


  3. Play a puzzle prompts the user with this menu:
                    === BATTLESWEEPER PUZZLES ===
    
                    1. puzzle1
                    2. puzzle2
                    3. puzzle3
                    4. Go Back
    
                    > 1
    Again, the > is your prompt and the 1 shows an example of the user's input. In this case, the game has three puzzles loaded, from files named puzzle1.txt, puzzle2.txt, and puzzle3.txt (so a puzzle's name is simply everything that comes before ".txt" in its filename).

    Choosing 1-3 will take you to the solver, the last menu item (4 in this example) will take you back to the main menu. 

    Any invalid input should simply cause the > prompt to display again and allow the user to retype their selection.

  4. Quit displays the following and prompts the user for a file to write player information to.
                    === BEFORE YOU GO! ===
    
                    Enter player history filename:
    If the user enters nothing (or a file name that can't be written to), exit the program without saving the current player information to a file. Otherwise, write the menu screen from option 1 to the file the user specifies, and then quit.

Puzzle File Format

You've been doing menus since P1, so that all should be easy. The file loading will be a bit more challenging. For reference, let's use the file puzzle1.txt, which corresponds to the puzzle solving demonstrated in the Game Play section above and in the example below.

All puzzles are played on a 6x6 board. To keep things simple, the puzzle files have a very specific format (and all valid puzzle files will have this format, so don't worry about checking it): For example, puzzle1.txt contains the following:
puzzle1.txt File Example Interpretation of the Puzzle File Format
a,g
a,l
f,k
c,g c,h
e,g e,h
a,j b,j c,j
2
a,h
f,k
[ship location]
[ship location]
[ship location]
[ship location] [ship location]
[ship location] [ship location]
[ship location] [ship location] [ship location]
[how many cells are revealed]
[revealed location]
[revealed location]
...

  • The first three lines are for the single-cell (o) ships.
  • The next two are the two-cell (<>) ships
  • The next one line is the three-cell (<+>) ship.
  • The next line is the number of locations that will be revealed (displayed) to the player.
  • The next lines indicate the row,column of revealed locations; one line per revealed location. For example, in puzzle1.txt, there are two (2) revealed locations. All coordinates are letters indicating the row,col that is to be revealed in the puzzle grid.  Hint: use zero-based indexing starting in the upper left corner.
  • There will be no trailing newline (that is, no empty line at the end of the file).

There will always be exactly six (6) ships but there may be any number of cells displayed to the user.

Do not make any assumptions about the ordering of the provided information outside of the type of information provided in a line (for example, we do not guarantee that the ships or revealed locations will be listed from upper left to lower right).

Once you've loaded a puzzle correctly, it should be available to the user for play the next time they choose Play a puzzle from the main menu. Again, the initial board for puzzle1.txt should look like:

Prompt your player with Row,column or (q)uit: (Note: you may assume correct input at this point. If you wish to implement input checking for your own benefit, you may, but this behavior will not be tested). Once they've specified a location, ask whether they wish to place water or a ship at that location:

However, if your player tries to change one of the initially-revealed cells, don't let them and display the message: That location is fixed!:

If your player tries to do something illogical, don't judge them! Let them make their own mistakes:

A puzzle should be considered complete when the user has entered a guess for all of the cells (that is, no ? remain). If the user has correctly solved the puzzle, you should display all the ships in their correct configurations and print Congratulations!:

Once the puzzle has been solved successfully, prompt the user for their initials (Enter your initials: ) and transform their input to UPPER CASE (if a word longer than three characters is input, use only the first three characters). If a player with that name does not exist, create a new player with that name and add this puzzle to their list of solved puzzles. If a player with that name does exist, add the current puzzle to the list of solved puzzles for that player (but only if that puzzle is not already included in their solved puzzle list).

Note that at any time during the game, the user can give up by entering q. This should reveal the puzzle's solution and print Quitter. instead of Congratulations!, and return to the main menu without asking for the user's name.

If the grid is full so the puzzle is complete but the player has NOT solved the puzzle correctly, change any cells that the user incorrectly guessed to E, and print Oh no... and return to the main menu. The player must play the puzzle again to solve.

Optional "Nice-to-Have" That You May Implement If You Want To

THIS OPTION WILL NOT BE TESTED. If you know a whole row or column is going to be water, it can be tedious to go through and change every cell to water individually. If you choose to, you may implement an option for the Row,column prompt that accepts a single character and then confirms with the user that they wish to convert the entire row or column to water:

We won't be testing this behavior, but it can make playing the game a bit more enjoyable :)


Required Object Oriented Design Components for Program 4

NOTE: Your main class must be named BattleSweeper.java.

Students are required to design and implement at least two (2) instantiable classes.

Suggestions for instantiable classes:

The design of this program is entirely up to you, and we won't be providing any code skeletons. Your design should follow encapsulation principles (for example, don't have public instance variables - use accessor methods). However, if you're stuck on how you want to implement the program, maybe these suggested classes will get you started:

Player.java

Store information about the players using your program.

Puzzle.java

Store information about the puzzles your users can solve.

BattleSweeper.java

Must have a main method, but you may find some benefit to making this class instantiable.  It could store information about the current state of the BattleSweeper programs.


Javadocs

Since we don't provide any skeleton, the documentation is entirely of your creation. Hint: Use the examples from Programs 3,2,1 to help you get started.

Getting Started and Development Milestones

We suggest that you incrementally develop this program by following the milestones in the order listed below. This order will make it easy for you to check that each milestone is working properly before you move on to the next one. Don't move on to a new milestone until you can convince yourself that the current milestone is working correctly. The further along you get, the harder it will be to detect errors in code you developed early on.

  • Milestone 0 (4/23) - Read the assignment, create your project with a main class named BattleSweeper.   Add code to display main menu and accept user input to choose a menu option.  Implement the quit option without worrying about the file output. 

    Reminder: Pair programming teams: Be sure to register (create AND join) your team via Forms before you begin working with someone on Program 4.

    sample-runs/milestone0.txt

  • Milestone 1 (4/25) - Implement main menu option 1 to display player information.  Hint: You can hardcode player information or create some dummy player information in your program.  But, no players have played and won yet, so you'll just be doing this part for your own testing purposes. 

    Also, add code to write to a file. This is the second part of the quit option. Ask the player for a file name and write the player information to the file named by the player.

    sample-runs/milestone1.txt (Note: after this sample run, your directory will contain a file called player_output.txt with contents identical to this.)

  • Milestone 1 [OPTIONAL: command-line argument] (4/25) - If you choose to implement the command-line option for reading player information from a file.  This is a good time to implement that option.  Read this sample player information file to your program.  player_input.txt

  • Milestone 2 (4/28) - Implement main menu option 2 to read a puzzle in from a file and display the solved puzzle grid.  Displaying the solved puzzle grid is just for testing, so that you can see if you are generating the solved puzzle grid correctly.  This display of the solved grid should be removed from the final program submission.

    sample-runs/milestone2.txt (Note: this sample run uses the file puzzle4.txt)

    The file format is specified, but we have left the design of how to store that puzzle grid up to you.   HINT: You will likely need to keep two copies of the puzzle grid: one for the solved puzzle and one for the current state of player's guesses.   This idea is not a requirement, but is intended to help students think about this issue.

  • Milestone 3 (4/30) - Implement main menu option 3 to allow the player to solve the puzzle.  Follow instructions in Game Play for correct implementation of this part.

    sample-runs/milestone3.txt (Note: this sample run uses the optional row-fill behavior. Those steps are equivalent to individually setting all remaining unknown cells in a row or column to water.)

  • Milestone 4 (5/2) - Return to each milestone and be sure that it does what it is supposed to do, and just the testing and development behavior we've suggested. 

    sample-runs/milestone4.txt

  • Milestone 5 (5/7) - Complete testing and debugging of program and handin before 4pm on Friday, 5/9.

Testing

The testing server will be available one week before the due date.

Submission:

Before handing in your program, check that you've done the following:

  • Did you verify that your program works correctly by following the information in the Testing section above? About 75% of your grade is based on your program working correctly and handling errors as described.
  • Did you turn in all necessary source files listed below? About 5% of your grade is based on submitting ALL source code files correctly.
  • Did you use good programming style by following the CS302 Style Guide? About 15% of your grade is based on good programming style.
  • Did you properly comment your program by following the CS302 Commenting Guide? About 5% of your grade is based on proper commenting. Note, we've provided most of your method header comments. But, it is still the students responsibility to ensure that they are complete and correct.
  • Are your program's source files named exactly as provided by the skeleton? You will not be able to hand in files, if you have renamed any files. You will lose points if you renamed any classes or changed any public methods headers from the skeleton.

Use the CS302 Forms Page to electronically submit and backup your work:

  • You may submit the files listed below as often as you wish at any time before the due date and time.
  • Previously submitted files are overwritten when you re-submit your work.
  • We suggest you use your handin directory to keep a backup of your most recent working copy as you develop your solution. Use the "List Files" form to download the files in your handin directory as a backup. They are downloaded as a zip file that you'll need to unzip to extract your files.
  • You can verify that you've submitted things correctly. Please do not ask your instructor to check for you. Use the "List Files" form to list and download what you've submitted to verify that the files with the desired contents are your handin directory.

Submit these files:

  • BattleSweeper.java
  • Any other class source files you developed to complete the assignment. DO NOT HANDIN *.class files.

As stated in the assignment goals, to receive full credit, you must have implemented and used AT LEAST TWO instantiable classes to complete this assignment.