/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package automata.turing;
import automata.Transition;
import automata.State;
import java.util.*;
/**
* The TMTransition
is a transition for a Turing machine.
*
* @see automata.turing.TuringMachine
*
* @author Thomas Finley
*/
public class TMTransition extends Transition {
//added for turing to grammar conversion
private int tapes;
/**
* Produces a one tape Turing transition.
*
* @param from
* the state this transition comes from
* @param to
* the state this transition goes to
* @param ntoRead
* the string that the machine should satisfy before moving on to
* the next state
* @param ntoWrite
* the string that the machine should write on to the tape
* @param ndirection
* the direction to move the read/write tape head
*/
public TMTransition(State from, State to, String ntoRead, String ntoWrite,
String ndirection) {
this(from, to, new String[] { ntoRead }, new String[] { ntoWrite },
new String[] { ndirection });
}
/**
* Produces a Turing transition. The number of tapes for this Turing machine
* transition is inferred from the number of elements in the arrays
*
* @param from
* the state this transition comes from
* @param to
* the state this transition goes to
* @param toReadArray
* the strings that the machine should satisfy in each tape
* before moving on to the next state
* @param toWriteArray
* the strings that the machine should write on each tape
* @param directionArray
* the direction to move the read/write tape head on each tape
* @throws IllegalArgumentException
* if the number of elements in each array is not the same, or
* the arrays are empty
*/
public TMTransition(State from, State to, String[] toReadArray,
String[] toWriteArray, String[] directionArray) {
super(from, to);
if (toReadArray.length != toWriteArray.length
|| directionArray.length != toReadArray.length)
throw new IllegalArgumentException(
"Read symbols, write symbols, and directions "
+ "must have equal numbers of elements!");
tapes = toReadArray.length;
if (tapes == 0)
throw new IllegalArgumentException(
"Attempted to create a transition with 0 tapes!");
toRead = new ArrayList();
toWrite = new ArrayList();
direction = new ArrayList();
for (int i = 0; i < tapes; i++) {
toRead.add("");
toWrite.add("");
direction.add("");
setRead(toReadArray[i], i);
setWrite(toWriteArray[i], i);
setDirection(directionArray[i], i);
}
}
/**
* Gets the number of tapes in the Turing Machine.
* @return tapes number of tapes in machine.
*/
public int getTapeLength()
{
return tapes;
}
/**
* Produces a copy of this transition with new from and to states.
*
* @param from
* the new from state
* @param to
* the new to state
* @return a copy of this transition with the new states
*/
public Transition copy(State from, State to) {
String[] s = new String[0];
return new TMTransition(from, to, (String[]) toRead.toArray(s),
(String[]) toWrite.toArray(s), (String[]) direction.toArray(s));
}
/**
* Returns the input to read for the given tape.
*
* @param tape
* the tape index to retrieve
*/
public String getRead(int tape) {
return (String) toRead.get(tape);
}
public void setRead(int tape, String symbol) {
toRead.set(tape, symbol);
}
public void setWrite(int tape, String symbol) {
toWrite.set(tape, symbol);
}
/**
* Sets the input to read for a given tape.
*
* @param stringToRead
* the input to read for a given tape
* @param tape
* the tape index
*/
protected void setRead(String stringToRead, int tape) {
if (stringToRead.length() == 0)
stringToRead = BLANK;
if (stringToRead.equals("!"))
stringToRead = "!"+ BLANK;
if (stringToRead.length() != 1
&& !(stringToRead.startsWith("!") || stringToRead.equals("~") || stringToRead
.indexOf("}") != -1)) {
throw new IllegalArgumentException(
"Read string must have exactly one character!");
}
if (stringToRead.indexOf("}") != -1 && stringToRead.indexOf("!") != -1)
throw new IllegalArgumentException(
"Read string cannot cannot mix variable assignment in the NOT (!) operator.");
toRead.set(tape, stringToRead);
}
/**
* Returns the string to write to tape portion of the transition label for
* this transition.
*
* @param tape
* the tape to return the
*/
public String getWrite(int tape) {
return (String) toWrite.get(tape);
}
/**
* Sets the string to write to tape for the given tape.
*
* @param stringToWrite
* the string to write to tape
* @param tape
* which tape to write
*/
protected void setWrite(String stringToWrite, int tape) {
if (stringToWrite.length() == 0)
stringToWrite = BLANK;
if (stringToWrite.length() != 1)
throw new IllegalArgumentException(
"Write string must have exactly one character!");
toWrite.set(tape, stringToWrite);
}
/**
* Returns the direction to move the tape head for one of the tapes.
*
* @param tape
* the tape index which this direction will affect
* @return the transition's direction for this tape
*/
public String getDirection(int tape) {
return (String) direction.get(tape);
}
/**
* Sets the direction to move the read/write tape head.
*
* @param newDirection
* the new direction to move the tape head
* @param tape
* the tape index to change the direction for, indexed 0 through
* one less than the number of tapes
*/
protected void setDirection(String newDirection, int tape) {
if (!(newDirection.equals("L") || newDirection.equals("R") || newDirection
.equals("S")))
throw new IllegalArgumentException("Direction must be L, R, or S!");
direction.set(tape, newDirection);
}
/**
* Returns the number of tapes this Turing machine transition acts on.
*
* @return the number of tapes
*/
public int tapes() {
return toRead.size();
}
/**
* Returns the description for this transition.
*
* @return the description, in this case, the input to read from the tape,
* the string to write to the tape, and the direction to move the
* read/write tape head for each tape
*/
public String getDescription() {
StringBuffer sb = new StringBuffer();
int t = this.tapes();
for (int i = 0; i < t; i++) {
if (i != 0)
sb.append(" | ");
sb.append((String) toRead.get(i));
if (!blockTransition) {
sb.append(" ; ");
sb.append((String) toWrite.get(i));
sb.append(" , ");
sb.append((String) direction.get(i));
}
}
return sb.toString();
}
/**
* Returns a string representation of this object. This is the same as the
* string representation for a regular transition object, with the
* additional fields tacked on.
*
* @see automata.Transition#toString
* @return a string representation of this object
*/
public String toString() {
return super.toString() + ": \"" + this.getDescription() + "\"";
}
/**
* Returns the hashcode for this transition.
*
* @return the hashcode for this transition
*/
public int hashCode() {
int code = super.hashCode() ^ toRead.hashCode() ^ toWrite.hashCode()
^ direction.hashCode();
return code;
}
/**
* Tests this transition against another object for equality.
*
* @param object
* the object to test for equality
* @return true
if this transition equals the passed in
* object, false
otherwise
*/
public boolean equals(Object object) {
try {
TMTransition t = (TMTransition) object;
return super.equals(object) && toRead.equals(t.toRead)
&& toWrite.equals(t.toWrite)
&& direction.equals(t.direction);
} catch (ClassCastException e) {
return false;
}
}
/**
* Is the transition a block transition?
* @return boolean whether the Transition is a Block Transition.
*/
public boolean isBlockTransition() {
return blockTransition;
}
public void setBlockTransition(boolean block) {
blockTransition = block;
}
private boolean blockTransition = false;
/** The read symbols. */
private List toRead;
/** The write symbols. */
private List toWrite;
/** The direction fields. */
private List direction;
/** The blank symbol. */
public static final String BLANK = "" + Tape.BLANK;
}