Last Updated: 2016-02-09 Tue 18:55

CS 211 Project 2: Obligatory Objects

CODE DISTRIBUTION:

CHANGELOG:

Tue Feb 9 18:53:01 EST 2016
The Honors Section problem has been added. Download the tests above and read the honors section problem for what to do.
Fri Feb 5 12:24:31 EST 2016
The class structure for GneeralLE was originally identical to SlopeInterceptLE by accident; this has been corrected.
Thu Feb 4 20:57:04 EST 2016
The original posting of the spec was missing overviews of the SlopeInterceptLE and GeneralLE classes which have now been added.

Table of Contents

1 Project Overview

1.1 Problem Sets

This project has 3 problems to complete. All of them involve creating new classes which do not exist in Java. The first two problems involve modeling simple linear equations of two variables using classes. This will introduce the idea of invariants: properties that should always be true about a class after one of its methods completes. The third problem revisits the queues of the previous project and implements them in a proper, Java-esque fashion as an object with associated methods. The honors problems builds on this to improve the efficiency of the queue methods and makes it more flexible to allow for expansion.

1.2 Project Files

The following files are relevant to the project. Some are provided in the project distribution while others you must create. You should submit all files listed unless marked as Optional (in the State column).

File State Notes
SlopeInterceptLE.java Create Create for first problem
SlopeInterceptTests.java Testing Tests for first problem
     
GeneralLE.java Create Create for second problem
GeneralLETests.java Testing Tests for second problem
     
ProperQueue.java Create Create for third problem
ProperQueueTests.java Testing Tests for third problem
     
P2Tests.java Testing Run all standard tests for the project
     
CircularQueue.java Honors Create for honors problem
CircularQueueTests.java Honors Tests for honors problem
     
junit-cs211.jar Testing JUnit library for command line testing
ID.txt Create Create in setup to identify yourself

2 Background on Linear Equations

Throughout much of your Mathematics education, you've likely spent time using linear equations to represent the relationship between things and solved them as parts of larger problems. We like to solve problems with computers, so a good first step could be developing our own library of classes to represent these equations.

The primary motivation of the object-oriented programming paradigm is to guarantee that operations on data preserve internal invariants for that data. Most of us know that the radius and diameter of a circle have the relationship \(r = 2d\). If circles are represented using both radius and diameter, changing one must affect the other: a circle with radius 5 and diameter 322 badly violates our notion of what constitutes a proper circle. This is the essence of the object-oriented paradigm, to only allow access to manipulate an object via certain methods which will preserve the internal consistency of the object's state.

In the next few problems we will be representing linear equations with real number coefficients in two different formats. We need a representation that keeps track of the different variables and constants, and that also maintains the relationship between them as the variables are changed. We consider first the slope intercept form, and then the general form.

Should you need a math refresher, Wikipedia's Linear Equations article contains useful reminders of terminology and formulas.

3 Problem: Slope/Intercept Linear Equations

Files to submit

SlopeInterceptLE.java
Define a class to model a linear equation of variables \(x\) and \(y\) in slope intercept form. A skeleton for this file is provided in the project pack.
SlopeInterceptLETests.java
Provides tests of the correctness of the above class.

3.1 Good old Em ex plus Bee

A linear equation is in slope intercept form if it is written \[ y = m x + b \] where \(m\) and \(b\) are constants that do not change while \(x\) and \(y\) are variables that do change.

Define a class which models a linear equation in slope intercept form. A template is provided for you in the file SlopeInterceptLE.java. You will need to add any fields that are required for the class to work properly and fill in definitions for the below methods.

3.2 Class Structure of SlopeInterceptLE

// A class to model linear equations of two variable (x and y) in
// slope intercept form.
public class SlopeInterceptLE {

  // Public constructor that accepts values for the slope m and
  // intercept b, defaults the value of x to 0.0 and sets y
  // appropriately.
  public SlopeInterceptLE(double m, double b);

 // Public constructor that accepts values for the slope m and
 // intercept b and initial value of x and sets y appropriately.
  public SlopeInterceptLE(double m, double b, double x);

  // Return the numeric value of the equation which is the numeric
  // quantity that should be on both left and right sides of the equal
  // sign.
  public double value();

  // Return the current value of x
  public double getX();

  // Return the current value of y
  public double getY();

  // Set the value of x and change y accordingly to preserve the
  // equation.
  public void setX(double x);

  // Set the value of $y$ and change $x$ accordingly to preserve the
  // equation.
  public void setY(double y);

  // Return a =String= version of the general form of the equation.
  // The pretty version's general format should be as follows.
  // 
  //   y = M.MM * x + B.BB
  //
  // M.MM is the slope with 2 digits of accuracy and B.BB is the
  // intercept with two digits of accuracy.  Look for a method of the
  // String class to assist with formatting.
  //
  // Examples:
  //    y = 1.23 * x + 122.41
  //    y = -1.23 * x + -122.41
  public String toString();

}

3.3 Implementation Notes

The method

public String toString()

should return a String version of the general form of the equation. This string's general format should be

y = M.MM * x + B.BB

where M.MM is replaced with the value of \(m\) with 2 decimal digits of accuracy and similarly for B.BB being replaced by \(b\). For example, if \(m = 1.23, b= 122.408\), the appropriate string to produce is

y = 1.23 * x + 122.41

If \(m = -1.23, b= -122.408\), the appropriate string to produce is

y = -1.23 * x + -122.41

This task is significantly easier if you examine the String.format() method and learn a few things about format strings for producing nice looking output. Format strings are used with System.out.printf() which is derived from the C language printf function. There are several places to learn about them.

3.4 Sample Session

Welcome to DrJava.  Working directory is /...
> SlopeInterceptLE si = new SlopeInterceptLE(1.0,2.0)
> si
y = 1.00 * x + 2.00
> si.toString()
y = 1.00 * x + 2.00
> si.getX()
0.0
> si.getY()
2.0
> si.value()
2.0
> si.setX(4)
> si.value()
6.0
> si.getY()
6.0
> si
y = 1.00 * x + 2.00
> si.toString()
y = 1.00 * x + 2.00
> si = new SlopeInterceptLE(0.25, 10.25, 1.0);
> si.getX()
1.0
> si.getY()
10.5
> si
y = 0.25 * x + 10.25
> si.setY(4.5)
> si.getY()
4.5
> si.getX()
-23.0
> si
y = 0.25 * x + 10.25
> si.value()
4.5
> si = new SlopeInterceptLE(-0.25, -10.25, -1.0);
> si.toString()
y = -0.25 * x + -10.25
> si = new SlopeInterceptLE(0.67512, -1.999, -1.0);
> si.toString()
y = 0.68 * x + -2.00

3.5 (10%) SlopeInterceptLE Manual Inspection Criteria   grading

  • Fields of the class are present, documented, and have an appropriate access modifier to prevent external sources from modifying them
  • Methods should be short and sweet

4 Problem: General Form of Linear Equations

Files to submit

GeneralLE.java
Define a class to model a linear equation of variables \(x\) and \(y\) in general form. You must create this file.
GeneralLETests.java
Provides tests of the correctness of the above class.

4.1 General LE

A linear equation is in general form if it is written \[ a x + b y = c\] where \(a,b,c\) are constants that do not change while \(x\) and \(y\) are variables that do change.

Define a class which models a linear equation in general form. You will need to create the file GeneralLE.java and fill in the appropriate fields and methods.

4.2 Class Structure of GeneralLE

public class GeneralLE {

  // Public constructor that accepts values for the three constants a,
  // b, and c, as well as the variable x. This is the only public
  // constructor.
  public GeneralLE(double a, double b, double c, double x);

  // Return the numeric value of the equation which is the numeric
  // quantity that should be on both left and right sides of the equal
  // sign.
  public double value();

  // Return the current value of x
  public double getX();

  // Return the current value of y
  public double getY();

  // Set the value of x and update other values as appropriate to
  // preserve the equation.
  public void setX(double x);

  // Set the value of y and update other values as appropriate to
  // preserve the equation.
  public void setY(double y);

  // Return a String version of the general form of the equation.  The
  // pretty version's general format should be
  // 
  //   A.AA * x + B.BB * y = C.CC
  // 
  // A.AA, B.BB, and C.CC are the coefficients for the linear equation
  // with 2 decimal digits of accuracy. Examples:
  // 
  //   1.23 * x + 45.68 * y = 2.00
  //   -54.99 * x + -9.86 * y = 42.41
  public String toString();

  // Produce a version of this GeneralLE in slope intercept form.  The
  // values of x and y must be preserved but the coefficients should
  // be converted to slope intercept form. The resulting
  // SlopeInterceptLE is not connected to the generating GeneralLE in
  // any way: changes to one do not affect the other.
  public SlopeInterceptLE toSlopeInterceptLE();

}

4.3 Implementation Notes

As with SlopeInterceptLE, the toString() method is made much easier if you master the String.format() method to produce formatted output.

To complete the conversion method toSlopeInterceptLE(), you will need to do a little bit of arithmetic to generate the slope and intercept. Make sure to include a comment explaining the algebra involved.

4.4 Sample Session

Welcome to DrJava.  
> GeneralLE g = new GeneralLE(1, 10, 11, 1);
> g
1.00 * x + 10.00 * y = 11.00
> g.value()
11.0
> g.getX()
1.0
> g.getY()
1.0
> g.setX(5)
> g.getY()
0.6
> g.value()
11.0
> g.setY(5.5)
> g.getX()
-44.0
> g
1.00 * x + 10.00 * y = 11.00
> g.value()
11.0
> SlopeInterceptLE si = g.toSlopeInterceptLE();
> si
y = -0.10 * x + 1.10
> si.getX()
-44.0
> g.getX()
-44.0
> si.getY()
5.5
> g.getY()
5.5
> si.value()
5.5
> si
y = -0.10 * x + 1.10
> g.value()
11.0
> g
1.00 * x + 10.00 * y = 11.00
> g = new GeneralLE(1.999, -10.238, 11.2345, 1);
> g.toString()
2.00 * x + -10.24 * y = 11.23

4.5 (10%) GeneralLE Manual Inspection Criteria   grading

  • Fields of the class are present, documented, and have an appropriate access modifier to prevent external sources from modifying them
  • Methods are short and sweet
  • Some documentation for the toSlopeInterceptLE() method is provided which explains how the conversion process is accomplished

5 Problem: Proper Integer Queues

Files to submit

ProperQueue.java
Create this file and implement the ProperQueue class in it.
ProperQueueTests.java
Provides tests of the correctness of the above class.

5.1 A Better Queue than Last Time

We will revisit the notion of a queue that we introduced in our previous project. There will be two significant changes:

  • Queues this time will be built as a class with methods called ProperQueue instead of just using an array itself as the queue. There will still be an array inside of the objects of this class but it will be better encapsulated to hide details of the implementation.
  • We are storing Integer objects in the queue instead of primitive-type int values. This implies that null is a possible value in the array.

5.2 int versus Integer

The Integer type is a simple idea: sometimes, we must have an object instead of a primitive type in order to deal with references; Integer is a class that represents individual int values, while also giving us a reasonable place to write methods and to provide constants related to integers. Java has some built-in support for converting between these "boxed types" and the primitive types they mimic. We can almost leave it up to Java to implicitly convert between int and Integer when needed, except in times when different overloaded methods were written for both, as we might see in some of the unit testing code. (This is why there are some casting expressions to turn an int into an Integer). The last thing to consider about them is that, as a class type, variables that should refer to an Integer might actually store the null value. This couldn't happen with the primitive int type.

5.3 Class Structure of ProperQueue

We are borrowing some of the structure from Java's own Queue interface and specializing it to a class that only holds Integer values (it's not time yet for generics), and to make an initial and permanent fixed size for any particular ProperQueue object. We want to add items to a queue, we want to remove items and see what was removed, and we want to check what is the element at the head of the queue without actually removing it. But sometimes queues don't have items when we ask to remove or peek at an element; and since our queues have an unchangeable capacity, sometimes we can't add another element. Should the queue just yield null values, or raise exceptions? We will provide both versions of behavior for all three of those actions (just like our source of inspriation, Java's Queue interface, does). We will also have some simpler functionality that should be very direct to complete.

5.4 Fields

  • size: number of elements currently stored in the queue.
    private int size
    
  • elements: an array of Integer values that stores the elements of our queue, just like last time (squashed towards the front of the array).
    private Integer[] elements
    

5.5 Methods

  • constructor. Must initialize all instance variables. When maxCapacity isn't a positive integer, this creates a queue with zero capacity.
    public ProperQueue (int maxCapacity)
    
  • getSize : returns how many elements are currently stored in the queue.
    public int getSize()
    
  • getCapacity : returns the maximum number of elements that can be stored in the queue at once.
    public int getCapacity()
    
  • isFull : indicates if the queue is currently entirely filled with elements or not.
    public boolean isFull()
    
  • isEmpty : indicates if the queue currently holds no elements.
    public boolean isEmpty()
    
  • toString: creates and returns a String representation of the Queue by showing each number in the queue, each separated by an individual space character, but without an extra space at the end.
    public String toString()
    
  • add: attempts to add the element e to the end of the queue. throws a RuntimeException with the message
    "Queue full"
    

    when the queue is full (and can't accept another item). Returns true upon successful addition of the element. Attempting to add null to the queue raises a RuntimeException with the message

    "Cannot add null"
    

    The method prototype is:

    public boolean add (Integer e)
    
  • offer: variation of the add method that does not raise an exception when space is unavailable; it would return false instead under those circumstances.
  • remove: attempts to remove the front item in the queue and return it. Raises a RuntimeException with the message
    "Queue empty"
    

    when no item is available for removing.

    public Integer remove()
    
  • poll: variation of the remove method that does not raise an exception when no element was available for removal. It returns null in that circumstance.
    public Integer poll()
    
  • element: this method will copy the front item from the queue and return it, but it does not actually remove the item from the queue (it doesn't modify the queue at all). Raises a RuntimeException with the message
    "Queue empty"
    

    if the queue is empty.

    public Integer element()
    
  • peek: variation of the element method that will return null instead of raising an exception when no elements were present in the queue.
    public Integer peek()
    

5.6 Implementation Notes

As with the queues of the previous project, the intention is for ProperQueues to keep the front element at array index 0 in their internal array. On removing an element, shift all elements to lower indices.

Several methods require RuntimeExceptions to be thrown with specific messages. Review the syntax to create and raise exceptions for these situations.

The string representation of queues is slightly different than in the first project: no trailing whitespace is allowed. Observe:

> ProperQueue q = new ProperQueue(4);
> q.add(15);
> q.offer(25);
> q.add(35);
> q.toString()
"15 25 35"

You will need to structure your toString() differently from the previous project to account for this difference.

It may be worthwhile to write an internal helper method which shifts elements. This method may be utilized in both remove() and poll() as both require similar functionality.

5.7 Sample Session

The following interactive session in DrJava demonstrates the core functionality of the ProperQueue.

Welcome to DrJava.
> ProperQueue q = new ProperQueue(5);
> q.toString()
""
> q

> q.getSize()
0
> q.getCapacity()
5
> q.isEmpty()
true
> q.isFull()
false

// add() returns true on a successful addition
> boolean result = q.add(20);
> result
true
> q.toString()
"20"
> q
20
> q.isEmpty()
false
> q.isFull()
false
> q.getSize()
1

// element() returns the first element without removing it
> q.element()
20
> q
20

// remove() returns the first element and removes it
> Integer first = q.remove();
> first
20
> q

> q.getSize()
0

// Attempting to remove() from an empty queue raises an exception
> first = q.remove();
java.lang.RuntimeException: Queue empty
        at ProperQueue.remove(ProperQueue.java:140)

// Attempting to poll() an empty queue returns null
> first = q.poll();
> first
null

// add() and offer() are identical when the queue has room
> q.add(15)
true
> q.offer(25)
true
> q.add(35)
true
> q.offer(45)
true
> q.add(55)
true

// q is now full (at capacity)
> q.getSize()
5
> q.getCapacity()
5
> q.isFull()
true

// add() on a full queue raises an exception without altering the queue
> q.add(65)
java.lang.RuntimeException: Queue full
        at ProperQueue.add(ProperQueue.java:91)

// offer() on a full queue returns false without altering the queue
> q.offer(65)
false
> q
15 25 35 45 55
> q.offer(65)
false
> q
15 25 35 45 55

// remove() and poll() are identical when the queue has elements
> first = q.remove()
15
> q
25 35 45 55
> first = q.poll()
25
> q
35 45 55

5.8 (20%) ProperQueue Manual Inspection Criteria   grading

  • Methods should be short and sweet
  • Provide a few comments to document sections of your code which shift elements around in methods such as poll() and remove()
  • Document fields and describe how they are to used within the class
  • For methods that involve special behavior for certain inputs or conditions, ensure that the special cases are clearly identified and handled prior to moving on to the general case.
  • As there are quite a few methods associated with this class, make sure to organize the methods within the class.
  • Document any and all methods, including helper methods, that are not part of the required public methods.

6 Honors Section: Circular Queues that Expand

Files to submit:

CircularQueue.java
Create this file and implement the CircularQueue class in it.
CircularQueueTests.java
Provides tests of the correctness of the above class.

6.1 Improvements in Time and Space

A dissatisfying aspect of the ProperQueue is its need to shift elements in the internal array every time a removal is performed. This leads to more computational work being done than is strictly necessary. Rather than shifting elements, one can add a field to the queue which indicates the index of the front element. As elements are removed, this field front changes to reflect the location of the new first element rather than moving all elements around. Similarly, a rear field tracks the back end of the queue. As rear reaches the end of the queue, if there is space at the beginning of the array due to removed elements, rear wraps around. This wrap-around leads to front being bigger than rear in some cases and gives rise to notion of circularity for a CircularlQueue. The following diagram illustrates some of these ideas.

circular-queue.png

An additional annoyance of our previous queues is their fixed capacity: when the internal array is full, further add() and offer() requests do not modify the queue. To remedy this situation, the CircularQueue will implement expansion. As there is no way make arrays larger in Java, the simple solution is to allocate a new, larger array and copy elements over to it. For the CircularQueue, this is a good opportunity to straighten elements out so that the front is back at the 0th element of the array. A common size change that leads to reasonable performance is to double the size of the array used when expansion is required. The above example is continued below to illustrate expansion.

circular-queue2.png

6.2 Class Structure of CircularQueue

CircularQueue possesses all of the methods that ProperQueue does plus one additional method. The behavior of some methods differs from ProperQueue. A summary appears in the implementation notes in the next section.

// Implements a queue of integers as an object with
// methods. Internally ints are stored in an array with empty cells
// containing nulls.  The queue tracks the number of elements it
// contains (size) and expands by allocated arrays twice the size of
// current size if a request to add is made when at capacity.
// Removing elements does not shift but instead adjusts an internal
// index dictating the location of hte front element. Similarly,
// adding adjusts an internal index indicating the location of the
// rear element. The queue will wrap around to use empty front slots
// in the array if they are available leading to its "circular"
// nature.
public class CircularQueue{

  // Create an empty queue with the given maximum capacity.  Allocate
  // an array of the given size but it does not need to be initialized
  // with any special values.  Initialize the queue's size to 0.  If
  // maxCapacity is less than or equal to zero, use an initial
  // capacity of 1.
  public CircularQueue(int maxCapacity);

  // Return the number of elements that have been added to the queue
  // but not removed.
  public int getSize();

  // Return the maximum number of elements that can be stored in the
  // queue which corresponds to the length of it its internal array.
  public int getCapacity();

  // Return true if the queue's size is equal to its maxium capacity
  // and false otherwise.
  public boolean isFull();

  // Return true if zero items are currently in the queue, false
  // otherwise.
  public boolean isEmpty();

  // Add the element e to the end of the queue.  This method should
  // only throw an exception if e is null. Otherwise it should add the
  // given element and return true.  If the queue is full, allocate a
  // new array twice as large as the present array, copy elements over
  // to it and proceed to use the new array henceforth.
  public boolean add(Integer e);

  // Identical to add(x) in all respects
  public boolean offer(Integer e);

  // If the queue is empty throw a RuntimeException with the message
  // "Queue empty".  Otherwise, remove the front element from the
  // queue.  This method should not shift elements in the internal
  // array but should instead adjust internals to the position of the
  // new front element.  Slots of the array where elements are removed
  // should be filled with null.
  public Integer remove() ;

  // If the queue is empty, return null. Otherwise behave exactly as
  // remove() does.
  public Integer poll () ;

  // Return the front item in the queue without modifying the
  // queue. If the queue is empty throw a RuntimeException with the
  // message "Queue empty"
  public Integer element();

  // Return the front item in the queue without modifying the
  // queue. If the queue is empty return null.
  public Integer peek();

  // Produce a string representing the queue.  This string should not
  // contain any null elements: only the integers that have been added
  // in their queue order. Each element should be separated by a
  // space, with *NO* additional space at the end after the last
  // element.  Sample formats are as follows.
  // 
  // |-----------------------------------------+----------------|
  // | Code                                    | q.toString()   |
  // |-----------------------------------------+----------------|
  // | CircularQueue q = new CircularQueue(4); | ""             |
  // | q.add(4); q.add(7);                     | "4 7"          |
  // | q.add(9);                               | "4 7 9"        |
  // | q.remove()                              | "7 9"          |
  // | q.remove()                              | "9"            |
  // | q.add(2);                               | "9 2"          |
  // | q.add(7);                               | "9 2 7"        |
  // | q.add(3);                               | "9 2 7 3"      |
  // | q.remove()                              | "2 7 3"        |
  // | q.add(5);                               | "2 7 3 5"      |
  // | q.add(8);                               | "2 7 3 5 8"    |
  // | q.add(11);                              | "2 7 3 5 8 11" |
  // | q.remove()                              | "7 3 5 8 11"   |
  // |-----------------------------------------+----------------|
  public String toString();

  // Produce a string version of the internal array of elements used
  // by the queue.  Methods from the java.util.Arrays class may prove
  // helpful as the format of the internals string is modelled after
  // how arrays are stringified there. Sample formats are below.
  //
  // |-----------------------------------------+--------------------------------------|
  // | Code                                    | q.internalsString()                  |
  // |-----------------------------------------+--------------------------------------|
  // | CircularQueue q = new CircularQueue(4); | "[null, null, null, null]"           |
  // | q.add(4); q.add(7);                     | "[4, 7, null, null]"                 |
  // | q.add(9);                               | "[4, 7, 9, null]"                    |
  // | q.remove()                              | "[null, 7, 9, null]"                 |
  // | q.remove()                              | "[null, null, 9, null]"              |
  // | q.add(2);                               | "[null, null, 9, 2]"                 |
  // | q.add(7);                               | "[7, null, 9, 2]"                    |
  // | q.add(3);                               | "[7, 3, 9, 2]"                       |
  // | q.remove()                              | "[7, 3, null, 2]"                    |
  // | q.add(5);                               | "[7, 3, 5, 2]"                       |
  // | q.add(8);                               | "[2, 7, 3, 5, 8, null, null, null]"  |
  // | q.add(11);                              | "[2, 7, 3, 5, 8, 11, null, null]"    |
  // | q.remove()                              | "[null, 7, 3, 5, 8, 11, null, null]" |
  // |-----------------------------------------+--------------------------------------|
  public String internalsString();

}

6.3 Implementation Notes

The two primary goals of CircularQueue are to

  1. Avoid shifting elements while efficiently using available array space.
  2. Expand when the internal array is full and new elements are to be inserted.

Many of the methods associated with CircularQueue are nearly identical to ProperQueue. Below are some major differences that will require some new code.

Initialization in the Constructor

public CircularQueue(int maxCapacity)

The constructor for CircularQueues should allocate an array of at least length 1. If the parameter maxCapacity is 0 or less, ignore it and initialize the internal array of elements to be size 1.

It may be necessary to set the front and rear indices to strange initial values like -1 to get the rest of the methods to work out right. You will most likely need to track the size of the queue in addition to front and rear indices.

Internal Representation

public String internalsString()

This method is meant to produce a "picture" (string version) of the internal array used by the CircularQueue. It is not present in ProperQueue. The format of these strings is easily produced using methods from the java.util.Arrays so that this method can be as short as a single line. It is mainly used to verify that the internal layout of the queue is correct.

add() and offer() always succeed

public boolean add(Integer e)
public boolean offer(Integer e)

Unlike the ProperQueue, methods to put elements in a CircularQueue should always work. Thus add() and offer() should behave identically and always return true. The only reason to raise an exception is in the event that the parameter e is null.

The general approach to expansion when the array is full is to take the following steps.

  • Check if queue's array is full by comparing size and capacity
  • When full, trigger an expansion
  • Expansion should allocate a new array that is twice the size of the old array
  • Copy elements from the old array in queue-order into the new larger array
  • Adjust internal fields so that the queue now uses the new larger array and has its front and rear indices set appropriately
  • After it is certain that the internal array has enough space (not full or expansion has finished) place the new element in the queue adjusting the rear index appropriately.

6.4 Sample Session

The following table gives code to create and manipulate a CircularQueue. The table is right top to bottom left to right and shows what each method call returns and the results of how the queue would look after the code is executed according to its toString() method and its internal structure as evidenced by the internalsString() method.

|----+---------------------------+--------+----------------+--------------------------------------|
|    | Code                      | Return | q.toString()   | q.internalsString()                  |
|----+---------------------------+--------+----------------+--------------------------------------|
|  0 | CircularQueue q;          |        |                |                                      |
|  1 | q = new CircularQueue(4); |        | ""             | "[null, null, null, null]"           |
|  2 | q.add(4); q.add(7);       | true   | "4 7"          | "[4, 7, null, null]"                 |
|  3 | q.add(9);                 | true   | "4 7 9"        | "[4, 7, 9, null]"                    |
|  4 | q.remove()                | 4      | "7 9"          | "[null, 7, 9, null]"                 |
|  5 | q.remove()                | 7      | "9"            | "[null, null, 9, null]"              |
|  6 | q.add(2);                 | true   | "9 2"          | "[null, null, 9, 2]"                 |
|  7 | q.add(7);                 | true   | "9 2 7"        | "[7, null, 9, 2]"                    |
|  8 | q.add(3);                 | true   | "9 2 7 3"      | "[7, 3, 9, 2]"                       |
|  9 | q.remove()                | 9      | "2 7 3"        | "[7, 3, null, 2]"                    |
| 10 | q.add(5);                 | true   | "2 7 3 5"      | "[7, 3, 5, 2]"                       |
| 11 | q.add(8);                 | true   | "2 7 3 5 8"    | "[2, 7, 3, 5, 8, null, null, null]"  |
| 12 | q.add(11);                | true   | "2 7 3 5 8 11" | "[2, 7, 3, 5, 8, 11, null, null]"    |
| 13 | q.remove()                | 2      | "7 3 5 8 11"   | "[null, 7, 3, 5, 8, 11, null, null]" |
|----+---------------------------+--------+----------------+--------------------------------------|

Below is the same example above but written long-form to show each action followed by toString() and internalsString() results.

> CircularQueue q = new CircularQueue(4);
> q

> q.toString()
""
> q.internalsString()
"[null, null, null, null]"
> q.add(4); q.add(7);
> q.toString()
"4 7"
> q.internalsString()
"[4, 7, null, null]"
> q.add(9);
> q.toString()
"4 7 9"
> q.internalsString()
"[4, 7, 9, null]"
> q.remove()
4
> q.toString()
"7 9"
> q.internalsString()
"[null, 7, 9, null]"
> q.remove()
7
> q.internalsString()
"[null, null, 9, null]"
> q.toString()
"9"
> q.add(2);
> q.toString()
"9 2"
> q.internalsString()
"[null, null, 9, 2]"
> q.add(7);
> q.toString()
"9 2 7"
> q.internalsString()
"[7, null, 9, 2]"
> q.add(3);
> q.toString()
"9 2 7 3"
> q.internalsString()
"[7, 3, 9, 2]"
> q.remove()
9
> q.toString()
"2 7 3"
> q.internalsString()
"[7, 3, null, 2]"
> q.add(5);
> q.toString()
"2 7 3 5"
> q.internalsString()
"[7, 3, 5, 2]"
> q.add(8);
> q.toString()
"2 7 3 5 8"
> q.internalsString()
"[2, 7, 3, 5, 8, null, null, null]"
> q.add(11);
> q.remove()
2
> q.toString()
"7 3 5 8 11"
> q.internalsString()
"[null, 7, 3, 5, 8, 11, null, null]"
>

6.5 (5%) (Honors CircularQueue Test Cases   grading

Test cases for the CircularQueue are provided in CircularQueueTests.java.

6.6 (10%) (Honors) CircularQueue Manual Inspection Criteria   grading

  • No shifting is done on adding/removing elements from the queue.
  • Internal fields are used to track the indices of the front and rear of the queue as well as other necessary features such as size.
  • The process to expand the internal space/array associated with the queue is clearly documented and has clean code to transfer elements from old to new array. Consider implementing this as a private internal method.
  • Methods that share functionality such as add() and offer() invoke one another to avoid copying/pasting code.
  • All fields of the class are clearly named and documented.

7 Other Manual Inspection Criteria

7.1 (5%) Correct Project Setup   grading

Correctly setting up the directory structure for each project greatly eases the task of grading lots of projects. Graders get cranky when strange directory structures or missing files are around and you do not want cranky graders. The following will be checked for setup on this project.

  • The Setup instructions were followed closely
  • The Project Directory is named according to the specification
  • There is an Identity Text File present with the required information in it
  • Code can be compiled and tests run from the command line

7.2 (5%) Coding Style and Readability   grading

Reading code is made much easier if it is styled reasonably well. On this assignment, you will get credit for properly doing the following:

  • Indenting and {bracketing} code uniformly throughout the program
  • Including comments above each method which describe its purpose and any limitations. Some information can be transcribed from the project specification.
  • commenting complex parts of code to describe what is happening in them. Some methods are required to have these, while others may need them if your approach is unusual.

On subsequent assignments, you may be penalized for dirty-looking code and lazy/absent commenting, so get in good habits now while there are rewards for it.

8 Running the Automated Tests

8.1 (50%) Automated Tests   grading

We are providing a battery of unit tests in the file P2Tests.java which test the code. These are examples and may not be the exact tests used for evaluation so you may want to begin studying how these tests work and experiment with your own.

8.2 Command Line Invocation of Tests

Graders will mostly run tests on the command line while grading so it is in your own interest to verify that your code passes the tests when run on the command line, as it will let you see what you will get on this portion of the assignment.

To run the tests on the command line, make sure that junit-cs211.jar is in the project directory. This file contains th JUnit library for running tests, and is part of the code distribution linked at the top of the project specification).

Systems Discrepancy: Windows uses a semicolon to separate paths, but Unix/Mac OSX uses a colon in the same place (see below). It is easy to overlook the difference! They look nearly the same if you're not looking closely. We will provide both versions here, but pay attention to what machine you're on and use the correct style.

Unix Users (including Mac OS X): To test your code use the following commands at the terminal. The OS-prompt here is >. (Don't type those leading >'s).

# Compile and Run tests for first problem
> javac -cp junit-cs211.jar:. SlopeInterceptLETests.java
> java -cp junit-cs211.jar:. SlopeInterceptLETests
JUnit version 4.12
.....
Time: 0.106

OK (5 tests)
...

# Similar compile/run for other classes

# Run tests for all problems simultaneously
> javac -cp .:junit-cs211.jar *.java
> java -cp .:junit-cs211.jar P2Tests
JUnit version 4.12
..........................................................................................
Time: 0.017

OK (38 tests)

Windows Users: To test your code use the following commands which replaces colons with SEMICOLONS. Other examples throughout the specification will use colons, but you are smart and will remember to use semicolons in all situations like this classpath situation. Here, the prompt is shown as >. (Don't actually type those >'s).

# Compile and Run tests for first problem
> javac -cp junit-cs211.jar;. SlopeInterceptLETests.java
> java -cp junit-cs211.jar;. SlopeInterceptLETests
JUnit version 4.12
.....
Time: 0.106

OK (5 tests)

8.3 Testing with Dr. Java

DrJava can run these tests by opening the various test files and clicking on the Test button. Be sure to successfully compile first. Click on test errors to jump to the test code. Useful! This JUnit testing integration is one of the reasons DrJava is supported in our class.

9 Project Submission

9.1 Provided Files

Download the zip file p2pack.zip which contains necessary files for this assignment. Unzip this file which will create a folder which you should as you project directory as described below.

9.2 Project Directory

Rename the pXpack directory (folder) according to the project directory convention: NetID-LabSecNum-pNum where

  • masonID is your GMU Net ID, the first part of your GMU email address.
  • labSecNum is your lab section number, such as 201, 202, 2H1, etc.
  • pNum represents the project number, such as p1.

Examples

  • msnyde14-2H1-pX for Mark Snyder in lab section 2H1
  • ckauffm2-205-pX for Chris Kauffman in lab section 205

All work you do should be saved in your project directory for eventual zipping and submission.

9.3 Identity Text File

Create a text file in your project directory called ID.txt which has identifying information in it. A sample ID.txt looks like this:

Mark Snyder
msnyde14
G0071234
Lecture: 002
Lab: 205

It contains a full name, mason ID, G#, lecture section, and lab section in it.

Failure to submit your work in an appropriately named directory and with the ID.txt file in it with correct information will result in the loss of 5%.

9.4 Submission

Create a zip file of your homework directory and submit it to the course Blackboard page. Do not e-mail the professor or TAs your code.

Create a .zip file of your directory as you will learn in the first programming lab.

To submit your zip to Blackboard:

  • Click on the Projects Link
  • Click on Project 2
  • Scroll down to "Attach a File"
  • Click "Browse My Computer"
  • Select your Zip file

You may submit as many times as you like; only the final valid submission will be graded. If you turn in late work within 48 hours, it will consume late tokens. If you turn in late work beyond 48 hours, that particular submission is invalid and will be ignored.

You should always verify that your submission is successful. Go back to the assignment and download your last submission; is there actually a file there? Can you unzip that file, and see .java files in there as you'd expect? Can you run those files? It turns out you can do quite a bit to ensure you've properly submitted your work. Don't get a zero just because of a failure to actually turn in the right files! It is your responsibility to correctly turn in your work.