On this page:
Instructions
Practice Problems
1 Problem 1 — N Bullets
1.1 Visual Clarification
1.2 Submission format
1.3 World requirements
1.4 Ships
1.5 Bullets
1.6 Java and math
1.7 Tick-tock On The Clock
1.8 To IList or ILo?
1.9 Local variables
1.10 A note about randomness
1.11 Suggested constants
1.12 Yikes, This Sure Is A Lot!
2 Problem 2 — Courses and Prereqs
2.1 Extra Credit:   Ormap
8.10

Assignment 5: A Game, Visitors

Goals: Design a game; implement generics and visitors.

Instructions

This assignment is long. Start early.

Be very, very careful with naming! Again, the solution files expect your submissions to be named a certain way, so that they can define their own Examples class with which to test your code. Therefore, whenever the assignment specifies:
  • the names of classes,

  • the names and types of the fields within classes,

  • the names, types and order of the arguments to the constructor,

  • the names, types and order of arguments to methods, or

  • filenames,

...be sure that your submission uses exactly those names.

Make sure you follow the style guidelines that we enforce. For now the most important ones are: using spaces instead of tabs, indenting by 4 characters, following the naming conventions (data type names start with a capital letter, names of fields and methods start with a lower case letter), and having spaces before curly braces.

You will submit this assignment by the deadline using the online submission system. You may submit as many times as you wish. Be aware of the fact that close to the deadline the system may slow down to handle many submissions - so try to finish early.

There will be a separate submission for each problem - it makes it easier to grade each problem, and to provide you with feedback for each problem you work on.

The submissions will be organized as follows:

Due Date:
  • Problem 1: November 8th, 10:00pm

  • Problem 2: November 8th, 10:00pm

Practice Problems

Work out these problems on your own. Save them in an electronic portfolio, so you can show them to your instructor, review them before the exam, use them as a reference when working on the homework assignments.

1 Problem 1 — N Bullets

You are going to design a game called N Bullets, based on the game 10 Bullets.

N Bullets is a game in which ships fly across the screen and the player shoots bullets at them from the center of the bottom of the screen. When a bullet and ship collide, both are instantly destroyed. The bullet, however, is replaced by a group of bullets that fly out to hit other ships. The game ends when the player run out of bullets and no more bullets are on screen.

Your game will use the javalib.funworld library, which provides an implementation of Worlds and bigBang similar to what was used in 1114. Read the documentation carefully for more information.

1.1 Visual Clarification

To get a better idea of what we are looking for, watch this gameplay video; it’s our implementation of the game

1.2 Submission format

You may find it overwhelming to keep all of your code within one file. To make your code more managable, you may submit a zip archive for this assignment instead of a single file. If you are more comfortable submitting as a single file, though, that is also fine.

1.3 World requirements
1.4 Ships
1.5 Bullets
1.6 Java and math
1.7 Tick-tock On The Clock

This style of programming is called a fluent interface.

As you may have noticed, a lot has to happen in one tick (bullets and ships have to move, collisions need to be handled, ships may be spawned, etc.). To make this manageable, we recommend you design methods that use the current (this) world and produce a new world, where one of those steps have been taken, and a new world is returned. You can then chain those together to in your onTick method. Using this methodology, it should look something like this (with much better naming, of course):

// advance the world by one tick: do step one, then step two, then step three, // and then step four public MyTowerDefenseClass onTick() {
return this.doStepOne()
.doStepTwo()
.doStepThree()
.doStepFour();
}

An added benefit of designing this collection of methods is, of course, the ability to test each step of your code independently.

As a note of caution, beware that you’re calling dependent operations in the right order. For example, the order in which you choose to remove off-screen components and handle ship/bullet collisions could affect the results of the game.

1.8 To IList or ILo?

It is up to you whether or not you want to use the IList<T> interface we have recently covered or the ILo* pattern from earlier in the course. The former has the advantage of being able to write and re-use abstractions like foldr, map, filter, etc. easily, while the latter has the advantage of not having to write many function objects.

1.9 Local variables

You will almost certainly want to use local variables for this assignment.

Be cautious, because some programms use local variables as an excuse for not using helper methods. Remember, one task per method.

Let’s say we were computing the average of a list, and returning 0 if the list was empty:

public int average() {
if (this.length() == 0) {
return 0;
} else {
return this.sum() / this.length();
}
}

The problem, of course, is the length is being computed twice. One way to get around this would be to use a helper method:

public int average() {
return this.averageHelper(this.length());
}
 
public int averageHelper(int length) {
if (length == 0) {
return 0;
} else {
return this.sum() / length;
}
}

Why did the programmer choose to compute the sum in the helper and not in the outer method and pass it to the helper?

This is fairly verbose for such a simple operation, however. Instead, we can use a local variable:

public int average() {
int length = this.length();
if (length == 0) {
return 0;
} else {
return this.sum() / length;
}
}

This local variable could have been called something besides length.

As in ISL, local variables should be used to avoid duplicate computation, clarify what expressions mean, and contain simple computations another method wouldn’t need to use. Proper usage of local variables, also like in ISL, is a judgement call.

1.10 A note about randomness

There are two ways to generate random numbers in Java. The easiest is to use Math.random(), which generates a double between 0 (inclusive) and 1 (exclusive). You can multiply this number by some integer to make it bigger, then coerce to an int to produce a random integer in the range you wish. However, this is not easily testable: you’ll get different random values every time.

The better way to generate random numbers is: First, import java.util.Random at the top of your file. Next, create a new Random() object, and use its nextInt(int maxVal) method, which will give you a random integer between zero (inclusive) and maxVal (exclusive).

This is known as a "pseudorandom number generator", since the numbers aren’t really random if they can be reliably repeated...

The reason this is better is because there is a second constructor, new Random(int initialSeed), which has the property that every time you create a Random with the same initial seed, it will generate the same "random" numbers in the same order every time your program runs. You should therefore design your world classes with two constructors:

1.11 Suggested constants

While you are welcome to tweak the game to create gameplay you enjoy (so long as you adhere to all of the above specifications), here are the constants we used that we know will generate decent gameplay (as seen in the previously linked video):

1.12 Yikes, This Sure Is A Lot!

Yes, it is, but don’t worry, you can do it. A big part of being able to succeed with this assignment is to keep track of what data represents what, how to organize it, and what you will need to do with it. As always, sticking to the design recipe and fleshing out your wishlist in advance is the best way to go about handling daunting programs. To help you out, we’ve started an informal wishlist of tasks your program must be able to do:

All of these directly imply that your program also needs to do the following:

To begin, we recommend fleshing out this wishlist and storing it somewhere you can easily access, and determing which classes each task should belong to. Then, you can add the method stubs to each of the classes, and write examples and tests before you begin to program. Give each method its own test function, and comment them out. As you implement each method, you can uncomment that method’s test function, and that way you can test the whole program as you go.

2 Problem 2 — Courses and Prereqs

A Course has a name and prereqs, which is an IList<Course> (see Lecture 15 for the data definition of parametrized lists).

Notation: When you see notation of the form ClassName#methodName(...), it means methodName is a method defined in the class ClassName, and the arguments are left for you to determine. For example, String#substring(...).

2.1 Extra Credit: Ormap

If you plan on doing the extra credit, your submission to the handin server should either totally complete the above two items or not. Your graders will only grade one version of HasPrereq.