CSE 131 Module 7: Objects

Extensions

Extension 1: Conways Game of Life (8 points):

Authors
This is not ma and pa's old Conway; this is a new, improved, and less confusing version of the classic extension. We hope you enjoy it!
Conway's Game of Life is a biology simulation that was developed by British mathematician John Horton Conway in 1970. It is designed to simulate cellular automation by creating an initial configuration of living and dead cells and observing how they evolve. Many interesting patterns have developed from the origins of the original simulation--producing patterns that pulsate, exist into infinity, and even glide like spaceships.

The rules of Conway's Game of life are as follows:

This set of rules can end up making some very interesting patterns. Below we have drawn out some of the patterns that are made by cells in Conway's game of life. Dead cells are represented by white squares, living cells are represented by black squares.

Sample Patterns

Still Lifes

Block Block

Beehive Beehive

Loaf Loaf

Boat Boat

Oscillators

Blinker Blinker

Toad Toad

Beacon Beacon

Pulsar Pulsar

Spaceships

Glider Glider

Lightweight Spaceship Lightweight Spaceship

Perpetual Patterns

Gosper Glider Gun Gosper Glider Gun

Block-Laying Switch Engine Block-Laying Switch Engine

Directions

In this lab, you will be responsible for building the simulator portion of Conway's Game of Life (henceforth known as Conway, or Life). You can then run the game on your own patterns or on patterns that we provide.

The code for this work can be found conway package of the extensions source folder. The Conway class is where you will be doing all of your work. ConwayTest is the tester for Conway and Main is what you will run when your code is finished to actually see your work happen. The Main class creates a GUI, Graphical User Interface, which allows you to see cells dying and coming back to life. Open Conway. You will create the following methods:

  1. A public Conway(int rows, int cols) constructor that specifies the dimensions of the Conway board.
  2. A public int getRows() method, that is an accessor.
  3. A public int getColumns() method, that is an accessor
    Your code should now pass the getRowsAndColumnsTest()
  4. A public void setLiveness(boolean b, int row, int col) method that takes in a row and a column, and whether that cell should be currently alive or dead
    It would make sense that if a cell was alive, and it was represented by a boolean, it would be true, and if it was dead it would be false. You must come up with a data type that stores values in rows an columns to represent all of the cells. There are multiple ways to store this information, but think carefully about which one you choose, for this choice could save you time down the road. Just remember; you should not change anything within the test, and you must return what we ask you to return.
  5. An public boolean isAlive(int row, int col) method, which returns whether the cell at that specific row and column is alive or dead. If the row and column are out of the bounds of that Conway object, then return false.
    Your code should now pass the isAliveTest() and the setLivenessTest().
  6. A public void clear() method, which sets every cell in the Conway object to dead.
    Your code should now pass the clearTest()
  7. A public int countLivingNeighbors(int row, int col) method, which considers the cell at a certain row and column, and returns the number of living neighbors that it has.
    The neighbors of a certain cell are considered to be the eight cells that are surrounding it. Your isAlive() should help you with this.

    If you were to count the number of living neighbors of the living cell in the picture above, you would check the eight white squares that are surrounding it, and see if any of those cells were alive. In this picture, the live cell in the middle has no living neighbors, so according to the rules, it will die of loneliness. So in the next frame it will become a white square.
    This is a random group of cells
    This picture shows the number of living neighbors that each of the cells in the above picture has

    Once you implement this method, your code should pass the countLivingNeighborsTest()

  8. A public void step() method, which executes a generation of life. What this means is that you take all of the cells from the this Conway object, and determine whether or not they will be alive in the next generation.
    It might be helpful here to create a next conway object with the same dimensions as the this Conway object. If you change the values of the original Conway object while you still havent determined whether other cells will be alive in the next generation, you might not count the wrong number of living neighbors. For instance, say cell A and cell B both alive, and are neighbors. If you determine that A will be dead in the next generation, and you kill it, when you go to count the number of living neighbors of B, it will have fewer living neighbors now than it should. If you create another Conway object, you can store the liveness of ALL of the cells on that Conway object, and then alter the values of the this Conway object at the end.
    If a cell will not be alive in the next generation, set it to false. If a cell will be alive in the next generation, set it to true. Make sure to account for all cells, and not just the ones that are currently alive. The rules of the Conway Game of Life are listed at the top of this page. This is where you will implement those rules.
    Your code should now pass the stepTest()
In the code, we have public void yourDesginOne() and public void yourDesginTwo(). You do not have to fill these out for the code to work, but if you want to create a pattern, you can create it here, and you will be able to access it through the GUI. These will be used for the next extension The following methods are provided for you, do not change any of these:
  1. public void blinker() allows the GUI to create a blinker pattern
  2. public void fourBlinkers() allows the GUI to create a four-blinker pattern
  3. public void gosperGliderGun() allows the GUI to create a gosperGliderGun pattern
  4. public void glider() allows the GUI to create a glider pattern
  5. Other supporting classes, including the visualization code, are in the labsupport source folder. They are moved there to reduce the clutter in the extensions folder.
There is also an empty public void logAndCapture() method. You do not need to put anything in here right now, this is the subject of the next extension

Once you have completed all the methods, you can run the Main method to play Conway's Game of Life. There are many patterns that can be used to test your simulation, some of which can be found here.

To further debug your code, the visual interface allows you to take one step at a time. If the game is not working, use the debugger or print information helpful to diagnosing the problems you see.


To Demo

Your code must pass all of the unit tests, and the GUI should work, and be able to display cells interacting with eachother.
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.1
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 1


Extension 2: Conways Game of Afterlife: Automatic generation (3 points):

Authors
For this extension, you will be working with automatic code generation, which will save you time and energy if you want to save any of the cell mappings you create in Conway. In order to get credit for this extension, you must implement the functionality of logAndCapture() in Conway to capture the current living cells you have on the board and generate the appropriate Java code for creating those cells in the console.

For example, the Four Blinkers code is captured already, but if you were to generate code for it using logAndCapture() the result would look something like this:

Beginning of Log and Capture
setLiveness(true, 1, 1);
setLiveness(true, 1, 2);
setLiveness(true, 1, 3);
setLiveness(true, 1, 5);
setLiveness(true, 1, 6);
setLiveness(true, 1, 7);
setLiveness(true, 5, 1);
setLiveness(true, 5, 2);
setLiveness(true, 5, 3);
setLiveness(true, 5, 5);
setLiveness(true, 5, 6);
setLiveness(true, 5, 7);
End of Log and Capture
The idea is that the code can be copied from the console, pasted into your Conway class, and when you choose the right menu item from the interface, the board will be initialized to replicate what you captured.

Once you have logAndCapture() working, use this new tool to automatically generate your own Conway patterns in myDesignOne(), myDesignTwo(), and myDesignThree(). For credit for this extension, these patterns should be both intriguing and potentially time-consuming to generate by hand.

When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.2
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 2


Extension 3: Project: Matrix (5 points):

Authors

Procedure

In the matrix package of the extensions source folder, implement the Matrix class. Every time you implement a method correctly, you will be able to pass one more unit test. We have provided and finished some methods. We ask that you do not change anything other than the methods listed below. Implement the methods with the following features:
  1. A constructor that takes a two-dimensional array of type double and saves it (as an instance variable) as the values of the matrix.
    To be safe, your instance variable must be a copy of the parameter, so that the contents of your Matrix's array cannot be changed beyond your control.

    To copy the two-dimensional array, you must instantiate a new two-dimensional array and copy the original array's contents into your new array. Do not use clone. It will only clone the first row of the array, and the rest of the rows will be left empty

  2. An arraysAreEqual(double[][] one, double[][] two) method that compares the two arrays to see if they are the same. The two arrays are the same if:
    The .equals(Object) method included with this lab calls your arraysAreEqual method, so that Matrix equality of two matrices depends on the contents of those matrices.

    Until this method is working, the rest of the JUnit tests will not work properly.

  3. A toString method that neatly shows the contents of the matrix. In your string use "\n" to insert a line break, and use "\t" where you want a tab between elements. Include JUnit tests that print these strings to the console (using System.out.println) for visual inspection, in addition to any automated tests you perform. Your toString method will come in handy for debugging the other methods.

  4. A scaleRow method that takes a row number (an integer) and a scale factor (a double), and multiplies that row by the given scale factor. This method does not return anything. It just modifies the matrix.
    In this lab, rows are numbered as arrays are indexed. Thus, the top row in the matrix is row 0, and the bottom row is numbered one less than the number of rows in the matrix.

  5. An addRows method that takes two row numbers as parameters, and adds the two rows together, storing the result in place of the second of the two rows.

  6. A plus method that takes another Matrix as its parameter and returns the matrix that results from adding this matrix by the given one. Matrix addition is only valid when the two matrices are the same size in both dimensions, so your plus method should throw an IllegalArgumentException when this is not the case.

  7. A transpose method that takes no parameters and returns a new matrix that is the transpose of this one. Recall that the columns of the transposed matrix have the same values as the rows of the original matrix.

  8. A times method that takes another Matrix as its parameter and returns the matrix that results from multiplying this matrix by the given one. Recall that when you multiply two matrices A and B, the value in the cell at row r and column c of the resulting matrix is the dot product of A's row r with B's column c. Also recall that matrix multiplication is only valid when the number of columns of the first matrix is equal to the number of rows of the second, so your times method should throw an IllegalArgumentException when this is not the case.

  9. An exchangeRows method that takes in two rows i and j and exchanges the two. This modifies the matrix and does not return anything.

To Demo

Your code must pass all of the unit tests
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.3
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 3


Extension 4: Gaussian Elimination (6 points):

Authors

Directions

You will create a Gaussian class in the matrix package. Inside of it you will have a public Matrix getSolution() method that solves a series of equations by Gaussian elimination as described in this Wikipedia article. you must do the following:
  1. Create a constructor in the Gaussian class that takes in two matrices, a three by three matrix that represents the constants in the set of equations, and a three by one matrix that represents the sums
  2. Write a public Matrix getSolution() method that takes a certain Gaussian object and finds the solution of the system of equations that it represents. HINT: all of the inputs will be doubles, but you can assume that they will be whole numbers
    For instance: if we have the system of equations:

    3x + 10y - 4z = 27

    2x - 3y + 2z = 7

    -x - y + z = 0

    We know that the matrix for the coefficients looks like

    [3][10][-4]

    [2][-3][2]

    [-1][-1][1]

    And the matrix for the sums looks like

    [27]

    [7]

    [0]

    Since the solution to this particular system of equations is x = 3, y = 5, z = 8, the solutions matrix would look like

    [3]

    [5]

    [8]

    You can also assume that there will only be one solution to the system of equations that we provide to you.
    NOTE: Your solution to this extension must be a general one. In other words, it cannot be restricted to solving 3x3 (or 3x4 if you count the constants column) matrices. It must be able to solve systems of equations with arbitrary numbers of parameters.

To Demo

You must pass the GaussianElimination unit test.
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.4
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 4


Extension 5: Gone Golfin' (7 points):

Authors
Issues: Move this extension earlier because it's relatively easy from a design and object point of view.

Overview

In this extension you will build a golf game where the player can putt the ball into the hole with a mouse click. Your golf game will use the Point and Vector classes you developed in lab.

Make sure to import the correct Point and Vector classes from lab!

Procedure

In the golf package you will find four classes:

Green
The Green is where the Ball and Hole reside.

When you have finished writing this class, run the TestGreen unit test.

Hole
The Hole is the goal.

When you have finished writing this class, run the TestHole unit test.

Ball
The Ball object represents your golf ball.

When you have finished writing this class, run the TestBall unit test.

Game
The Game is where it all comes together.

One crucial part of this extension is figuring out how to grab the mouse coordinates. Remember that StdDraw has built-in methods you can use to your advantage, namely StdDraw.isMousePressed(), StdDraw.mouseX(), and StdDraw.mouseY().

Hint:
while(!StdDraw.isMousePressed){
     //here we know nothing has happened...
}
//mouse must have been pressed here!
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.5
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 5


Extension 6: Julia Sets: Fractal Images (10 points):

Authors
Issues: Needs a careful editing

Overview:

Fractals are mathematical models that can create seemingly complex drawings from very simple specifications. Because they are not easily bored, computers are well-suited to iterative tasks. You will use iteration in this lab to compute a fractal drawing. This lab emphasizes how computation can be applied with relative ease and speed to create what would take a human much longer to accomplish.

Before Starting:

  1. Update your workspace and look for the julia package in the extensions source folder. To run the program, run JuliaController as a Java application.
  2. Please read over the entire document before you start. Really. It will save you time in the long run.
  3. If you are interested, see the wallpaper a student made from this lab. You can change constants and colors to get different patterns.

Background Information:

Fractals are an amazing mechanism for describing complex systems in terms of simple and recursive components. The idea of fractals in the complex plane (where the x coordinate is real and the y coordinate is imaginary) dates back to 1918, when Gaston Julia began research that characterized Julia Set fractals. In 1979, Benoit Mandelbrot defined a map over Julia sets that reflected the expense of computing a specific point in the set. Such maps generate interesting patterns, and we will in a sense reproduce Mandelbrot's work in this lab. Since Mandelbrot's original work, computers have become faster and Java has made programming them easier. Thus, our renditions will be more aesthetically pleasing (and won't take overnight to render either).

Problem statement: Drawing a Julia Set

This lab involves computation over some points of a complex plane. Recall that a complex number has two components: a real and an imaginary part. For each complex point c (which we will display on a cartesian coordinate system) that we want to display, we compute a function rigor(c). This is an important formula when considering Julia sets, but for this extension, we will use it to compute what color we will make a certain point.

Code for rigor(c):
   Complex z = new Complex(-0.7795, 0.134);
   int iters = 0;
   while(c.abs() < 2 && iters < this.IPP) {
      c = c.times(c).plus(z);
      iters = iters + 1;
   }
   return iters;

In this formula, z is a constant that is chosen so that the colors of this Julia set come out a certain way. Once you finish this lab, you can experiment with different values of z to try to find new images.

In other words, rigor(c) is the number of iterations that it takes to compute the value at c. The value of IPP is arbitrary, but let's assume for now that 100 iterations are allowed for the computation. The function abs(z) computes the distance of z from the complex point (0,0).
The IPP is the Iterations Per Pixel. If you change the IPP, the budget for each pixel will be larger, which means that the code will spend longer computing each point. The rigor(c) function iteratively calculates what color a pixel will be by executing the above code, but sometimes certain points on the complex plane take an arbitrarily large amount of time to measure, so instead of letting your computer run for an arbitrarily large amount of time, you will cap the function when you reach a certain number of iterations.

To show complex numbers on an x-y axis system, let us assume that the real component of a complex number is registered on the x-axis; the imaginary component is thus registered on the y axis. If we apply the above computation over the complex plane as x ranges from -2 to 2 and y ranges from -2i to 2i, we obtain the following picture:


(-2, 2i)(0, 2i)(2, 2i)
(-2, 0i) (2, 0i)
(-2, -2i)(0, -2i)(2, -2i)
Figure 1: Initial display

The black areas represent points whose computation exceeded the limit set above (IPP).

In the figures shown in this write-up, the color of a pixel p is computed as follows, based on the value of iters that was computed for the Complex coordinate associated with p:

Color color = Color.black;
if (iters < this.IPP) {
   // If you feel like changing the color, play with this line
   color = Color.getHSBColor((iters % 256)/255.0f, 1.0f, 1.0f);
}
StdDraw.setPenColor(color);
//
// Draw a point
//
StdDraw.filledCircle(realCoord, imaginaryCoord, .00001);
The rigor(c) function gives you the value of iters. You entered a certai complex coordinate c, and this function gives you the color of that coordinate. So the last line of this code draws a tiny circle at that complex coordinate of the color that was given by the rigor(c) function
The above code uses the HSB color model. For more information, consult the Color.getHSBColor documentation. The basic idea is to pick a hue based on the number of iterations, but leave the brightness and saturation at full.


Note the complex coordinates of the lower-left and upper-right corners.
We use those two corners to describe the currently viewed area of the display.
Zooming in, zooming out, and the selection of a box all affect those two corners, which in turn frame the display that is shown.

Zooming around

What is really interesting about a fractal drawing is that one can dive into the drawing and discover ever increasing detail. Below you see the results of zooming into the picture.

(-1.6, 0.5i) (-0.6, 0.5i)
(-1.6, -0.5i) (-0.6, -0.5i)
(-1.51755, 0.063544i) (-1.51210, 0.063544i)
(-1.51755, -0.0690i) (-1.51210, -0.0690i)
Zoom in on left part of picture Another zoom in on left part of picture

Procedure

We will be printing out one part of a large function defined on the complex plane. We will start out by showing the function from (-2, -2i) to (2, 2i). When we zoom in, we will look at a different section of the picture.
Remember the z value that we gave you for the rigor function beforehand? Here are some values of z that will give you interesting designs: These are actually all points on the graph of the Mandelbrot set whicch is a complex graph of Julia sets.
This picture should be the result of you pressing the Test 1 button
This should be the result of you pressing the Test 2 button
This should be the result of you pressing the Test 3 button

To Demo:

The JuliaController should work, and your ta should be able to verify that all of the test buttons do everything that they should.
For more information about the Mandelbrot set and Julia sets, try this Youtube video or this web page.
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.6
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 6


Extension 7: Objects to Support Music (9 points):

Authors

Overview:

There are several extensions that involve the use of music. Without some nicely articulated objects in place, the code for those extensions would become unwieldy.

This extension involves your completing some classes that have already been designed. Each class has an API described here and in the class's JavaDoc comments. A JUnit test case is written both to help you create a correct implementation of the design and to demo your work for credit.

Before Starting:

Development Sequence

Some general guidelines follow:

OK, now follow the steps below, in order, to develop the classes for this extension:

  1. Open the Samples class as we will complete this class first.
  2. Take a look at the first constructor in Samples–the one whose signature is Samples(double[]).

    A Samples object has-a double array of samples. This constructor takes in such an array, and the constructor must capture the array by making a copy of its values to be retained as an instance variable.

    This is a bit unusual: you would normally capture an instance variable val by writing this.val = val, but for an array, that would retain the reference to the array without copying its values. While the reference is sufficient to access the array's values, there is no guarantee that code outside the Samples class won't change the array after the constructor returns.

    To guard against this, your constructor must make a copy of the array's values. As a reminder, this involves:

    1. Declaring the instance variable to be an array of double values.
    2. In the constructor, instantiating the array the be the same size as the parameter array's size.
    3. After instantiating the array, writing a loop to copy the values one-by-one from the parameter into the instance variable copy.
    The testConstructor1() test will not pass until you have also completed getNumSamples() and getSample(int i), so once you have completed the constructor, we advise that you complete these two simpler methods before unit testing again.

  3. Implement the double getSample(int) method, which should return the value of sample i. Note that getSample(0) returns the first value, because (like most things in Java), we begin our samples at index 0.
  4. Next complete the getNumSamples() method by returning the length of the instance-variable array of samples.
    Run the unit tests, and the testConstructor1() unit test should pass at this point, as well as the getNumSamples() unit test

  5. The second constructor for Samples has signature Samples(int). It does not accept an input array, but instead it should instantiate the instance variable to be an array of the specified length, all zero. Such an array is not not directly useful or suitable for play-back, but is useful as a base for composing or extending other samples. Java does initialize all newly instantiated double arrays to zero automatically.
    This constructor also requires getNumSamples() and getSample(int i) to be completed before it will pass testConstructor2

  6. Complete the play() method by having Sedgewick's StdAudio class play the instance-variable array of samples.
  7. Complete the toString() method to return a useful string to describe the contained samples.

  8. Complete the getMax() and getMin() methods so that they do what their comments say they should do.
    Run the unit tests, and the testMax() and testMin() unit tests should pass at this point.

  9. Complete the concat(Samples) method, which takes this sequence of samples and an other sequence of samples and return a new sequence that is the concatenation of the two. Note that this must return a new Samples object. The current object must not be changed!
    Run the unit tests, and the testConcat() unit test should pass at this point.

  10. Complete the combine(Samples) method, which takes this sequence of samples and an other sequence of samples, and sums them, element-by-element, to form a new sequence of samples. If one sequence is shorter than the other, it is as if the shorter sequence had zeros as the sums are computed.
    Run the unit tests, and the testCombine() unit test should pass at this point.

  11. OK after all that work, open Pitch and you will see that this class is done for you.
    Run the PitchTest unit tests, and they should pass at this point.

  12. Open the SingleTone class. A SingleTone has-a frequency which should be retained as a double.
  13. Complete the constructor for SingleTone.
  14. Complete the method getSamples() by generating samples at the specified amplitude and duration. Recall that a SingleTone has-a a frequency, so the frequency used for the samples should be stored as an instance variable in your class.
  15. Complete the getOverTone(double) method, which returns a new SingleTone object whose frequency is the specified mutliple of this one's frequency.
  16. Complete the getOverTone(int,int) method, which should return its result by reduction to the getOverTone(double) method. This means that you should return the result of getOverTones(int,int) by returning a suitable call of getOverTone(double).
    Run the unit tests, and the testOvertones() unit test should pass at this point.

  17. Open DiatonicScale. This class represents notes that form a major scale, such as the natural (usually, white) keys do on a piano. A DiatonicScale has-a starting Pitch, which should be retained as a Pitch reference.
    We could have designed this class to retain the starting pitch as an integer, but with the richer object Pitch we should use it instead.

    Why?

    A Pitch object can easily compute other related pitches, and return its representation as a frequency. We could carry out these computations on any integer, but by having it already programmed in Pitch, we should use that object to avoid code duplication, avoid work, and increase reliability.

  18. The first constructor is already completed in terms of the second one, so you don't have to worry about the first constructor.
  19. The second constructor must be completed, but it simply stores its incoming parameter in the instance variable you provisioned above.
  20. Let's look at getPitch(int). This method returns the Pitch that is the specified diatonic distance from this DiatonicScale's starting pitch. What makes this tricky is that the diatonic notes are not evenly spaced. This can be most easily understood by looking at the chromatic distances between the natural keys on a piano. The following table shows the relative chromatic distances between the notes of a diatonic scale:
    Example in
    key of C major
    Diatonic
    offset
    Chromatic offset
    from previous
    diatonic note
    C 0 N/A
    D 1 2
    E 2 2
    F 3 1
    G 4 2
    A 5 2
    B 6 2
    C 7 1

    Moreover, the getPitch(int) method must accommodate values for its parameter that are negative, zero, or positive, and those values may be outside the range of a single octave.

    This is the trickiest method: get help from the TAs or instructor if you need it.
    • Run the unit tests for DiatonicScale and they should pass at this point.
    • You can also run DiatonicScale as an applicaiton and it should print out some information about some scales.

  21. Open Triad class. A Triad has three SingleTones.
  22. Complete the constructor for Triad. The constructor takes in a DiatonicScale and an int, which is the diatonic offset of the root of the triad.

    The other two pitches are 2 and 4 diatonic offsets away from the root.

    Use the getPitch(int) method of the specified DiatonicScale to find the root, second, and third SingleTones of this Triad.

  23. Complete getTones() which returns an array consisting of the SingleTones of this Triad, in order.
  24. Complete getSamples(double,double), which returns a Samples object of the triad's tones at the specified amplitude and of the specified duration.
    Run the unit tests for Triad and they should pass at this point.

  25. For your final test, run PlayTest and choose a song. You should be able to hear the song repeat and with the mouse you can change its pitch and its speed.
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.7
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 7


Extension 8: Chord Organ (4 points):

Authors

You will use the Triad and other classes you have developed to make a simple chord organ that resembles the following:

The goal of your work is to hear the a diatonic triad play in the C major scale when your mouse enters the correspondingly marked rectangle.

Procedure

  1. Open the ChordOrgan class in the chords package. This is where you will write your code for this extension.
  2. Arrange for a screen such as the one shown above to be drawn, and detect mouse entry into the specified rectangles. To help you with this, consider the BoundingBoxGUIExample class in the chords.gui package:

    For the steps of the development described below, however, you must use the specified classes.

  3. Construct a DiatonicScale instance in the key of C:
    DiatonicScale ds = new DiatonicScale(3);
    
    This makes a diatonic scale object with high C as its base note.
  4. To make a given triad at offset i, use
    Triad t = new Triad(ds,i);
    
  5. You can get samples from that Triad (using Triad's getSamples(double,double)) of an amplitude and duration of your choosing and then cause them to be played using the Samples class.
  6. Demonstrate your work to a TA using a computer with sound enabled.
When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.8
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 8


Extension 9: 6-1-4-5: How To Be Famous (8 points):

Authors
Much has been written about the tendency for musicians from Pachelbel to Pink to write songs based on a common chord progression: In response of this, the Axis of Awesome has realized that the only barrier to their becoming famous is their lack of a four-chord song, as documented extensively in this amazing video and this other amazing video.

Axis of Awesome needs your help to record their soon-to-be-hit four-chord song.


In this extension, you use the chords.music classes you developed above to create a 4-chord song. The song consists of two Samples of music, background and tune, which are combined throughout to make a song. As the song plays, you can control how much of what you hear is background and how much is tune.

Overview


When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.9
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 9


Extension 10: Barcode Scanner (11 points):

Authors
Issues: Needs work

Introduction

The first item ever bought with a UPC barcode was a 10-pack of Wrigley's Juicy Fruit chewing gum. It cost 74 cents. While there are several encoding schemes used to produce barcodes, by far the most common is the Universal Product Code (or UPC-A). George J Laurer came up with the design for the Universal Product Code while he was working at IMB in 1973. Your task in this decode a UPC image.

Procedure

In the extensions folder you should find a package called upc. Open the UPC class inside it. You should see a constructor that takes in a Sedegwick Picture object and a method called getValue(). In order to test your code, you need to decode a barcode image and return the sequence of 12 digits it encodes as a string in the getValues() method. How you go about this is largely up to you. This extension will challenge you to take a large task and break it down into manageable, less intimidating components. To test your code when you are finished, run the TestUPC class in the upc package.

Note: For this extension, you need only consider left-to-right scans. Further, the data you will be provided with in the JUnit test is error free. This means that any trouble you have deciphering the 12-digit signature will not come as a result of the barcode image itself.

Below are some important points about UPC encoding that you may find useful. If you have any more questions, the Wikipedia link in the introduction of this extension is an excellent resource.


To get you started, here are some tips. There are three essential parts to your task ahead:

  1. Extracting information from the barcode image.
  2. Finding all of the digits in that raw data.
  3. Computing the digit values and ultimately the 12-digit signature of the UPC barcode.

How you accomplish these tasks is up to you, but creating additional classes to make your life easier is strongly advised. You are given a UPC Object; what other Objects might be useful in this task?

Hint: You might consider creating classes to handle pieces of the larger task so you can test as you go.

In the upc package is also a UPCUtil class. You are free to modify this class as you see fit. Inside it is a public int[][] digits that stores 10 integer arrays representing the UPC encoding of digits 0 through 9. The index of the array in digits tells you what digit the sequence of bar lengths therein represents.

digits[3] = {1,4,1,1} tells you that the digit "3" is encoded in a UPC by 4 bars of length 1-4-1-1

This information will be necessary for step three as described above. All of this information is also available in the hyperlink in the introduction.


You may find that you want to use the GenUPC class to test parts of your code before you are ready for the unit test. You can do so as follows:

GenUPC gen = new GenUPC(4);
String key = gen.genRandomUPC();
Picture pic = gen.genPic(key);

Here, the key is the 12-digit signature of the barcode and pic is the Picture that gets passed into the UPC class. To view the barcode image, use the .show() method of the Picture Object. The integer input in the GenUPC class indicates the number of pixels per module in the image to be generated.

When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.10
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 10


Extension 11: Barcode Scanner: Imperfect Data (11 points):

Authors
Issues: Needs work

Warning

It's strongly recommended that you complete extension 7.10 before doing this extension. If you start from scratch, you will complete extension 7.10 in the process of doing this extension.

Overview

Your task in this extension is to build on what you have already done in extension 7.10, Barcode Scanner. In the datafiles folder is a barcode folder full of JPEG images of barcodes. Have a look at some of them. You should notice that they are not a nice as the barcodes you had to deal with in the first barcode extension; they are blurry and some of them are warped by curved surfaces. Your task is to modify your code so that it can deal with blurry images, as well as upside-down images. You may find that you want to create a main file to test your code as you work. The UPC class has an empty constructor (public UPC()) that will pop up a window in which you can choose what JPEG image you want to use as your input picture. In the barcodes folder there are also three "mystery" barcodes with the signatures cropped out. Once you finish this extension, you should be able to decipher them and then you can search here to find out what the signature represents.

Procedure

Your first task is to modify your code to deal with blurry images. To do this, we are going to use a concept from image processing called thresholding. This basically involves pushing each pixel to white or black based on its brightness (or intensity henceforth). The intensity of a color is related to the strength of its red, green, and blue components. Recall that white is the composition of all colors and black is the absence of color. (If you completed the image processor extension, have a look at the grayscale method...).

Note: how you choose to represent white and black after thresholding is up to you. It will be helpful to choose a representation that is compatible with your choices from the first extension. Also, it will be very helpful to incorporate a parameter to serve as coefficient for the thresholding bound. By this I mean that to use the idea of thresholding, you need to compute a value that lies on the threshold between white and black. You need to have a default threshold, but you want to be able to modify this threshold with an input parameter. This is because sometimes the default bound won't eliminate all of the error, and you will want to try another one.

Once you have thresholding implemented, you should be able to find the digits and compute their values using your previously implemented code, but how do you know if the signature you find is correct? First you want to check that all of the digits that you discovered have the same parity and that they consist of seven modules. The parity of a digit is a way of determining if it was read from left to right, or vice-versa; if the sum of bar-lengths of the 1st and 3rd bars in a module is odd, then (assuming the digit is correct) it was scanned from left-to-right. Finally, you want to check the barcode using the check digit, or the last digit in the 12-digit UPC signature. The check digit is computed as follows:

  1. First, add up the odd-numbered digits (1st, 3rd, 5th...) and multiply by three
  2. Next, add up the even-numbered digits
  3. Next, add up the values computed in the previous two bullets, and take this value modulo 10.
  4. If the result isn't 10, subtract the result from 10.
If your computed check digit doesn't match the last digit in the UPC signature, then there is an error.

Now that you have the ability to detect error in your barcode reads, how do you fix the problem? Recall that in an actual barcode scanner, you need to keep waving the item in front of a laser until there is a beep, meaning that if there is an error, there is a re-scan. How you deal with error is up to you, but it's recommend that you re-read the data with a different threshold if the error too substantial to easily deal with.

Hint: if you are reading across the pixels of the image at a specific height, consider making that height variable (just like the threshold) so that you can vary the scan-height when you re-scan as well.

Once this is complete, the generatedWithError() test in the ImperefectDataTest class should pass.

After the thresholding modifications, the TestUPC JUnit test from the previous extension should still be passing. If it isn't, you should focus on getting that working before moving on to the imperfect data testing.


Your final task is to modify your code so that it can read barcodes that are upside-down as well (note that this is the same as a right-to-left scan). There are a variety of different ways to go about this, and it's up to you to decide what to do.

At this point, the files() test in the ImperefectDataTest class should pass as well.

When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.11
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 11


Extension 12: Roguelike (8 points):

Authors
Issues: Not yet ready

Intro

The roguelike genre of video games has exploded in popularity in recent years. The spirit of the roguelike genre lies in the random generation of elements which provide a fresh gameplay experience during any given play session. Gameplay elements like procedurally generated environments, permadeath, and randomly placed items and enemies have been implemented time and time again in such critically acclaimed games as Spelunky, The Binding of Isaac, and Don't Starve.

Overview

In this extension you will build a roguelike in the style of old-school ASCII games. An ASCII game is one where all of the game elements are represented by characters, a la Dwarf Fortress. Don't worry, we won't be attempting to approach the complexity of Dwarf Fortress in this game.
The rules of this roguelike are as follows:

Procedure

In the roguelike package you will find five classes:

Hero
The Hero is the representation of the player.

Baddie
The Baddies are this game's main antagonists.

Treasure
The Treasure object is how the player gets points.

Game
The Game is where it all comes together.

Useful Information

When you done with this extension, you must be cleared by the TA to receive credit.

This demo box is for extension 7.12
Last name WUSTL Key Propagate?
(or your numeric ID) Do not propagate
e.g. Smith j.smith
1 Copy from 1 to all others
2 Copy from 2 to all others

TA: Password:

End of extension 12