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.
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 4from the directory in which they are located.
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
java Test# | diff - /cs/cs60/as/a4/Test#.outIf 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.
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):
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.
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.
For example, suppose that QL is an OpenList that is a quantity list. Then, QL.first() returns an Object that is really the amount portion of the quantity list. We are storing these amounts as Strings. So, to make sure that java knows that it is a string, you need code like
String amount = (String) (QL.first());
You can multiply or divide strings (if they really hold numbers)
with the provided stringMult and stringDiv
methods.
As another example, the second element of QL (as long as
QL is a Quantity List) is itself an OpenList -- namely, the
OpenList of all of the units in the numerator. To get at this
numerator list, use
OpenList N = (OpenList)(QL.second());
As long as the method second is defined appropriately,
N will now be the numerator list that can be used for
further processing.
(Individual elements of the numerator and denominator lists
will still have to be cast to Strings.)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:
static void enqueue(Object o, Queue Q) {...}
and
void enqueue(Object o) {...}
static Object dequeue(Queue Q) {...}
and
Object dequeue() {...}
Both methods should return null if dequeue
is called on an empty Queue.
static boolean isEmpty(Queue Q) {...}
and
boolean isEmpty() {...}
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.
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 - 3where 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 == 17Any implementation that provides the correct answer (17 in this case) is all right.