CIT 591 Assignment 8: Squarelotrons
Spring 2013, David Matuszek

Purpose of this assignment

General idea of the assignment

Anita is the baby sitter of Baron Von Hauser’s kids. Von Hauser is a famous physics professor, so the Von Hauser kids have weird toys, all of which Anita has to master to be able to effectively entertain the kids.

While Anita was cleaning the bathtub she found new toys, large and small Squarelotron games. These are extremely weird, and possess a lot of mathematical symmetry. She is determined to understand these new toys, otherwise she won't be able to play with Von Hauser’s kids. However the complexity of such an extreme toy makes it difficult to play.

A Squarelotron consist basically of a matrix of numbers. This matrix can be decomposed as square rings which can rotate independently in 4 different ways: Upside-Down (↕), Left-Right (↔), and reflected through the Main Inverse Diagonal (↙), and through the Main Diagonal (↘).

For example, consider the following Squarelotrons.

Squarelotron a) has 2 rings. The outer ring contains the numbers 1, 2, 3, 4, 5, 8, 9, 12, 13, 14, 15, 16, while the inner ring contains the numbers 6, 7, 10, 11.

Squarelotron b) has two rings and a center piece. The outer ring contains the numbers 1, 2, 3, 4, 5, 6, 10, 11, 15, 16, 21, 25, 22, 19, 24, 20, while the inner ring contains 7, 8, 9, 12, 14, 17, 18, 23. The number 13 is by itself in the center.

A Upside-Down Flip of the outer ring of Squarelotron a) yields:

A Left-Right Flip of the inner ring of squarelotron b) yields:

A Flip through the Main Inverse Diagonal of the inner ring of squarelotron a) yields:

A Flip through the Main Diagonal of the outer ring of squarelotron b) yields:

Since the squarelotron is a physical object, it can be simply rotated. For example, if the top row of the 4x4 squarelotron contains (1, 2, 3, 4) and the squarelotron is rotated right by 90 degrees, then the rightmost column of the squarelotron will contain (1, 2, 3, 4). This is not considered a "flip."

Anita wants you to do a program which performs the following. It will ask you whether to use a 4x4 or a 5x5 squarelotron, then print out the initial squarelotron (with the numbers in order, as in (a) above; not as in (b), which is slightly jumbled). Then the program will let you tell it which flips to perform, and it will print out the new squarelotron after each flip. Finally, the program will let you start with a new squarelotron, or quit.

Details

Required Classes

public interface SquarelotronMethods
We haven't yet discussed interfaces in class, so this is provided for you here. It is nothing more than a list of methods that have to be implemented by each of the SmallSquarelotron and LargeSquarelotron classes.
abstract class Squarelotron implements SquarelotronMethods
This class houses any variables and methods that are common to both SmallSquarelotron and LargeSquarelotron. (There may not be very many.) This class should declare the instance variable public int[][] squarelotron, which will be inherited by each of the two subclasses. It contains the main method which interacts with the user, as described above, and is the only method that does input/output.
class SmallSquarelotron extends Squarelotron
This class implements 4x4 squarelotrons.
class LargeSquarelotron extends Squarelotron
This class implements 5x5 squarelotrons.

Constructors

SmallSquarelotron should have a constructor public SmallSquarelotron(). It inherits the variable int[][] squarelotron from the Squarelotron (abstract) class, and fills it with the numbers 1 to 16, in order.

LargeSquarelotronshould have a constructor public LargeSquarelotron(). It inherits the variable int[][] squarelotron from the Squarelotron (abstract) class, and fills it with the numbers 1 to 25, in order.

The SquarelotronMethods interface and the abstract Squarelotron class don't have constructors.

Methods in SmallSquarelotron and LargeSquarelotron

Notice that in both the 4x4 and the 5x5 squarelotron, there are two rings that can be flipped (the center of the 5x5 ring is immobile). In each of the following methods, the ring should be one of the two strings "outer" and "inner", all lowercase, with the obvious meanings. None of these methods should ask for input or produce output.

public static Squarelotron makeSquarelotron(int[] array) throws IllegalArgumentException
Constructs and returns a squarelotron with the given numbers, not just 1 to 16 or 26 in order. The following conditions must be met: (1) The given array is either 16 or 25 in length, and (2) all the numbers in the array are nonnegative (zero is allowed) and less than or equal to 99. If either of these conditions is violated, execute throw new IllegalArgumentException(message).

Note: You can test whether this method throws the exception when it should, by writing tests that start with @Test(expected=IllegalArgumentException.class) and deliberately calling the method with bad arguments.
public int[] numbers()
Given a 4x4 squarelotron, numbers returns an array of 16 numbers. Given a 5x5 squarelotron, it returns an array of 25 numbers. For a newly created squarelotron, the array returned by this method should have the same numbers in the same order as the array used to create the squarelotron.
public Squarelotron upsideDownFlip(String ring)
This method performs the Upside-Down Flip of the squarelotron, as described above, and returns the new squarelotron. The original squarelotron should not be modified (I will check for this).
public Squarelotron leftRightFlip(String ring)
This method performs the Left-Right Flip of the squarelotron, as described above, and returns the new squarelotron. The original squarelotron should not be modified (I will check for this).
public Squarelotron inverseDiagonalFlip(String ring)
This method performs the Main Inverse Diagonal of the squarelotron, as described above, and returns the new squarelotron. The original squarelotron should not be modified (I will check for this).
public Squarelotron mainDiagonalFlip(String ring)
This method performs the Main Diagonal Flip of the squarelotron, as described above, and returns the new squarelotron. The original squarelotron should not be modified (I will check for this).
public Squarelotron sideFlip(String side)
The argument side should be one of the four strings "left", "right", "top", and "bottom". The two indicated columns (leftmost or rightmost), or the two indicated rows (top two rows or bottom two rows) should be interchanged. The original squarelotron should not be modified (I will check for this).
public void rotateRight(int numberOfTurns)
The argument numberOfTurns indicates the number of times the squarelotron should be rotated 90° clockwise. Any integer, including zero and negative integers, is allowable as the second argument. A value of -1 indicates a 90° counterclockwise rotation. This method modifies the internal representation of the squarelotron; it does not create a new squarelotron.
@Override
public boolean equals(Object object)
Returns true if the object is a squarelotron that is equal to this squarelotron, and false otherwise. Squarelotrons that are the same except for rotations are considered equal. Squarelotrons of different sizes are never equal.
@Override
public String toString()
Returns a printable version of this squarelotron. The returned string should contain newline characters, '\n', between rows, so that printing the returned string produces neat, good-looking output. As with all of the above methods, calling this method should not result in any input/output.

How to get started

Eclipse can save you a lot of typing. Here's how to begin:

  1. Start Eclipse. In Moore 207, do this by starting Scala-IDE as usual (you may have to respond to some dialog boxes complaining about something), then go to Window → Open Perspective → Java (not Java Browsing; if you don't see Java, look under Other). Don't try to use the Scala perspective for Java programs, or vice versa!
  2. Create your project. Name it Squarelotron.
  3. Create a package. Name it squarelotron.
  4. Create an interface. Name it SquarelotronMethods.
  5. Copy/paste this file in place of your SquarelotronMethods file.
  6. Create the Squarelotron class.
  7. For both the SmallSquarelotron class and the LargeSquarelotron class:
    1. Create the class (File → New → Class), but as you do so, add the interface SquarelotronMethods to it, and be sure Inherited abstract methods is checked. If you do this correctly, Eclipse will generate stubs for all the methods in the interface (except possibly equals, toString and makeSquarelotron) you will have to create these yourself). If this doesn't happen, you did something wrong; delete the class and try again.
    2. Create the JUnit tests for the class:
      1. Make sure the file you want to test is selected, then go to File → New → JUnit Test Case.
      2. Make sure the project (Source folder), package, and name are filled in, and New JUnit 4 Test is selected. Also check SetUp(). Click Next>, not Finish!
      3. Check all your methods (but not Object and below). Now you can click Finish. If you do this correctly, you will get test stubs for all the methods.

Unit Testing

Writing JUnit Tests

If you did the above correctly, here's what you should have (and if you didn't, you'll have to type these things in):

@Before
public void setUp() throws Exception {}
This method will be executed before each and every one of your tests. Since you want each test to begin with a "clean slate" and not depend on other tests having been run, this is where you initialize any variables that you might want to use in your tests. And remember, those variables must be declared in the class, because if they are declared in this method, they're just local to the method and inaccessible to any other methods.
@Test
public final void testNameOfSomeMethod() {
    fail("Not yet implemented");
}
This is what your tests look like. The method body is just plain Java code, but should include calls to some of the methods in org.junit.Assert.*. Some of the most useful methods are:
assertEquals(expected, actual)
Asserts that the actual value equals the expected value. Both expected and actual must be the same type (for example, you cannot test an int against a double). If the two parameters are objects of a class that you have created, the test will use your public boolean equals(Object o) method (or == if you haven't defined equals, which is almost certainly not what you want!).
assertArrayEquals(expectedArray, actualArray)
Like assertEquals, but for arrays. If the elements of the arrays are objects of a class that you have created, the test will use the equals method for that class.
assertEquals(expected, actual, delta)
Asserts that two doubles or floats are equal to within a positive delta.
assertTrue(booleanCondition)
Asserts that the booleanCondition evaluates to true.
assertFalse(booleanCondition)
Asserts that the booleanCondition evaluates to false.

Reminder--TDD

Write and unit test the following methods. You should try using TDD, Test-Driven Design, as illustrated in class:

  1. Start with a method that doesn't do anything
  2. Write a test for the method.
  3. Run the test, and make sure it fails.
  4. Add code to the method to try to make the test pass.
  5. Run the test again.
    1. If the test fails, debug the method (or the test) until the test passes.
    2. If the test passes, continue.
  6. Is the method complete (does it do everything it should do)?
    1. If the method isn't complete, add code to the test to check the new functionality. Go to step 3.
    2. If the method is complete, you are done with this method.

As always, follow the specifications exactly, because we will also be using our own unit tests to check your work

Reference

This assignment is a modified version of the problem "10016 - Flip-Flop the Squarelotron," from Online Judge.

Due date

Before 6am Friday November 1. Submit your zipped project file to Canvas. As usual, submit one project for the team. No other form of submission will be accepted.