Assignment 5: Zombies: A METHOD to their Madness

Assignment Setup

To create your repository go here. Then follow the same accept/import process described in the setup instructions.

More Zombies… There’s a METHOD to their Madness!

This assignment is a follow-up to Assignment 4, where you wrote code that could read a data file and display entities being simulated. Here you’ll build on Assignment 4 in two ways:

  • Now that we have a new technique, methods, you’ll take your prior work and adjust it to use methods.

  • You’ll extend it with additional methods and complete the basic zombie simulator.

New Techniques & Topics

Refactoring!

Refactoring is a technique used to refine computer code. The basic idea is to restructure code without changing overall behavior. Often refactoring is done because either:

  • code is difficult to manage (too complex) and reorganizing it will make it easier to update/fix/understand or

  • new techniques provide better ways of writing the code.

Part of your work here will be easier if you just refactor some of your work from Assignment 4.

Methods!

Methods are a fundamental part of computing because:

  • They allow us to break complex problems into smaller, more manageable parts. It makes it possible for a single person to write a complex program by working on one small part at a time and ensuring that the small parts can be combined together.

  • They allow code to be re-used. In this case we will do some operations repeatedly and rather than copying/pasting code you can just write a method once (one copy of the code) and call it as-needed.

2D Array For X,Y Positions. 1D Array For Boolean Zombie State.

In this assignment, we will now use a two-dimensional array of doubles to store our coordinate data. Like before, each index (row index) will represent a single item. Rather than using different arrays for the x and y coordinates, we’ll instead use two columns of a two dimensional array. Column 0 will contain the x coordinate and column 1 will contain the y coordinate. We will still keep the zombie state in a boolean array, as it uses a separate data type.

“Magic” Numbers and Constants

The term Magic Number is often used to represent a constant value whose significance isn’t clear from the value and its context. For example, we will be storing the entities’ y-coordinates in the second column of an array, so the number 1 indicates the column containing the y-coordinates. The number 1 would be considered a “magic number” because it’s an arbitrary choice and may not be clear to someone who reads your code.

In order to make our code more readable, we’ll use special variables for the indices rather than the “Magic Numbers”. The starter code provided in ZombieSimulator.java includes:

static final int X = 0;
static final int Y = 1;

These two lines declare variables that represent the column that will contain the x coordinate and the column that will contain the y coordinate. Every time a location in the 2D array is used, these variables should be used to make your code easier to read. For example, when someone reads:

double v = positions[i][1];

it isn’t very clear that the 1 the Y coordinate (it is a magic number). The following is easier to read and less prone to errors:

double v = positions[i][Y];   // More clearly conveys reading the Y coordinate.

Of course, using a better variable name makes it even more readable:

double yCoordinate = positions[i][Y];

The lab assignment also includes:

static final String ZOMBIE_TOKEN_VALUE = "Zombie";

You should prefer the use of ZOMBIE_TOKEN_VALUE over the String "Zombie". "Zombie" could be misspelled, for example, resulting in diffilcult to debug errors. If you misspell ZOMBIE_TOKEN_VALUE, however, Eclipse and the Java Compiler will alert you to the problem, which makes it easier to debug.

The constants below will be used in drawEntities(). You may change the values, but you should reference these identifiers in your code.

static final Color ZOMBIE_COLOR = new Color(146, 0, 0);
static final Color NONZOMBIE_COLOR = new Color(0, 0, 0);
static final Color TEXT_COLOR = new Color(73, 0, 146);
static final double ENTITY_RADIUS = 0.008;

Note: collision detection in touchingZombie() will also use ENTITY_RADIUS.

Finally, updateEntities() will use RANDOM_DELTA_HALF_RANGE:

static final double RANDOM_DELTA_HALF_RANGE = 0.006;

Double Buffering

You may have noticed in Assignment 4 that it’s possible to see each individual entity being drawn. This is because drawing on the screen takes a little bit of time. When we’re running a simulation where entities are moving, however, seeing each entity being drawn will make the simulation will seem slow and jerky. Instead, we will use double buffering.

Double Buffering is a technique used to make animations look smooth. The basic idea is to have two different “frames” (the two buffers). At any given time, one frame is being shown on the screen. New drawings are placed on the other frame, which isn’t being shown. When these two frames are switched, it looks like a lot of changes have taken place simultaneously. A sequence of these changes can show an animation in the same way a flip book works (Sample Video on Wikipedia). Much like a flip book, all visible items are drawn in each frame, but the positions of items that are moving change a tiny bit from one frame to another.

StdDraw supports double buffering by the following approach:

  1. Prior to drawing anything (for example, when the the program first starts in main) call StdDraw.enableDoubleBuffering()

  2. Whenever it is time to change frames:

StdDraw.clear();  // Clear the non-shown frame
// Draw *all* objects in their locations (which may have changed from the last frame)
StdDraw.show();  // Swap the non-shown frame with the one being shown on screen.

Unit Testing

Unit testing can help find problems and add confidence that certain aspects of your program are functioning correctly. As you complete each part of this assignment, you will test that part. If all the parts work in the intended way, there’s a greater chance that they will work when combined together.

Special Note: Unit tests help developers make sure the code works, but they usually only test a relatively small number of possible conditions. NEVER assume that code that passes unit tests “must work”. The test only ensures that it did what those tests expected. The tests themselves could be flawed and they don’t test everything!

If you fail any unit test cases, you should try to read through the test case and see what it’s testing. In this assignment, almost all tests cases are either looking for a particular value (via assertEquals() or assertNotEquals() ) or for a boolean condition (via assertTrue``() or ``assertFalse()). Doubling clicking on a failing test will take you to the code for that test, where you can probably figure out what the test case is expecting and then try to identify why your code didn’t pass it. The comments in and above the test cases may also provide some guidance.

Assignment Requirements

Partial credit is possible (check the rubric), but for full credit:

  • IN ADDITION TO PASSING ALL TESTS the ZombieSimulator should run.

    • It should repeatedly update entities until only zombies remain (at which point it should stop updating)

    • It should show the results after each update

Here’s an example run (note: there is no audio):

Submitting your work

To submit your work come to office hours or class on an “Assignment day” and sign up for a demo via wustl-cse.help.

You have attempted of activities on this page