/*
* 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.Automaton;
import automata.Transition;
import automata.State;
import automata.Note;
import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import java.util.Collection;
import java.io.Serializable;
import java.io.File;
import gui.action.OpenAction;
import gui.environment.EnvironmentFrame;
import javax.swing.JButton;
/**
* This subclass of Automaton
is specifically for a definition of
* a Turing machine, possibly with multiple tapes.
*
* We also redefine equals(), and clone(), as well as become() to deal with Building Blocks, so that we don't have to deal with them in Automaton.
*
* @author Thomas Finley, Henry Qin
*/
public class TuringMachine extends Automaton {
/**
* Creates a 1-tape Turing machine with no states and no transitions.
*/
public TuringMachine() {
this(1);
}
/**
* Creates a Turing machine with a variable number of tapes, no states, and
* no transitions.
*
* @param tapes
* the number of tapes for the Turing machine
*/
public TuringMachine(int tapes) {
super();
this.tapes = tapes;
}
/**
* Returns the class of Transition
this automaton must
* accept.
*
* @return the Class
object for automata.tm.TMTransition
*/
protected Class getTransitionClass() {
return automata.turing.TMTransition.class;
}
/**
* Adds a transition to this Turing machine.
*
* @param t
* the transition to add
* @throws IllegalArgumentException
* if this transition requires a different number of tapes than
* required by other Turing machines
*/
public void addTransition(Transition t) {
try {
int ttapes = ((TMTransition) t).tapes();
if (tapes == 0)
tapes = ttapes;
if (ttapes != tapes)
throw new IllegalArgumentException("Transition has " + ttapes
+ " tapes while TM has " + tapes);
super.addTransition(t);
} catch (ClassCastException e) {
}
}
/**
* Returns the number of tapes this Turing machine uses.
*
* @return the number of tapes this Turing machine uses
*/
public int tapes() {
return tapes;
}
/**
* Creates a TMState, inserts it in this automaton, and returns that state.
* The ID for the state is set appropriately.
* This method was once Final in Automaton, but it must be overriden here, because TMStates are not like standard states.
*
* @param point
* the point to put the state at
*/
public State createState(Point point) {
return createTMState(point);
}
/**
* We need to implement our own clone() method, rather than use that of Automaton, because we use TMStates instead of ordinary states, and we handle the building block cloning in a more elegant way.
*/
public Object clone() {
//MERLIN MERLIN MERLIN MERLIN MERLIN//
TuringMachine a = new TuringMachine(this.tapes());
a.setEnvironmentFrame(this.getEnvironmentFrame());
HashMap map = new HashMap(); // Old states to new states.
for (Object o: states){
// System.out.println(o.getClass().getName());
TMState tms = (TMState)o;
TMState ntms = new TMState(tms);//I could write a clone for that TM too, I suppose, but there's nothing wrong with a nice C++ style copy constructor
ntms.setAutomaton(a); //recognize thine new master, after the convenience of the copy constructor, lest there be great many bugs.
ntms.setLabel(tms.getLabel());
ntms.setName(tms.getName());
map.put(tms, ntms);
a.addState(ntms);
//using OBJECT equality, and OBJECT hashcode, which is fine here because we want to know if the objects are literally the same (which they should be)
}
for (Object o: finalStates){
TMState tms = (TMState) o;
a.addFinalState(map.get(tms));
}
a.setInitialState((TMState) map.get((TMState) getInitialState()));
for (Object o: states){
TMState tms = (TMState)o;
Transition[] ts = getTransitionsFromState(tms);
TMState from = map.get(tms);
for (int i = 0; i < ts.length; i++) {
TMState to = map.get(ts[i].getToState());
Transition toBeAdded = (Transition)ts[i].clone();
toBeAdded.setFromState(from);
toBeAdded.setToState(to);
// a.addTransition(ts[i].copy(from, to));
a.addTransition(toBeAdded);
}
}
return a;
}
/**
* Creates a state, inserts it in this automaton, and returns that state.
* The ID for the state is set appropriately.
*
* @param point
* the point to put the state at
*/
public final TMState createBlock(Point point) {
int i = 0;
while (getStateWithID(i) != null)
i++;
OpenAction read = new OpenAction();
OpenAction.setOpenOrRead(true);
JButton button = new JButton(read);
button.doClick();
OpenAction.setOpenOrRead(false);
return getAutomatonFromFile(i, point);
}
/**
* Reads the automaton in from a file.
*/
private TMState getAutomatonFromFile(int i, Point point) {
TMState block = new TMState(i, point, this);
Serializable serial = OpenAction.getLastObjectOpened();
File lastFile = OpenAction.getLastFileOpened();
if (lastFile == null || OpenAction.isOpened() == false) {
return null;
}
// block = putBlockContentsInAutomaton(block, serial, lastFile.getName(),
// this);
assert serial instanceof TuringMachine;
TuringMachine tm = (TuringMachine) serial;
tm.setEnvironmentFrame(this.getEnvironmentFrame());
block.setInternalName(lastFile.getName());
//MERLIN MERLIN MERLIN MERLIN MERLIN//
block.setInnerTM(tm);
block.setName(lastFile.getName().substring(0, lastFile.getName().length() - 4));
addState(block);
return block;
}
/**
* For the sake of separation, some methods must unfortunately be duplicated.
*
*
*/
public final TMState createTMStateWithID(Point p, int i){
TMState state = new TMState(i, p, this);
addState(state);
return state;
}
/**
* For the sake of separation, some methods must unfortunately be duplicated.
*
*
*/
public final TMState createTMState(Point point) {
int i = 0;
while (getStateWithID(i) != null)
i++;
TMState state = new TMState(i, point, this);
addState(state);
return state;
}
public TMState createInnerTM(Point point, Serializable auto, String name, int i) {
TMState ntms = new TMState(i, point, this);
TuringMachine innerTM = (TuringMachine) auto;
addState(ntms);
ntms.setInnerTM(innerTM);
ntms.setInternalName(name);
return ntms;
}
public static void become(TuringMachine dest, TuringMachine src){
System.out.println("Calling the real become");
dest.clear();
// Copy over the states.
HashMap map = new HashMap(); // Old states to new states.
// Iterator it = src.states.iterator();
for (Object o: src.states){
System.out.println(o.getClass().getName());
TMState state = (TMState) o;
TMState nstate = new TMState(state.getID(),
new Point(state.getPoint()), dest); //this time we're not using copy constructor
// copyStaticRelevantDataForBlocks(nstate, state, dest, src);
nstate.setLabel(state.getLabel());
nstate.setName(state.getName());
map.put(state, nstate);
dest.addState(nstate);
}
// Set special states.
for (Object o: src.finalStates){
TMState tms = (TMState) o;
dest.addFinalState(map.get(tms));
}
dest.setInitialState((TMState) map.get((TMState) src.getInitialState()));
// Copy over the transitions.
for (Object o: src.states){
TMState tms = (TMState)o;
Transition[] ts = src.getTransitionsFromState(tms);
TMState from = map.get(tms);
for (int i = 0; i < ts.length; i++) {
TMState to = map.get(ts[i].getToState());
Transition toBeAdded = (Transition)ts[i].clone();
toBeAdded.setFromState(from);
toBeAdded.setToState(to);
// dest.addTransition(ts[i].copy(from, to));
dest.addTransition(toBeAdded);
}
}
for(int k = 0; k < src.getNotes().size(); k++){
Note curNote = (Note)src.getNotes().get(k);
dest.addNote(new Note(curNote.getAutoPoint(), curNote.getText()));
((Note)dest.getNotes().get(k)).initializeForView(curNote.getView());
}
dest.setEnvironmentFrame(src.getEnvironmentFrame());
// EDebug.print("finished");
}
public Map getBlockMap(){
Map ret = new HashMap();
for (TMState s: (Collection) states) //that's right, EVERY state in TM has an inner Auto, even if that inner auto might be empty.
ret.put(s.getInternalName(), s.getInnerTM());
return ret;
}
public void setParent(TMState tms){
parent = tms;
}
public TMState getParent(){
return parent;
}
/**
* The number of tapes. It's public for some hacky reasons related to
* serialization.
*/
public int tapes;
public boolean isOuterMost;
//MERLIN MERLIN MERLIN MERLIN MERLIN//
private TMState parent = null; //not going to force it with compiler, just make sure you set it WHERE it MATTERS
}