Note: This assignment will take significantly more time to complete than assignment 1. Please start early. Programming classes and objects for the first time can be very confusing. It will be very helpful if you allocate enough time to ask questions.
For the next assignment, and for the majority of the semester, we will be recreating the classic Battleship game. For those of you who haven't spent hours of riveting ship-sinking fun, don't forget to visit your nearest search engine and take a look at how it is played. If you don't like ships, you are free to remake the theme of the game (Maybe you want to have a caterpillar themed Battleship game. This would be strange, but you can do it). Either way, remember to preserve the rule structure!
In our version of Battleship, the main drawing screen will consist of two boards, side by side. The board on the left is your board where you can see all your ship placements as well as shots the computer has attempted. The board on the right will be the computer's board. You will not be able to see the computer's ships, but you will be able to see your shots - hits and misses.
The first thing you will need to do is create the class framework for the game. This is very foundational for the rest of your work this semester, so if you are confused, it might be wise to chat with one of the TAs. Listed below are the major classes and their functions. For this assignment, it is your job to create each class described.
First create an abstract class Ship. Because of the nature of Battleship, each user will have several different types of ships at their disposal. This means that you will be creating a concrete class for each variety of ship. Here is the classic breakdown of ships and their lengths on the gameboard (Each of these ships should have their own subclass of the Ship class):
This is an inheritance relationship where class Ship will be the superclass and each type of ship will be a subclass of Ship. At the end of this section you should have created 6 different classes (The abstract class Ship and a subclass for each type of ship). When you create your Ship class, you should include variables or methods that MUST OCCUR in ALL SHIPS . One example is if you kept a hits variable - an integer that holds how many times the ship has been hit (or maybe you would keep a life variable instead).
When you create your subclasses of Ship, ask the question "What makes this ship distinct?". That is the information that should be included in each class.
Remember that all ships should have instance variables that store the data needed for drawing the ship and keeping track of its status. The Ship class (and subclasses) should contain a draw routine which would draw the ship in its correct location onto the drawing area. Inside the draw routine you can use regular Java Graphics or Graphics2D drawing methods or an image to draw the Ship onto the drawing area.
The Ship class should have a constructor that specifies its initial position, orientation, or whatever other information you need.
This is another wonderful example of inheritance. Similar to your abstract Ship class, create an abstract Board class. Then, create two subclasses of Board - one representing your board, one representing the computer's board. In the abstract Board class, put all methods and variables that will be necessary for both boards. Put unique attributes of each board in the individual subclasses.
Your board class should include a collection of Squares - one for each coordinate on the board. Remember that the classic Battleship board is 10 by 10, although you may choose to create a larger board.
Because you have both a board class and a square class, drawing duties can be a little bit tricky to work out. Your board class should draw the grid you are used to seeing in Battleship games. This is important so that the Square class doesn't need to draw a square. This would be annoying to get the borders "just right". Instead, the square class will just draw what's inside the the square. A hit, a miss, etc. Each time you redraw the board, you should also redraw each of the squares in the board.
You should also provide an object that keeps track of the overall state of the game and draws the main game canvas. It maintains data that applies to the game as a whole. This class will create (or simply subclass) and maintain the drawing canvas, provide the main redrawing routine for it, as well as create the boards. Your Game.paintComponent() method should call each object that will appear on the screen and ask it to draw itself.
All drawing is done inside the paintComponent() callback, which may be called at any time. It will be called if the window is exposed or resized; you may also trigger it manually when the state of the game changes due to a user command. Your routine should always be prepared to draw the game from scratch, using data you have stored inside your objects.
Your main program, which is a public static method in your class called Main, should simply instantiate an object of class Main. Your constructor for Main will then set up your window, instantiate and initialize the objects you need, such as the Game object (which in turn instantiates the boards, etc.), show() the window, and then let the window system take over and wait for callbacks. The window should close and the application should quit when a user clicks on the close icon (the "X" in the far upper-right corner of the window title bar).
Once the program is running, it will simply display the drawing area, redrawing it as necessary, and wait for callbacks from user input.
When the program is run, it should be able to display both game boards. You should also hardwire your code so that it imitates a game in progress - show a couple of ships, as well as some shots across the board. Your game itself does not need to be functional. We are simply establishing the structure for you to construct a working game in the next assignment.
Your program design should exploit the features of object-oriented programming (encapsulation of code and data, support for abstract data types, polymorphism/overloading, inheritance). In particular, object-oriented programming provides us a good way to handle the various data needed in callback routines. You should use objects to encapsulate each interactive widget with the routines and data you need to use it.
You should provide an object for each interactive widget or small group of widgets you create. That object should hold anything you need to remember about the widget from one callback to another, all the data pertinent only to the command for that widget or that you need to operate this control, (including, in most cases, a pointer to the graph or other outside object to perform the actual action the user requested), and the widget's own listener callback routines.
If you have several widgets that share some behavior or properties, you should organize your objects into an appropriate inheritance hierarchy.
You will have other data that must be accessed by several widgets, particularly shared information about the state of the program or global information about the state of the user interface. Provide additional classes and objects for holding this kind of information.
Remember to trigger your drawing to repaint itself explicitly whenever one of your commands causes a change in the state of the graph that should be reflected on the screen. And remember that the way to change the screen is first to change the data stored in the Graph or other classes and then to trigger the repaint.
You should follow these general Java programming practices:
And, finally, for uniformity please name your Java class that has your main program in it Main, in file Main.java
In addition to your program, submit documentation about the design of your system in these forms:
ownwhich other objects)
usesor collaboration relationships (which objects use which other objects to perform functions)
secretsof each of your classes (i.e., what design decisions are entirely encapsulated within that class).
Submit this documentation electronically in text form. Include it as part of the readme file that you submit with your assignment.
These diagrams may be trivial for this assignment, but will become more interesting with later assignments.
As in the previous assignment, note that creating an excellent, nontrivial software application requires creativity beyond what your customers, or professor, can explicitly mandate. In general, great software satisfies a set of general requirements or requests, and then adds something beyond that. Grading for the assignments will reflect this fact. Satisfying exactly the bare minimum for each assignment will merit a grade of approximately 75% or 85%, depending on the specific assignment (15% for this assignment, as listed above). The remaining points will be awarded for additional work that adds the special something. This is not necessarily easy to do. You will be both the software designer and the software developer in this course. It's not just the implementation that is important, but also the design of the application. If you do this, include a brief description in your readme file, as noted in the submission instructions.