Harvey Mudd College
Computer Science 60
Assignment 4, Due Friday, Sep. 29, by midnight

Starbucks Menus Java Lists and applications

This assignment consists of writing three Java files. The first is a linked list that emulates rex's lists. The second is a "port" of the Unit-conversion calculator that the last two assignments have developed. The final file is a Queue data structure, which is another linked list, but one which accepts items only at the back of the list and that releases items only at the front.

The key ideas are that a lot of the functionality that's available in Rex is also available in Java, but Java makes it easier to write code that takes advantage of side effects ("closed" lists like the Queue). In addition, this week's assignment is meant to provide enough practice with Java references and Java syntax that they will be less of an issue in the more involved algorithms and graphical programs.

Submitting your code

For this assignment, you will need to create three files, named OpenList.java, Unicalc.java, and Queue.java.

To submit the files, you will need to run

cs60submit 4
from the directory in which they are located.

Reading

This assignment continues through the book's Chapter 7. However, Chapter 6 is not necessary... (we will come back to Chapter 6 later in the course). Also, most (hopefully all) of the material needed to do this assignment will be presented in class.

Testing your code

Code to test each of the (three) Java classes you're writing in this assignment appear in the files /cs/cs60/as/a4/Test#.java . You can use these by


Lastly, you can compare the output with that in /cs/cs60/as/a4/Test#.out. You can compare your output visually, or, to be sure they're exactly the same, run
java Test# | diff - /cs/cs60/as/a4/Test#.out
If there is no output from the diff command, your output matches the expected output perfectly. If there are output lines from the diff command, those beginning with < are lines appearing in your output, but not the expected output. Lines beginning with > are lines appearing in the expected output, but not your output.

In Queue.examples and OpenList.examples (in /cs/cs60/as/a4), there are toString methods (and perhaps other helpful code). USE THOSE METHODS (named toString in your code! That way everyone's output formatting will be consistent.

Problems (only three of them...)

1. An OpenList class

This problem is meant to introduce the implementation of data structures in Java without abandoning all of the good features of rex. In addition, it is a chance to review what Java looks like and how java code is structured. (If you haven't used Java before, you may need to review a bit about the language. There is example java code in /cs/cs60/as/a4 and there are lots of on-line references available from the references page.)

Write a java class named OpenList in a file named OpenList.java. OpenList should implement an (open) linked list data structure, which is the kind of list rex uses. In fact, this problem is, essentially, the first step in writing the rex programming language in Java.

Write your class in a file called OpenList.java. Open lists are not modified in the computer's memory (so that there is no worry about side effects) -- instead, each function returns a newly created list (or whatever data is appropriate).

First, in your OpenList class, you will want to indicate the data that comprises a list. Using rex's philosophy of a list being a first and a rest, your data members should include two java Objects:

          Object first;
          OpenList rest;
     
In fact, these are the only data members you will need in your list implementation. Notice that because the data member named first is of type Object, this implementation of lists will be able to create lists of any Java Objects. (Everything in Java is an Object except the types int, double, float, boolean, byte, char, and long.) We will use only Strings and OpenLists for this problem. The next problem will put this OpenList class to use.

For your OpenList class, implement the following functions (often called methods in Java):



To test your code (and please test as you go along!!), you may want to write a method with the familiar signature
     public static void main(String[] arg)
     
In that method you can create OpenLists, perform some operations on them and then print out the results. Also, the test files in /cs/cs60/as/a4 check that portions of your code are working. Examples of such test runs are in the files /cs/cs60/as/a4/Test#.in.



Hint: for append and reverse, using recursion will make your code much simpler... . Java supports recursion to the same extent that rex does, though the syntax looks a bit different.

2. Unicalc

The second problem is to write a class named Unicalc in a file named Unicalc.java. You will use Open Lists to handle the data (units, quantity lists, etc.) for the Unicalc application.

Your Unicalc class is an "execute-only" class. That is, no objects of type "Unicalc" will be made and so the Unicalc class will consist of only static methods.

The unit-conversion calculator is written in rex in /cs/cs60/as/a3/hw3.rex, the solutions to assignment 3. You don't have to emulate that recursive rex code, but it does make things easier than trying to implement it without recursion. Many people avoid recursion at all costs... in this problem those costs are high.

You will need to write four of Unicalc's methods:

(1)  static OpenList simplify(OpenList L) {...}
(2)  static OpenList multiply(OpenList L, OpenList M) {...}
(5)  static OpenList norm_unit(String s, OpenList db) {...}
(6)  static OpenList norm(OpenList QL, OpenList db) {...}
The others:
(*)  static OpenList sort(OpenList L) {...}
(*)  static OpenList assoc(String s, OpenList db) {...}
(*)  static OpenList getDB() {...}
(*)  static String stringMult(String x, String y) {...}
(*)  static String stringDiv(String x, String y) {...}
(3)  static OpenList divide(OpenList L, OpenList M) {...}
(4)  static OpenList conv_unit(String s, OpenList db) {...}
(7)  static void convert(OpenList FromQL, OpenList ToQL, OpenList db) {...}
are already written for you and are in /cs/cs60/as/a4/Unicalc.examples. These are various utilities, for example, stringMult, converts strings to doubles, multiplies them, and converts the result back to a string. This uses an intermediate class called a Double (built-in to Java) that "wraps" a double so that it can be treated as an object. You will want to copy these methods into your Unicalc class right away and comment it out. Then, as you add the functions that code requires, you can uncomment the copied code and run your class against the tests. Also, to start you off, we will discuss the simplify method in class.

Keep in mind that all methods in your Unicalc class will be static. And, because you'll never create a Unicalc object, you do not need to write any constructors... .

You may want to write additional methods in your OpenList class or Unicalc class: feel free to add whatever functionality you might need.

Important Notes on Unicalc

3. A Queue class

Write a java class named Queue that implements a closed-list version of a Queue. Recall that a Queue is a list in which data are added (enqueued) at the back and removed (dequeued) from the front.

As a starting point, you might want to consider the Stack class covered in class and available in /cs/cs60/as/a4/Stack.java. Your Queue class should have two QCell data members: front and back.

In any case, you need to have the following things in your Queue class:

You can test your Queue class (when the toString mewthod is included) as indicated in the "Testing your code" section above.

The completely optional extra credit involves extending your Queue class.

4. Extra Credit

For totally optional extra credit (up to 20%), add a nonstatic method evaluate to your Queue class. The idea is to add something of a real calculator to complement the unit calculator of problem #2. The signature of the evaluate method is simply
  double evaluate() 
  
What evaluate does is return a double that is the "value" of the Queue that invoked the method (the "this" Queue). That is, evaluate looks through the items on its Queue one by one as if they were forming an arithmetic expression. Then it evaluates that expression. You can assume that every data element in the Queue will be either a Double or a String that is one of "+", "-", "*", or "/". (Remember that Double is a Java wrapper class so that values of type double can be treated as Objects. The "*" and "/" should be executed immediately -- at highest priority -- and the "+" and "-" have lower priority. For example, if the Queue Q consisted of
  10 + 4 * 5 / 2 - 3
  
where the left is the front of the Queue and the right is the back (most recently inserted elements), then Q.evaluate() should go through these steps:
  10
  10 + 4
  10 + 4 * 5 == 10 + 20
  10 + 20 / 2 == 10 + 10
  10 + 10 - 3 == 20 -3
  20 - 3 == 17 
  
Any implementation that provides the correct answer (17 in this case) is all right.