CS 201 - Homework 5.5 (optional) - Turing Machines using Stacks and/or Queues

Due: Wednesday 11/25 at 8am

This is an optional assignment over fall break, consisting of a single programming problem. If you choose to do this assignment, I will include the score with all your other homework scores, and drop the overall lowest homework score when computing your final grade. You can thus use this assignment to make up for a (possibly future) poor homework score, or you can simply do it for fun and to improve your programming skills! :)

When you have completed the assignment, please submit your program Tape.java using the HW 5.5 submission page.


Simulating Tapes with linear data structures

In this assignment, you will implement an abstract data type (ADT) called a tape. Variations on this data type are commonly used in Turing machines - theoretical models of a computer, which you will learn about in CS 301. A tape is a linear sequence of cells that conceptually extends infinitely in both directions. Each cell holds a single character. Initially, all cells of a tape are assumed to be blank; we will model a blank cell as one that contains the asterisk character, '*'. Associated with a tape is a tape head that designates the "current" cell of the tape. The tape head is said to be "over" a particular cell in the tape. For example, here is an abstract view of a sample tape:


The diagram shows six cells of the tape, the center four of which contain letters that spell out Hawaii's favorite lunch meat. The ellipses on the sides indicate that blank cells extend infinitely to the left and to the right. The position of the tape head is indicated by a cell with a thick border. In this example, the tape head is over the cell containing the character 'p'.

The interface to tapes consists of the following five operations:

Constructor:

public Tape();

Create a new empty tape. The tape head is over a blank cell. Here is a depiction of an empty tape:


Instance methods:

public void store(char c);

Store character c on this tape in the cell under the tape head, overwriting previous contents. For example, storing a 'w' into the cell under the tape head in the above "spam" example would yield:


public void left();

Move the tape head of this tape one cell to the left. Applying this operation to the original "spam" example would yield:


public void right();

Move the tape head of this tape one cell to the right. Applying this operation to the original "spam" example would yield:


public void display();

Display (i.e., print) the contents of all cells in this tape ever visited by the tape head. Since the tape is infinite, it is impossible to display the contents of all the cells. However, since all cells are initially blank, and non-blank characters can only be stored by moving the tape head to a cell, the set of all cells visited by the tape head contains all the non-blank characters in the tape. (It may contain some blank ones as well.) The contents are displayed in left-to-right order. Furthermore, the position of the tape head is indicated by a pair of square brackets surrounding the contents of the cell under the tape head. In the original "spam" example, if we assume that all six cells have been visited by the tape head, then the displayed contents of the tape are

    * s [p] a m *
If only the four cells containing letters have been visited by the tape head, the output would be
    s [p] a m

Tape implementation

In this problem you will implement the tape ADT by implementing the five methods listed above. The current contents of the tape should be represented using three instance variables: current, left and right. The current variable should simply store the character currently under the tape head, while the other two variables variables should contain linear data structures storing characters that represent the contents of all cells ever visited to the left and to the right of the tape head, respectively.

No other instance variables should be used to represent the contents of the tape and the current head position. Given the original "spam" example (assuming all 6 cells were visited), current would contain 'p', left would contain "* s" (not necessarily in this order), and right would contain "a m *" (not necessarily in this order). Think carefully about what types of linear data structures to use for left and right: stacks, queues, or one of each?

Note that while you can use the primitive type char for the current variable, you will have to use the element type Character with your linear structures (as usual, Java will perform the necessary conversions automatically). For instance, if you wanted to use a stack for "left", you would declare your instance variable like this:

    Stack<Character> left;
and in the constructor you would initialize it to one of the implementations, e.g.
    left = new StackList<Character>();

What to do

To get you started, I'm providing a (mostly empty) Eclipse project. To use it, download and extract hw55.zip in your cs201 directory, which will result in a new directory hw55. Then, as for HW 5, start Eclipse, go to File->Import, select General->Existing Projects into Workspace, hit Next, select your "hw55" folder as "root directory", and hit finish. Next, in the "Package Explorer", expand "hw55", expand "(default package)", and open Tape.java. Your job is to implement the Tape class, which involves writing the above constructor and instance methods. No code is provided for this homework - you will have to write everything from scratch.

When you are first testing your implementation of the Tape class and methods, you can just construct a sequence of commands that call your methods directly from inside a main method in your file Tape.java. For example, you could use the following sequence of commands:

    public static void main (String[] args) {
        Tape t = new Tape();
        t.display();    // show current tape contents (empty tape)
        t.store('a');
        t.left();
        t.left();
        t.right();
        t.store('c');
        t.display();    // show current tape contents
        t.right();
        t.right();
        t.store('t');
        t.display();    // show current tape contents
    }
which should result in the following output:
         ~/cs201/hw55% java Tape
         [*] 
         * [c] a 
         * c a [t] 
Note: Implementing the "display()" method will be a little bit tricky, since I want you to use only the "add", "get", "remove", and "isEmpty" methods (or their aliases) when accessing the linear data structures. To iterate over all the elements, you will thus have to remove the elements and temporarily store them in another linear structure, and then "shuffle" them all back.

Once you are confident that your implementation is correct, modify your program so that the user can specify any sequence of tape operations by supplying a String of characters as a command-line argument. The characters in this string should encode the operations to be performed:

character  operation
<left();
>right();
?display();
cstore(c);
As the string is read left-to-right, the corresponding operations should be performed. Any character c that is not one of '>', '<', or '?' should be stored on the tape. To access the individual characters in a string, use the method charAt(). The length of a string can be determined using the method length(). For example, the following piece of code prints all characters in the first command-line argument:
        String s = args[0];
        for (int i=0; i < s.length(); i++) {
            char c = s.charAt(i);
            System.out.println(c);
        }
While Eclipse lets you specify command-line arguments (Run -> Run Configurations -> Arguments Tab), it will probably be easier to run your program from the command line like you did in the first 4 homeworks. Open a terminal window, navigate to your hw55 directory, and run your progam by typing "java Tape". (You can still use Eclipse for editing and compiling of course!) Note that you will have to enclose the entire string in single quotes to prevent the operating system from interpreting the characters '>', '<', '?' as control characters.

As always, a self-respecting program should print a usage message when called with the wrong number of arguments. Here are some sample runs:

    ~/cs201/hw55% java Tape 
    
       usage: java Tape 'command-string'
    
       command-string is a string of characters
       encoding the possible operations:
	 < = left()      > = right()
	 ? = display()   c = store(c)

    ~/cs201/hw55% java Tape '?'
    [*] 
    ~/cs201/hw55% java Tape 'a?'
    [a] 
    ~/cs201/hw55% java Tape '<?'
    [*] * 
    ~/cs201/hw55% java Tape '>?'
    * [*] 
    ~/cs201/hw55% java Tape 'abc>def?'
    c [f] 
    ~/cs201/hw55% java Tape 'abc>d?e?f?'
    c [d] 
    c [e] 
    c [f] 
    ~/cs201/hw55% java Tape 'h>e>l>l>o?'
    h e l l [o] 
    ~/cs201/hw55% java Tape '<<<<h>e>l>l>o?'
    h e l l [o] 
    ~/cs201/hw55% java Tape '<<<<<<<h>e>l>l>o?'
    h e l l [o] * * * 
    ~/cs201/hw55% java Tape '><m<a<p<s<>>?'
    * s [p] a m *