Task: Universal Turing machine



C#: using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class TuringMachine
{
    public static async Task Main() {
        var fiveStateBusyBeaver = new TuringMachine("A", '0', "H").WithTransitions(
            ("A", '0', '1', Right, "B"),
            ("A", '1', '1', Left,  "C"),
            ("B", '0', '1', Right, "C"),
            ("B", '1', '1', Right, "B"),
            ("C", '0', '1', Right, "D"),
            ("C", '1', '0', Left,  "E"),
            ("D", '0', '1', Left,  "A"),
            ("D", '1', '1', Left,  "D"),
            ("E", '0', '1', Stay,  "H"),
            ("E", '1', '0', Left,  "A")
        );
        var busyBeaverTask = fiveStateBusyBeaver.TimeAsync();

        var incrementer = new TuringMachine("q0", 'B', "qf").WithTransitions(
            ("q0", '1', '1', Right, "q0"),
            ("q0", 'B', '1', Stay,  "qf")
        )
        .WithInput("111");
        foreach (var _ in incrementer.Run()) PrintLine(incrementer);
        PrintResults(incrementer);

        var threeStateBusyBeaver = new TuringMachine("a", '0', "halt").WithTransitions(
            ("a", '0', '1', Right, "b"),
            ("a", '1', '1', Left,  "c"),
            ("b", '0', '1', Left,  "a"),
            ("b", '1', '1', Right, "b"),
            ("c", '0', '1', Left,  "b"),
            ("c", '1', '1', Stay,  "halt")
        );
        foreach (var _ in threeStateBusyBeaver.Run()) PrintLine(threeStateBusyBeaver);
        PrintResults(threeStateBusyBeaver);

        var sorter = new TuringMachine("A", '*', "X").WithTransitions(
            ("A", 'a', 'a', Right, "A"),
            ("A", 'b', 'B', Right, "B"),
            ("A", '*', '*', Left,  "E"),
            ("B", 'a', 'a', Right, "B"),
            ("B", 'b', 'b', Right, "B"),
            ("B", '*', '*', Left,  "C"),
            ("C", 'a', 'b', Left,  "D"),
            ("C", 'b', 'b', Left,  "C"),
            ("C", 'B', 'b', Left,  "E"),
            ("D", 'a', 'a', Left,  "D"),
            ("D", 'b', 'b', Left,  "D"),
            ("D", 'B', 'a', Right, "A"),
            ("E", 'a', 'a', Left,  "E"),
            ("E", '*', '*', Right, "X")
        )
        .WithInput("babbababaa");
        sorter.Run().Last();
        Console.WriteLine("Sorted: " + sorter.TapeString);
        PrintResults(sorter);

        sorter.Reset().WithInput("bbbababaaabba");
        sorter.Run().Last();
        Console.WriteLine("Sorted: " + sorter.TapeString);
        PrintResults(sorter);

        Console.WriteLine(await busyBeaverTask);
        PrintResults(fiveStateBusyBeaver);

        void PrintLine(TuringMachine tm) => Console.WriteLine(tm.TapeString + "\tState " + tm.State);

        void PrintResults(TuringMachine tm) {
            Console.WriteLine($"End state: {tm.State} = {(tm.Success ? "Success" : "Failure")}");
            Console.WriteLine(tm.Steps + " steps");
            Console.WriteLine("tape length: " + tm.TapeLength);
            Console.WriteLine();
        }
    }

    public const int Left = -1, Stay = 0, Right = 1;
    private readonly Tape tape;
    private readonly string initialState;
    private readonly HashSet<string> terminatingStates;
    private Dictionary<(string state, char read), (char write, int move, string toState)> transitions;

    public TuringMachine(string initialState, char blankSymbol, params string[] terminatingStates) {
        State = this.initialState = initialState;
        tape = new Tape(blankSymbol);
        this.terminatingStates = terminatingStates.ToHashSet();
    }

    public TuringMachine WithTransitions(
        params (string state, char read, char write, int move, string toState)[] transitions)
    {
        this.transitions = transitions.ToDictionary(k => (k.state, k.read), k => (k.write, k.move, k.toState));
        return this;
    }

    public TuringMachine Reset() {
        State = initialState;
        Steps = 0;
        tape.Reset();
        return this;
    }

    public TuringMachine WithInput(string input) {
        tape.Input(input);
        return this;
    }

    public int Steps { get; private set; }
    public string State { get; private set; }
    public bool Success => terminatingStates.Contains(State);
    public int TapeLength => tape.Length;
    public string TapeString => tape.ToString();

    public IEnumerable<string> Run() {
        yield return State;
        while (Step()) yield return State;
    }

    public async Task<TimeSpan> TimeAsync(CancellationToken cancel = default) {
        var chrono = Stopwatch.StartNew();
        await RunAsync(cancel);
        chrono.Stop();
        return chrono.Elapsed;
    }

    public Task RunAsync(CancellationToken cancel = default)
        => Task.Run(() => {
            while (Step()) cancel.ThrowIfCancellationRequested();
        });

    private bool Step() {
        if (!transitions.TryGetValue((State, tape.Current), out var action)) return false;
        tape.Current = action.write;
        tape.Move(action.move);
        State = action.toState;
        Steps++;
        return true;
    }


    private class Tape
    {
        private List<char> forwardTape = new List<char>(), backwardTape = new List<char>();
        private int head = 0;
        private char blank;

        public Tape(char blankSymbol) => forwardTape.Add(blank = blankSymbol);

        public void Reset() {
            backwardTape.Clear();
            forwardTape.Clear();
            head = 0;
            forwardTape.Add(blank);
        }

        public void Input(string input) {
            Reset();
            forwardTape.Clear();
            forwardTape.AddRange(input);
        }

        public void Move(int direction) {
            head += direction;
            if (head >= 0 && forwardTape.Count <= head) forwardTape.Add(blank);
            if (head < 0 && backwardTape.Count <= ~head) backwardTape.Add(blank);
        }

        public char Current {
            get => head < 0 ? backwardTape[~head] : forwardTape[head];
            set {
                if (head < 0) backwardTape[~head] = value;
                else forwardTape[head] = value;
            }
        }

        public int Length => backwardTape.Count + forwardTape.Count;

        public override string ToString() {
            int h = (head < 0 ? ~head : backwardTape.Count + head) * 2 + 1;
            var builder = new StringBuilder(" ", Length * 2 + 1);
            if (backwardTape.Count > 0) {
                builder.Append(string.Join(" ", backwardTape)).Append(" ");
                if (head < 0) (builder[h + 1], builder[h - 1]) = ('(', ')');
                for (int l = 0, r = builder.Length - 1; l < r; l++, r--) (builder[l], builder[r]) = (builder[r], builder[l]);
            }
            builder.Append(string.Join(" ", forwardTape)).Append(" ");
            if (head >= 0) (builder[h - 1], builder[h + 1]) = ('(', ')');
            return builder.ToString();
        }

    }

}






VB: Option Base 1
Public Enum sett
    name_ = 1
    initState
    endState
    blank
    rules
End Enum
Public incrementer As Variant, threeStateBB As Variant, fiveStateBB As Variant

Private Sub init()
    incrementer = Array("Simple incrementer", _
        "q0", _
        "qf", _
        "B", _
         Array( _
         Array("q0", "1", "1", "right", "q0"), _
         Array("q0", "B", "1", "stay", "qf")))
    threeStateBB = Array("Three-state busy beaver", _
       "a", _
       "halt", _
       "0", _
        Array( _
        Array("a", "0", "1", "right", "b"), _
        Array("a", "1", "1", "left", "c"), _
        Array("b", "0", "1", "left", "a"), _
        Array("b", "1", "1", "right", "b"), _
        Array("c", "0", "1", "left", "b"), _
        Array("c", "1", "1", "stay", "halt")))
    fiveStateBB = Array("Five-state busy beaver", _
        "A", _
        "H", _
        "0", _
         Array( _
         Array("A", "0", "1", "right", "B"), _
         Array("A", "1", "1", "left", "C"), _
         Array("B", "0", "1", "right", "C"), _
         Array("B", "1", "1", "right", "B"), _
         Array("C", "0", "1", "right", "D"), _
         Array("C", "1", "0", "left", "E"), _
         Array("D", "0", "1", "left", "A"), _
         Array("D", "1", "1", "left", "D"), _
         Array("E", "0", "1", "stay", "H"), _
         Array("E", "1", "0", "left", "A")))
End Sub

Private Sub show(state As String, headpos As Long, tape As Collection)
    Debug.Print " "; state; String$(7 - Len(state), " "); "| ";
    For p = 1 To tape.Count
        Debug.Print IIf(p = headpos, "[" & tape(p) & "]", " " & tape(p) & " ");
    Next p
    Debug.Print
End Sub
 

Private Sub UTM(machine As Variant, tape As Collection, Optional countOnly As Long = 0)
    Dim state As String: state = machine(initState)
    Dim headpos As Long: headpos = 1
    Dim counter As Long, rule As Variant
    Debug.Print machine(name_); vbCrLf; String$(Len(machine(name_)), "=")
    If Not countOnly Then Debug.Print " State  | Tape [head]" & vbCrLf & "---------------------"
    Do While True
        If headpos > tape.Count Then
            tape.Add machine(blank)
        Else
            If headpos < 1 Then
                tape.Add machine(blank), Before:=1
                headpos = 1
            End If
        End If
        If Not countOnly Then show state, headpos, tape
        For i = LBound(machine(rules)) To UBound(machine(rules))
            rule = machine(rules)(i)
            If rule(1) = state And rule(2) = tape(headpos) Then
                tape.Remove headpos
                If headpos > tape.Count Then
                    tape.Add rule(3)
                Else
                    tape.Add rule(3), Before:=headpos
                End If
                If rule(4) = "left" Then headpos = headpos - 1
                If rule(4) = "right" Then headpos = headpos + 1
                state = rule(5)
                Exit For
            End If
        Next i
        counter = counter + 1
        If counter Mod 100000 = 0 Then
            Debug.Print counter
            DoEvents
            DoEvents
        End If
        If state = machine(endState) Then Exit Do
    Loop
    DoEvents
    If countOnly Then
        Debug.Print "Steps taken: ", counter
    Else
        show state, headpos, tape
        Debug.Print
    End If
End Sub
 
Public Sub main()
    init
    Dim tap As New Collection
    tap.Add "1": tap.Add "1": tap.Add "1"
    UTM incrementer, tap
    Set tap = New Collection
    UTM threeStateBB, tap
    Set tap = New Collection
    UTM fiveStateBB, tap, countOnly:=-1
End Sub