p2-tefball

EECS 285 Project 2: Tefball

Project Due Friday, 19 Oct 2018, 8pm

For this project, you will implement a simple game called “TefBall” (tef = two eighty-five). The game has some remote resemblance to American football, but is very simple in comparison. No knowledge of football is necessary to be successful on this project.

TefBall is played on a rectangular field. The game consists of multiple objects on the field, including a ball, and some number of players. All players progress through the game via a function named performMove() – however, different types of players act differently, so this project will utilize polymorphism to provide multiple implementations (ways to move) for a common interface (the performMove() method). The primary focus of this project is the use of polymorphism, so be sure not to try to circumvent the use of it during your design. If you do not make good use of inheritance and polymorphism as expected, you will not receive credit for your project. The goal of TefBall is to successfully throw the ball and have a receiver catch it without being caught by a defender.

Authors

The original project was written by Andrew M. Morgan for EECS 285.

Table of Contents

Project Roadmap

This is a big-picture view of what you’ll need to do to complete this project. Most of the pieces listed here also have a corresponding section later on in the spec that goes into more detail.

This project will be autograded for correctness, and the correctness portion is worth 80% of your project grade. We will also hand grade it for both programming practices and the comprehensiveness of your test cases, which will be worth a total of 20% of your project grade.

You may work alone or with a partner. Please see the syllabus for partnership rules.

Download the starter code

The starter code is available at https://eecs285.github.io/p2-tefball/starter-files.zip. The following files are included:

File(s) Description
PlayingField.java Game driver – implements the game simulation
PlayTefball1.java
PlayTefball2.java
Command-line interface, intended as test code
PlayTefball1.correct
PlayTefball2.correct
Correct output from running the test code

Extract the files to a temporary directory.

Set up your project

Follow the Project 1 setup tutorial to set up your project. Use the package name described below.

Your Java files should all be in a package with the structure eecs285.proj2.<uniqname>, where <uniqname> is your uniqname. If you are working in a partnership, then use both of your uniqnames, in alphabetical order, separated by an underscore. For example, if I am working alone, I would put the following package directive at the top of each .java file:

package eecs285.proj2.akamil;

If I am working with schatzju, then I would use the following:

package eecs285.proj2.akamil_schatzju;

Familiarize yourself with the game rules below

Read through and make sure you understand the rules for Tefball before writing any code.

Familiarize yourself with the required interface

Your implementation must adhere to the required interface described below.

Design, implement, and test your classes

Implement your game simulation in the PlayingField class that is part of the starter code. Define the other parts of the required interface and any other classes you need and place them appropriately as standalone classes in their own .java files, nested classes, or anonymous classes.

Submit

Submit the following files to the autograder.

As per course policy, we will grade your last submission to the autograder. It is your responsibility to ensure that your last submission is complete.

Game Rules

Player Types and Descriptions

There are only three types of players in this version of TefBall, and they are described below. Each specific type of player must inherit from a more generic class that represents any player, regardless of type. You should put attributes and functionality that apply to all players, regardless of type, in the base class, and attributes and functionality that apply only to specific types in the appropriate subclass. You should avoid placing functionality that doesn’t apply to all subclasses in the base class.

Quarterback

The quarterback is the player that has possession of the ball at the start of the game. In TefBall, there is exactly one quarterback, who acts in a very specific way. First, the quarterback starts at a specified location, and upon starting the game, moves toward a specified final position while holding the ball (that is, the ball moves with the quarterback at the beginning of the game, until thrown). Upon arriving at the final (actual floating point, non-rounded) position, the quarterback throws the ball to a pre-determined specified location. After throwing the ball, the quarterback stops moving and is no longer a factor in the game.

Receiver

TefBall allows multiple receivers to play at the same time. Each individual receiver starts at a specified location, and upon starting the game, moves toward a specified intermediate position. Upon arriving at the intermediate (actual floating point, non-rounded) position, the receiver changes direction and moves toward a specified final location. When a receiver arrives at the final location, they wait there, without further movement.

Defender

TefBall allows multiple defenders to play at the same time. A defender starts at a specified location, and upon starting the game, moves toward the quarterback’s current location. Once the quarterback throws the ball, the defenders change their strategy and begin running to the location that the ball is being thrown to (i.e. the ball’s destination).

Progression of the Game

As the game progresses, the user is shown a view of the field. Players and the ball move in a continuous way (i.e. their positions, and destinations are maintained and calculated as double-precision floating point values). However, when the field is drawn to the screen, an object in the game (ball or player) is drawn at the nearest (integer rounded) row and nearest (integer rounded) column. If two objects occupy the same row and column, the object that moved last is the one that is displayed. Since we are using polymorphism, players will move in the order they were specified by the user. The order that players move is an important strategy in TefBall, since if a defender moves before the quarterback moves and ends up occupying the same space, a sack will have been made. However, if the quarterback moves first, the quarterback may have moved to a different location before the defender arrives, and when the defender moves, they are occupying different spaces. Due to this, you must ensure that players move in the order specified – it is not acceptable for all receivers to move first, followed by all defenders, etc.

Before the ball is thrown, its position is the same as the quarterback’s, as described above. Starting the turn after the ball is thrown, the ball moves to its destination in each turn before any other players move.

Before a “turn” of the game, the current state of the field is drawn to the screen as shown here:

 0123456789012345
0----------------
1--------Q-------
2----------------
3----------------
4----------------
5--------D-------
6----------------
7---------B------
8----R-----R-----
9----------------
0----------------
1----------------

Note: Column and row indicators are provided to allow easy determination of game object positions. The indicators are just the last digit of the 0-based column or row index

Field elements are printed as follows:

After the field is printed, each object in the game will perform a move. If, at the end of the turn, the game is still ongoing, play continues with another turn.

Ending the Game

All objects in the game continue to move as described above. The game ends when one of the following conditions occurs in your program:

Note that games don’t only end when a full “turn” is complete. The game can end whenever any of the above criteria is met, even if some objects have not yet moved.

User Interaction

There is no user interaction for this project. Instead, we have provided two test files, PlayTefball1.java and PlayTefball2.java, that contain main() functions used to to test the other classes. You should develop your own test files as well – the provided ones do not fully test your program. When grading, we will utilize PlayTefball classes that cover a wider range of test cases, so be sure to develop your own tests to ensure your implementation performs as expected in all cases.

We have also included the expected output from running the two test files. Your implementation must match the output exactly. Use the command-line diff tool or an online diff checker to make sure this is the case.

Error Handling

In an attempt to make this programming project less work, most error handling will not be required. You can safely assume we will not test your program with the following cases:

Some error checking is required, though. Specifically, in order to play a game of TefBall, the user (the person who wrote the main() function) must add exactly one quarterback and exactly the number of players they indicated would play in the playing field’s constructor. These criteria must be checked inside your implementation of the checkIsValidGame() method of PlayingField.

There certainly is a lot of error checking that could (and really should) be done for a project like this. However, you may assume that, except for the specific error checking described for checkIsValidGame(), the user will do what they are supposed to.

Required Interface

You must implement a specified interface so that users can write main() functions to test your version of TefBall. Unlike Project 1, however, you are free to make as many additional members (data and/or functions) as you need to complete the project. Some of your grade will be based on your design, so think carefully about where attributes or functionality belong, and make sure you don’t duplicate code more than absolutely necessary. When grading, we will be looking for inappropriate members, methods at the wrong level of the inheritance tree, etc. An example of an inappropriate member is having a variable called j in a class simply because many methods need a loop counter. Since that value doesn’t describe an attribute of the object at all, it should not be a member variable, even if that means declaring a loop variable in 12 different member functions.

The following is the required interface you must develop. You must follow this exactly, including class and method names. However, you may add other data attributes, methods, classes, enumerated types, etc., as needed by your implementation. The additional items you add will not be utilized directly by the author of main().

Class: PlayingField

An object of this class will be used to represent the TefBall playing field that objects in the game move around on as described. Read through the documentation in the starter code for what you should implement. You must adhere to the interface provided in the starter code.

Enum: GameResultEnum

A list of possible outcomes from a turn of Tefball. The possible values are: ONGOING, SACK, INTERCEPTION, RECEPTION, and INCOMPLETION. While the enum definition will likely be short, you must put the definition in its own Java source file named GameResultEnum.java.

Player-Type Classes: Quarterback, Receiver, Defender

You should define a class for each type of player. These classes allow you to instantiate player objects that participate in the game. Each player class has a unique implementation of a method named performMove(). You may use whatever parameters you need for this method.

Class: Some kind of base class for the different players, etc.

While the individual player type classes have different implementations of performMove() (and potentially other methods too), the interface is common across different player types. Therefore, you’ll need to set up an inheritance tree and ensure the common interface is defined at a base class level. Polymorphism must be used to a full extent in this way, as this is primary learning goal for this project.

Movement in the Tefball Simulation

All objects that move in TefBall move the same way. To move, first determine the object’s 2D vector of travel by subtracting its current location from its destination location. Next, make this 2D vector be a unit vector (with a magnitude of 1.0) by dividing the vector elements by the total length of the 2D vector. At this point, you have a unit vector describing the direction that the object will travel. Multiplying the unit vector by the object’s speed will indicate how far, and in which direction, the object could travel on its next “turn”. To ensure your objects move in the same way as the objects in our solution do, be sure to follow this algorithm when developing your solution.

Movement Example: Let’s say a Receiver starts the turn at a position of (4.0, 4.0) having a destination of (2.0, 6.0), and runs at a speed of 1.4143. The receiver’s movement would be performed as follows:

A game object never overshoots its destination. If the movement calculated above would take it past its destination, the object stops at its destination instead.

An object only performs one action in each turn. Specifically, a quarterback does not throw the ball until the turn after they reach their destination. (If a quarterback’s destination is the same as their initial location, they throw the ball their first turn, since they have already reached their destination without moving.) Similarly, a receiver does not start moving to their final destination until the turn after they reach their intermediate destination. (If the receiver’s starting and intermediate locations are the same, they don’t move toward their final destination until their second turn.)

Requirements, Restrictions, and Clarifications

Final Thoughts

This project is fairly involved, but it does not necessarily require a lot of code. There is no requirement for “number of lines of code”, but just to give you a feel, my implementation has about 300 lines of code, excluding comments and blank lines. It’s fine if you have more or less than that, but if you find you’re writing 1200 lines of code, you may be making it more complicated than it needs to be.