CIT 591 Assignment 10: Array Operations Fall 2014, David Matuszek
Purposes of this assignment
To get you started with JUnit 4
To give you practice with arrays
To help you understand APIs (Application Programmer Interfaces)
General idea of the assignment
Define a new object type, named Layout. A Layout
object is like a two-dimensional array of integers. However, it
will be different from an array in a couple of respects: (1) Layouts
have a number of operations defined on them that arrays do not have,
(2) Layouts are immutable, in the same way that Strings are immutable;
once created, they cannot be changed, and (3) Layouts are just objects,
so you can't use brackets with them as you can with arrays.
A "one-dimensional" Layout is represented internally as a two-dimensional array with only one row. Therefore, every method defined for two-dimensional Layouts should also work for Layouts that appear to be one-dimensional.
Write a number of methods for manipulating Layouts. Test
all your methods thoroughly with JUnit 4.
There are a lot of methods listed below, but don't worry--they are all
very short, just a couple of for loops each. Most of your
work will be in writing the JUnit tests for them.
There is no need for a main method
anywhere in this assignment. You are not writing a program, you are writing
a class that could be used by other programs.
Constructors
public Layout(int[][] array)
Creates a Layout containing a copy of the given array.
public Layout(int[] array)
Creates a Layout containing the given array. (Internally, every Layout object holds a two-dimensional array. Copy the given one-dimensional array of N locations into a 1xN two-dimensional array.)
public Layout(int length)
Creates an Layout of length integers, and fills it with the numbers 1 to length.
Example:new Layout(12) returns
1
2
3
4
5
6
7
8
9
10
11
12
Remember that
all Layouts are actually two-dimensional, so the array you create would be 1xlength in size.
Methods
public Layout reverse()
Returns a new Layout whose values are in the reverse order of those in the given Layout.
Example:
3
1
4
1
6
.reverse() returns
6
1
4
1
3
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.reverse() returns
4
3
2
1
8
7
6
5
12
11
10
9
public Layout rotateRight()
Returns a new Layout which is "rotated"
a quarter-turn clockwise.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.rotateRight() returns
9
5
1
10
6
2
11
7
3
12
8
4
public Layout rotateLeft()
Returns a new Layout which is "rotated"
a quarter-turn counterclockwise.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.rotateLeft() returns
4
8
12
3
7
11
2
6
10
1
5
9
public Layout transpose()
Transposes a Layout of m rows and n columns to form a Layout of n rows and m columns.
The value in location [i][j] of the Layout become the value in
location [j][i] of the new Layout.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.transpose() returns
1
5
9
2
6
10
3
7
11
4
8
12
public Layout ravel(int n)
Takes a one-dimensional Layout of m × n
numbers and returns a two-dimensional Layout of m rows and
n columns. The first n numbers of the given Layout are
copied into the first row of the new Layout, the second n numbers
into the second row, and so on. This method throws an
IllegalArgumentException if the length of the input Layout
is not evenly divisible by n.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.ravel(4) returns
1
2
3
4
5
6
7
8
9
10
11
12
public Layout unravel()
Takes a m by n two dimensional Layout and returns
a one-dimensional Layout of size m × n containing the
same numbers. The first n numbers of the new Layout are copied
from the first row of the given Layout, the second n numbers
from the second row, and so on.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.unravel() returns
1
2
3
4
5
6
7
8
9
10
11
12
public Layout reshape(int n)
Takes a two-dimensional array of r rows and c columns
and reshapes it to have n columns by (r*c)/n rows. This method throws an
IllegalArgumentException if r*c
is not evenly divisible by n.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.reshape(6) returns
1
2
3
4
5
6
7
8
9
10
11
12
public Layout join(Layout layout)
Adjoins a Layout with n rows and m1 columns to the parameter Layout with n rows and m2 columns, forming a new Layout with n rows and m1+m2 columns. This method throws an IllegalArgumentException if the input Layouts do not have the
same number of rows.
Example:
1
2
3
4
5
6
.join(
10
20
30
40
50
60
70
80
) returns
1
2
3
10
20
30
40
4
5
6
50
60
70
80
public Layout stack(Layout layout)
Forms a new Layout with n rows and m1+m2 columns by putting the recipient Layout with n1 rows and m columns on top of the parameter Layout of n2 rows and m columns. This method throws an IllegalArgumentException if the input Layouts do not have the
same number of columns.
Example:
1
2
3
4
5
6
7
8
.stack(
10
20
30
40
) returns
1
2
3
4
5
6
7
8
10
20
30
40
public int rowCount()
Returns the number of rows in the Layout. For a one-dimensional Layout, this returns 1.
public int columnCount()
Returns the number of columns in the Layout. For a one-dimensional Layout, this is the number of values in the Layout.
public Layout rows(int firstRow, int lastRow)
Returns a new Layout containing values from row firstRow to row lastRow, inclusive, of the recipient Layout.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.rows(1, 2) returns
5
6
7
8
9
10
11
12
public Layout columns(int firstColumn, int lastColumn)
Returns a new Layout containing values from column firstColumn to column lastColumn, inclusive, of the recipient Layout.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.columns(1, 2) returns
2
3
6
7
10
11
public Layout slice(int firstRow, int lastRow, int firstColumn, int lastColumn)
Returns a new Layout containing values from the given portion of the recipient Layout.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
.columns(1, 2, 2, 3) returns
7
8
11
12
public Layout replace(Layout layout, int row, int column)
Returns a new Layout in which the parameter layout replaces the values of the recipient Layout, starting at the given row and column. This method throws an IllegalArgumentException if the parameter Layout would go beyond the bounds of the recipient layout.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.replace(
55
66
77
88
99
100
, 1, 2) returns
1
2
3
4
5
6
7
55
66
77
11
12
88
99
100
16
17
18
19
20
@Override
public boolean equals(Object o)
Returns true if and only if this Layout contains an array of the same shape and containing the same values as Object o.
Here's how to write an equals method:
Make sure you declare the parameter to be of type Object, not Layout.
Test if Object o is actually a Layout, with (o instanceof Layout). If it isn't, return false.
Declare a new variable that of type Layout, and assign (Layout)o to it. (This is a "cast").
Write code to determine if this Layout and that Layout are actually equal, by comparing their instance variables. In this case you need to compare the number of rows (array.length), the number of columns (array[0].length), and every value in those arrays.
@Override
public int hashCode()
Arrays have a hashCode method. Your Layout object contains an array. This method should return the hashCode of that array. Don't ask why, just do it.
public int[] toArray1D()
Returns a one-dimensional array of the values in the recipient Layout. If the Layout is two-dimensional, it is first unraveled.
public int[][] toArray2D()
Returns a copy of the two-dimensional array of the values in the recipient
Layout. If the Layout is one-dimensional, the result will be an array
containing, as its single element, a one-dimensional array. (Do not return the actual array; make a copy. If you were to return the actual array, and someone were to change some value in the array, that would change the value in the Layout. That violates our intention to make Layouts immutable.)
public int at(int row, int column)
Returns the integer at the given row and column.
How to do this assignment
You can save yourself quite a bit of typing if you follow these steps:
In Eclipse, create the project, the package, and the class.
Write each of the methods as stubs--that is, write the
headers, but just have each method return an incorrect value (usually null).
Use Eclipse to create a JUnit4 test class; go through the
steps carefully, so you don't miss the part where Eclipse creates
stubs for all your test methods.
Next, repeat the following steps:
Fill in the tests for one of the methods.
Choose a method that does not depend on other methods that
haven't yet been written or tested. It should be either completely
independent of other methods, or depend only on well-tested methods.
Run JUnit to make sure that your new test fails.
Now write the method to handle the simplest case, replacing the stub code.
Run JUnit to test whether your new method is correct.
Debug as necessary. (Remember, it's possible that the test itself,
rather than the method being tested, is wrong.)
Refactor (clean up) the code as much as possible, and retest to ensure you haven't introduced new errors.
If the method is correct but incomplete (needs to handle more cases), return to step 1 and write a test for another case.
Do the above for each of the methods, until you are thoroughly familiar
with the pattern.
Things to remember
If your test class is in the same package as the class being tested, you do not need to import it. Otherwise, you do.
In
your JUnit test class, declare some Layout variables as instance variables of the class, but assign them
their initial values in the setUp method.
JUnit has an assertArrayEquals(expected array, actual result)
method.
JUnit tests are intended to find anything that could be wrong
with your methods, not to "prove" that they are correct. As
you write them, you are the prosecuting attorney, trying to expose any
flaws in the defendant's (the method's) story. For example, do the methods
handle zero-length arrays correctly?
In Java, all arrays are one-dimensional. A so-called
"two-dimensional" array is actually a one-dimensional array, each of
whose elements are one-dimensional arrays; each element is a row of the two-dimensional array.
You can construct test cases more easily if you use array initialization.
For example, int[] oneD = new int[] { 1, 2, 3, 4, 5 };
and int[][] twoD = new int[][] { { 1, 2, 3 },
{
4, 5, 6 } };
Structure of the assignment
Project name: Layout
Package name: layout
Class name: Layout
Method signatures: Exactly as given above.
Provide JUnit tests for: All required methods.
Provide Javadoc documentation for all classes and methods, except JUnit
tests.
Document JUnit tests if they are complex or do something non-obvious
Name to use for Blackboard: Layout
Grading
My JUnit tests will be applied to your methods. They will test everything that I can
think of that your methods might possibly get wrong.
If time permits, your JUnit tests will be applied to my methods. There will be errors in some of the
methods, which I expect your JUnit tests to find.
In order for this to work, you must use the method signatures exactly as listed; any necessary corrections will be posted on Piazza. If your
methods can't be called from my JUnit tests, or vice versa, that will cost you
significant points.