M/F 2:30-3:20   
in Philips 101

CS 1130: Transition to OO Programming

Spring 2015

J*Man

Due to CMS by Friday, Feb 27.

In this assignment, you will create a simple video game called J*Man. In this game, the player uses buttons to steer the star-like J*Man around a board, capturing other pieces. The assignment will give you more experience with the structure of object-oriented programs (e.g. subclasses, casting, and abstract classes).

While the game appears simple, the methods in this assignment are quite involved. It is important that you read and understand the directions before you start with the assignment.


Table of Contents


Before You Get Started

Academic Integrity

We have given this assignment before. It is a good one, and students really like it. Do not share your code with others. Do not obtain or look at a copy of the earlier solution or a version being done by another student. Such cheating helps no one, especially you, and it makes more unnecessary work for us.

Unlike the Rhino assignment, it is highly unlikely that your code for this assignment will look exactly like someone else's. This is the first assignment that we will actively be using Moss to check for instances of cheating and plagiarism.

Grading Policy

As with the previous assignment, you are to resubmit this assignment until you pass. Once again,for this assignment, passing is considered 85%. You do not have to get a perfect to pass.

We will not outline our grading scheme in this assignment. If you do not pass you will be told what to revise. Hopefully, everything should be working properly within one revision.

Collaboration Policy

You may do this assignment with one other person. If you are going to work together, then form your group on CMS as soon as possible. If you do this assignment with another person, you must work together. It is against the rules for one person to do some programming on this assignment without the other person sitting nearby and helping.

With the exception of your CMS-registered partner, you may not look at anyone else's code or show your code to anyone else, in any form what-so-ever.

Getting Help

If you do not know where to start, if you do not understand the GUI framework, or if you are completely lost, please see someone immediately. This can be the course instructor, a TA, or a consultant. Do not wait until the last minute. See the staff page to get help.


Rules of the Game

To see the game J*Man in action, first download the following jar file; this is our solution to the assignment. Put the jar file onto your desktop and then double-click. On most systems, this should launch the game and start it going. A window will open, with buttons, the game board, and the game rules. It should look like the image to the right.

In the game there are four kinds of items.

  • J*Man, a vaguely asterisk shaped character.
  • Obstacles, white blocks which sit in place.
  • Walkers, colored triangles that move about.
  • Pillars, colored disks which do not move.

Both Walkers and Pillars may either be red, yellow, or green. As J*Man moves about the board, the Walkers wander about slowly (in random directions), but they do not change color. Conversely, Pillars do not move but they do change color.

The goal of the game is to use the four navigation buttons to move J*Man about the board until he has captured all the Walkers and Pillars. The pieces that J*Man is allowed to capture is determined by its current color.

  • A green J*Man can only capture red pieces
  • A red J*Man can only capture yellow pieces
  • A yellow J*Man can only capture green pieces
Whenever J*Man captures a piece, it takes on that piece's color. Hence the challenge is to cycle the colors of J*Man appropriately to capture all the pieces.

Both J*Man and the Walkers follow the following rule: if they try to move off the board or try to move into a square that is occupied by something they cannot capture (for a Walker, this means any occupied space), they do not move. After each attempt by J*Man to move (regardless of whether it is successful), all the Walkers and Pillars also get to perform one action. This action is determined as follows:

  • Approximately 2/3 of the time (this is random), the action consists of doing nothing.
  • If a Pillar gets to act (the other 1/3 of the time), then it randomly chooses a color: red, green, or yellow.
  • If a Walker gets to act (the other 1/3 of the time), it randomly chooses a direction - up, down, left, or right - and attempts a move in that direction. If the move is illegal (e.g. there is something in the way), the Walker does nothing.


Understanding the J*Man Application

The structure of this application is a bit more complicated than the previous assignment. This assignment, like most real software applications, is not made from a single class file. When you have a program that is made up of several classes, it is important to organize the parts of a program in a logical and coherent way, so that it is clear what each part is responsible for and so that interactions between parts are kept reasonable. The larger and more complicated the task of a program, the more important it is to have good organization.

In this section, we do three things.

  • We introduce the model-view-controller (MVC) pattern.
  • We introduce the source code for the assignment.
  • We show how the source code conforms to the MVC pattern.

All of these are important for understanding the scope of this assignment.


Model-View-Controller Pattern

The classic way of organizing applications — particularly those that are sit on a single computer and do not need to connect via the internet — is using what is known as the model-view-controller paradigm. In this paradigm, every single class is categorized as either a model, a view, or a controller. The roles of each are detailed below.

Model

The model is a class that holds the application data. It provides getters and setters to manipulate the data, plus some useful additional methods to perform commonly used tasks on the data.

The Rhino class, which you worked on for the first assignment, is a classic example of a model class. In this assignment, you will again work on Model classes, though the will be more sophisticated than the Rhino example.

View

A view is a class that displays a graphical user interface to the screen. It also keeps track of when the user performs any input, such as typing or moving/clicking a mouse. However, it does not tell the program what to do when the user performs input. It only keeps track of the fact that it happened.

A JFrame is a classic example of a view class. It displays graphics, and notifies the program when the user clicks the "close box".

Controller

Controllers are the heavy lifters and they do everything else. They start up the program and instantiate the other classes (e.g. the view and model) with new-expressions. They also provide the methods that do something when the user performs some input (e.g. presses a button). Finally, they also force the view to refresh whenever it should be updated.

You have not written a controller class for this course yet. These types of classes a bit beyond the scope of this course. However, you are welcome to look at the source code to understand them better.


Assignment Source Code

Now that you roughly understand the model-view-controller-pattern, it is time to look at the program source code. You should download the zip file A3.zip. Unzip this file and put the contents in a new directory. This zip file contains the following classes:

JManApp.java
This is the primary class for the application. It initializes all of the objects in this application, and links them together (e.g. makes them fields of each other so that they can "talk to each other"). It also has methods that perform actions when you click on the buttons in the application.
In our application design, this is a controller class.
JManFrame.java
This is a subclass of JFrame with buttons, panels, and other features. It does not do anything with the buttons; it just arranges them on the screen, while JManApp has the methods that perform actions when they are clicked.
In our application design, this is a view class.
Piece.java
Instances of this class the game board, with all of the pieces described above. It has methods for accessing the various pieces, as well as moving them about the board.
In our application design, this is a model class.
Piece.java
Instances of this class represent a element on the board in the game. It includes information such as the type of piece, its color, and its position.
In our application design, this is a model class.
JMan.java
Instances of this class represent the player controlled JMan; it is a subclass of class Piece.
In our application design, this is a model class.

All of these classes are explained in more detail below. You will only need to modify (and extend) the Model classes. The controller and GUI classes are already completed for you, as they are beyond the scope of this course. At the end of these instructions, we point you to some resources if you wish to learn more about building a graphical application in Java. We urge you to study this material, but you do not have to.


Running the Application

In order to run the application, the only file that you need to open in DrJava is JManApp.java. This is the primary controller that starts the application and initializes all of the other objects. If you compile and use this in DrJava, DrJava will automatically use the other classes behind the scenes.

To run the application — once you have opened and compiled JManApp.java — type run JManApp in the Interations pane. The window will pop up. It will look a lot like the image above, except that the board is now completely black. That is because there are no pieces in the game yet; it is your responsibility to add these.


J*Man Code Organization

Now that you are introduced to the concept of model-view-controller. We can review how these classes all fit together.

Class JManApp

This is the primary class for running the application, and is the only one that DrJava needs to open (though you will want to edit all of the Model classes). When you run it, Java invokes the static method called main() located in this class.

When run, JManApp creates instances of all of the other classes with new-expressions. It also puts them in fields so they can "communicate" with one another (e.g. call each other's methods). JManApp also "listens" to button clicks; when a button click happens, it instructs the board to rearrange its pieces and then requests the view to draw itself again. This update-then-draw functionality is a classic example of what a controller does.

Class JManFrame

This class is a subclass of JFrame, which is associated with a window on your monitor. It is a somewhat involved class because it lays out a lot of the visual components. The primary thing to pay attention to is the fields. It has fields for each of the buttons as well as a panel for displaying the board.

As a view class, this class does not tell the application what to do with these buttons. Instead, you should look at the method addController. This method is how we activate the buttons. Calling this method registers the instance of JManApp as a listener for each of the buttons. Once an object is registered as a listener, whenever you click on a button, the program will call the method actionPerformed() in this object.

Inside this class file you will notice that there is an additional class called JManPanel. Instances of this class as capable of drawing the board on the screenn. A class that is defined inside of another class like this is called an inner class. The reasons for using an inner class are a bit complicated (it simplifies the code in very subtle ways); take CS 2110 if you wish to learn more about this.

Class JManBoard

Instances of this class store a 2-dimensional array representing the state of the board. While this array is a private field, this class has methods for accessing the elements of the array. It also has methods for checking if a space is occupied, and moving a piece from one location to another.

The most important method in this act(), which instructs the board to update after user input. Most of the code that you will write in this assignment will be part of this act() method. This method also illustrates a bit of subtlety with our MVC pattern. This method is the one "controlling" the game, moving the pieces about the board; why is it not within a Controller class? That is because it is not an immediate response to user input. A controller is generally limited to methods that process user input, such as a button press. This method updates the state of the board, making it more like a setter or getter function.

This class is almost completely finished for you, with the exception of the method placePiece(), which you will complete on your own. However, this is a very, very important class, and we advise you to study the class in detail. In particular, you should look at the following methods:

  1. Function isOnBoard().
  2. Function isEmpty().
  3. Function pieceAt().
  4. Procedure act().
  5. Procedure placePiece().

For all of these methods you should read the specifications in detail. Then you should look at their bodies (except for placePiece, which is unfinished) to get a better understanding of how they work.

Classes Piece and JMan

The board needs to contain pieces and we need objects to represent those pieces. All objects on the board are instance of the Piece class. This is a model that contains the color of the piece, its position, and its type. The type is encoded as an integer corresponding to one of the named constants in the class Piece. As with Board, this class also has an act() method to perform updates on the piece.

You will note that the act() in class Piece is abstract. This is because each particular pieces (J*Man, obstacles, walkers, pillars) all behave differently, and need their own walk method. Therefore, it seems pointless to put an act() method in Piece.

However, we need some act() method in Piece for the purpose of apparent (i.e. static) type. The JManBoard needs to store all of the pieces in an array, and it needs to instruct them to act. Because the array needs a type, JManBoard uses type Piece, as every board piece will be an instance of a class that is a subclass of Piece (for example, JMan). As we saw in class, the legality of method calls depends on the apparent type, not the real (i.e. dynamic) type. Hence we put an act() method in Piece to make the method calls legal, but we make it abstract with the understanding that the subclasses are responsible for implementing it.

We have already start you off with one of these subclasses: JMan. However, it is incomplete. A large part of this assignment will be finishing JMan, as well as creating several other classes.


Assignment Instructions

Throughout this assignment, you should not need to modify either JManApp or JManFrame. Instead, you will focus on the other classes (JManBoard, Piece, and JMan), as well as writing a few new ones on your own.

We suggest that you complete the instructions below in the order provided. We find that it is the simplest way to approach the assignment and allows for the most testing. However, if you are comfortable with the assignment you are free to pursue it in any order that you wish, such as completing the method act() in JMan before creating the new classes.


Testing Guidlines

Before you get started, you should have an organized testing plan. If your program does not work properly, we will send it back to you and you will be forced to fix it. It is best that you get it right the first time.

You are welcome and encouraged to write JUnit tests — just as you did for the class Rhino — for each of the classes that you work on. Model classes are very natural classes to use for unit tests, as they do not (directly) involve any user input that would be difficult to test. However, this is not required, and we do not want you submitting any JUnit tests for grading. We will simply grade your assignment based on how well it works, not on how you tested it.

If you do not want to use JUnit tests, simply playing the game may suffice. But keep in mind, the less testing you do, the more likely we are going to send it back for revisions.


Finish Class Piece

The very first thing you should do is finish the class Piece. You will notice that it has no fields and all of the constructors and methods are all stubs. You need to add the appropriate fields, and fill out the bodies of the constructors and methods. The only method that should not have a method is act(), which is abstract.

Do not forget to use comments to specify the class invariants (e.g. the properities of the fields). Class invariants for private fields are specified with single-line comments, not JavaDoc comments.


Complete the Constructors to JMan

The constructors in the class JMan are also stubs. Complete them, using a a call to the super-class constructor in each case. You should only need one line to implement each constructor.

With that said, you might find it tricky to implement the first constructor for JMan in one line. The constructor in Piece takes a color, not an int. Therefore, it would appear that the right way to write the JMan constructor is as follows:

if (c == 0) {
    super(Piece.JMAN, x, y, Color.red);
} else if (c == 1) {
    super(Piece.JMAN, x, y, Color.green);
} else {
    super(Piece.JMAN, x, y, Color.yellow);
}
However, this does not work. The call to super must be the very first line in the constructor. Therefore, you need to figure out how write the code above as a single call to super. Perhaps using conditional expressions (e.g. a ? b : c)?

You do not need to complete the act() method yet. We will come to that later.


Fix placePiece()

If you run the game, you will see that you still have a black screen. That is because, even though you have filled in (most of) the methods of Piece and JMan, the game still does not add any of the pieces to the board.

Fix placePiece so that it handles (only) the case of parameter t being Piece.JMAN. You should read the specification of placePiece carefully to figure out how to do this. Now, when you evaluate run JManApp in the interactions pane, you should see a board with a J*Man in its upper left corner (position [0, 0]).


Add New Pieces

According to the rules of the game, you will need three more types of pieces: walkers, pillars,and obstacles. You need to make a class for each one of these. They each should be a subclass of Piece and should return the appropriate value for getType(). Look at your implmentation (so far) of JMan to see what we are looking for.

At this stage of the assignment, you should just focus on the constructors and toString(). The act() method can and should remain as a stub, just as it still is in the class JMan. In writing the constructors, make sure to specify them properly; look at the specifications of the constructors in JMan as examples.

For the method toString, you should look at the one we have written for you in class JMan. This method can be invaluable in debugging. For example, you can find information about a piece p simply by executing System.out.println(p).

When you are done with these new classes, it is time to test them. You can test them either by a JUnit test, or proceeding on to the next step.


Complete placePiece()

Fix placePiece in JManBoard so that it handles parameter t being any one of the new types of piece (e.g. walker, pillar, obstacle). Now when you evaluate run JManApp, you should see that kind of pieces appearing on the board. While you will not be able to do anything with them, you should be able to get some feel as to whether or not they are being placed correctly. Do you have the right number of pieces (10 walkers, 10 pillars, 20 obstacles)? Do you have a reasonable ratio of colors?


Complete act()

The final step is to complete the method act() for all four of the Piece subclasses: JMan, Obstacle, Walker, and Pillar. You might wish to do JMan first, but that is the hardest act() method to write and is best left to the end. In fact, you might notice that we have stubbed in a few extra method in JMan to help you write the method act().

For the other classes, you should pur in a good specification for the procedure act(); look at the one we give you for JMan as an example. Then write the method body. Look again at the rules above to see what each piece should be doing in its act() method.

The classes JMan and Walker require special attention. You have to account for moving in one of four directions: up, down, left, and right. You should not have essentially duplicate code four times, once for each direction. That leads to a long, unwieldy, difficult-to-debug and maintain method. Instead, your code should do the following:

  • Calculate the coordinates of the proposed position (px, py) to move towards.
  • Process the proposed move to (px, py).
If you do not write your code this way, you will be required by the grader to change it later.


Finishing the Assignment

You have now completed the assignment. In order to test that everything is working properly, you should play the game. Start the game and see what happens to the pieces when you click an up, down, left, or right button. For walkers and J*Man, be sure you try all possibilities. Try to move off the board in any direction; try to move to an empty square; try to move to an occupied square.

If you are happy with the game, go back and look at the source code in all of the .java files. Make sure that you have satisfied our style guide. This includes the following:

  1. All lines should be short enough that horizontal scrolling is not necessary (~80 characters).
  2. There should be a blank line before the specification of each method and none after the specification.
  3. The class invariants should be there (e.g. you have listed constraints for all the fields).
  4. The specifications for all of the methods should be complete.
  5. The files all should be properly indented.
To ensure the last one, select an entire .java file and hit tab; DrJava will then auto-indent for you.

Turning it In

To make grading simpler, we want you to submit all of the files, including those that you did not modify (e.g. JManApp.java and JManFrame.java) Put all of the .java files in a folder and produce a ZIP file called a3jman.zip. Upload this ZIP file onto CMS by the due date: Friday, March 1st at 11:59PM

As before, check the CMS daily until you get feedback from a grader. Make sure your CMS notifications for CS 1130 are set so that you are sent an email when one of your grades is changed.


Addendum: Building Graphical Applications in Java

The best place to learn about building GUIs in Java is to read/listen to lessons 17-1 to 17-4 of the CD ProgramLive. You already know that a JFrame is a window on your monitor. Lesson 17-1 tells you how you can add components to the JFrame, like buttons and text fields. Lesson 17-2 then shows you the basic components that one can add to a JFrame, and for each one, you can download the code for the demo. Lesson 17-3 then tells you about layout managers, which are used to put components in various positions of a JFrame. Finally, lesson 17-4 shows you the basics of "listening" to actions, like a click of a button.

With these lessons, in less than 1.5 hours, you can have a good idea about how GUIs are used. It is then fairly simple to look at a view class like JManFrame and see how the GUI is constructed. Note that GUI is laid out in the constructor, as we want the GUI to be complete as soon as the view class is allocated. We use Box objects as our layout manager to make everything line up. The view class also packs the frame, so that everything is the right size, and puts it in the right position.

Note, however, that the view is not immediately visible. That is because we have not yet registered listeners with the buttons; the view would not work properly if made visible too soon. To implement the listeners, we rely on the controller class (e.g. JManApp). In the MVC pattern, the controller class creates the instance of the view class, and not vice versa. So the controller class has to pass itself to the view class in order to register listeners. This is done in the method addController. We could have done this in the constructor (by adding a parameter for JManApp in the constructor). However, since we need to add and remove listeners every time we create a new game, we decided to make it a separate method. Only after this method is called are we ready to make the window visible.

If you are interested in learning more about creating graphical applications in Java, you should take CS 2110.

About the MVC Pattern

We should mention that our approach to the MVC pattern is not the only one. In particular, we used an MVC pattern with lightweight controllers. Our controller is only used for initializing the application, and receiving user-input events (e.g. button presses). However, there is the alternative approach of using heavywight controllers. In this approach, the models would never have anything other than getter and setter methods, while the act() methods would be part of the controller.

Why would we ever do this? In a game, the actions of a piece or a character can get quite complex. A character might lack certain abilities — such as swimming or a double-jump — until getting a power-up. Instead of trying to code every single possible ability in the class to begin with, it is easier to put these abilities each in separate controller classes and apply them to the player as necessary. This is a style of programming known as Aspect-Oriented Programming, which is covered some in CS 3110. Additionally, many of these topics are covered in CS 3152, the game design course.