using System; namespace TuringMachine.Core { public class Machine { public Tape Tape { get; } public TransitionTable Transitions { get; } public int HeadPosition { get; private set; } public string CurrentState { get; private set; } public bool IsHalted { get; private set; } public string InitialState { get; set; } = "q0"; public event Action? OnStep; public event Action? OnHalt; public Machine() { Tape = new Tape(); Transitions = new TransitionTable(); CurrentState = InitialState; } public void ForceHeadPosition(int position) { HeadPosition = position; } public void Reset() { Tape.Clear(); HeadPosition = 0; CurrentState = InitialState; IsHalted = false; OnStep?.Invoke(); } public void LoadProgram(string initialState, IEnumerable<(string state, char read, string newState, char write, MoveDirection move, string comment)> transitions) { InitialState = initialState; Transitions.Clear(); foreach (var t in transitions) { Transitions.Add(t.state, t.read, t.newState, t.write, t.move, t.comment); } Reset(); } public bool Step() { if (IsHalted) return false; char readSymbol = Tape[HeadPosition]; if (Transitions.TryGetTransition(CurrentState, readSymbol, out var result)) { if (result == null) { // Should not simplify happen due to TryGetTransition semantics, but for safety IsHalted = true; OnHalt?.Invoke(); return false; } Tape[HeadPosition] = result.WriteSymbol; CurrentState = result.NewState; switch (result.MoveDirection) { case MoveDirection.Left: HeadPosition--; break; case MoveDirection.Right: HeadPosition++; break; } OnStep?.Invoke(); return true; } else { // No transition defined = Halt IsHalted = true; OnHalt?.Invoke(); return false; } } } }