Here is a Turing Machine implemented in Java as described by the Wikipedia article:
https://en.wikipedia.org/wiki/Turing_machine
With the copy subroutine test taken from:
https://en.wikipedia.org/wiki/Turing_machine_examples
Tape.java
package org.adrianwalker.turingmachine;
import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;
import static java.util.stream.IntStream.rangeClosed;
import java.util.List;
import java.util.TreeMap;
public final class Tape {
private final TreeMap<Integer, String> cells;
private final String blank;
public Tape(final String blank) {
this.cells = new TreeMap<>();
this.blank = blank;
}
public List<String> getCells() {
return rangeClosed(cells.firstKey(), cells.lastKey())
.boxed()
.map(i -> getCell(i))
.collect(toList());
}
public void putCells(final List<String> symbols) {
range(0, symbols.size())
.boxed()
.forEach(i -> putCell(i, symbols.get(i)));
}
public String getCell(final int position) {
return cells.getOrDefault(position, blank);
}
public void putCell(final int position, final String symbol) {
cells.put(position, symbol);
}
}
Head.java
package org.adrianwalker.turingmachine;
public final class Head {
private final Tape tape;
private final String leftSymbol;
private final String rightSymbol;
private final String noOpSymbol;
private int position = 0;
public Head(
final Tape tape,
final String leftSymbol, final String rightSymbol, final String noOpSymbol) {
this.tape = tape;
this.leftSymbol = leftSymbol;
this.rightSymbol = rightSymbol;
this.noOpSymbol = noOpSymbol;
}
public void move(final String symbol) {
if (noOpSymbol.equals(symbol)) {
return;
}
if (leftSymbol.equals(symbol)) {
position -= 1;
} else if (rightSymbol.equals(symbol)) {
position += 1;
}
}
public String read() {
return tape.getCell(position);
}
public void write(final String symbol) {
if (noOpSymbol.equals(symbol)) {
return;
}
tape.putCell(position, symbol);
}
}
StateRegister.java
package org.adrianwalker.turingmachine;
public final class StateRegister {
private final String haltState;
private String state;
public StateRegister(final String haltState, final String startState) {
this.haltState = haltState;
this.state = startState;
}
public boolean isHaltState() {
return state.equals(haltState);
}
public String getState() {
return state;
}
public void setState(final String state) {
this.state = state;
}
}
Table.java
package org.adrianwalker.turingmachine;
import java.util.HashMap;
import java.util.Map;
public final class Table {
public static final class Entry {
private final String state;
private final String symbol;
private final String writeSymbol;
private final String moveTape;
private final String nextState;
public Entry(
final String state, final String symbol,
final String writeSymbol, final String moveTape, final String nextState) {
this.state = state;
this.symbol = symbol;
this.writeSymbol = writeSymbol;
this.moveTape = moveTape;
this.nextState = nextState;
}
public String getState() {
return state;
}
public String getSymbol() {
return symbol;
}
public String getWriteSymbol() {
return writeSymbol;
}
public String getMoveTape() {
return moveTape;
}
public String getNextState() {
return nextState;
}
}
private static final String SEPARATOR = "_";
private final Map<String, Entry> table;
public Table() {
table = new HashMap<>();
}
public void put(
final String state, final String symbol,
final String writeSymbol, final String moveTape, final String nextState) {
table.put(
state + SEPARATOR + symbol,
new Entry(state, symbol, writeSymbol, moveTape, nextState));
}
public Entry get(final String state, final String symbol) {
return table.get(state + SEPARATOR + symbol);
}
}
TuringMachine.java
package org.adrianwalker.turingmachine;
import org.adrianwalker.turingmachine.Table.Entry;
public final class TuringMachine {
private final Head head;
private final StateRegister stateRegister;
private final Table table;
public TuringMachine(final Head head, final StateRegister stateRegister, final Table table) {
this.head = head;
this.stateRegister = stateRegister;
this.table = table;
}
public long execute() {
long steps = 0;
while (!stateRegister.isHaltState()) {
steps++;
String state = stateRegister.getState();
String symbol = head.read();
Entry entry = table.get(state, symbol);
head.write(entry.getWriteSymbol());
head.move(entry.getMoveTape());
stateRegister.setState(entry.getNextState());
}
return steps;
}
}
TuringMachineTest.java
package org.adrianwalker.turingmachine;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public final class TuringMachineTest {
private static final String BLANK = "0";
private static final String MOVE_LEFT = "L";
private static final String MOVE_RIGHT = "R";
private static final String NO_OP = "N";
private static final String HALT_STATE = "H";
private static final String START_STATE = "A";
@Test
public void testBusyBeaver() {
Tape tape = new Tape(BLANK);
Head head = new Head(tape, MOVE_LEFT, MOVE_RIGHT, NO_OP);
StateRegister stateRegister = new StateRegister(HALT_STATE, START_STATE);
Table table = new Table();
table.put("A", "0", "1", "R", "B");
table.put("A", "1", "1", "L", "C");
table.put("B", "0", "1", "L", "A");
table.put("B", "1", "1", "R", "B");
table.put("C", "0", "1", "L", "B");
table.put("C", "1", "1", "N", "H");
TuringMachine machine = new TuringMachine(head, stateRegister, table);
long steps = machine.execute();
assertEquals(13, steps);
assertEquals(asList("1", "1", "1", "1", "1", "1"), tape.getCells());
}
@Test
public void testCopySubroutine() {
Tape tape = new Tape(BLANK);
tape.putCells(asList("1", "1", "1"));
Head head = new Head(tape, MOVE_LEFT, MOVE_RIGHT, NO_OP);
StateRegister stateRegister = new StateRegister(HALT_STATE, START_STATE);
Table table = new Table();
table.put("A", "0", "N", "N", "H");
table.put("A", "1", "0", "R", "B");
table.put("B", "0", "0", "R", "C");
table.put("B", "1", "1", "R", "B");
table.put("C", "0", "1", "L", "D");
table.put("C", "1", "1", "R", "C");
table.put("D", "0", "0", "L", "E");
table.put("D", "1", "1", "L", "D");
table.put("E", "0", "1", "R", "A");
table.put("E", "1", "1", "L", "E");
TuringMachine machine = new TuringMachine(head, stateRegister, table);
long steps = machine.execute();
assertEquals(28, steps);
assertEquals(asList("1", "1", "1", "0", "1", "1", "1"), tape.getCells());
}
}
Source Code
- Code available in GitHub - turing-machine
Build and Test
The project is a standard Maven project which can be built with:
mvn clean install