turingmachine-rs 0.2.0

A Turing Machine Simulation Library written in Rust
Documentation
//! In this example for the turingmachine-rs crate a turing machine is created which, when
//! supplied with two numbers `n` and `k` will determine whether `n` is divisable by `k`.
//!
//! Its usage is in the CLI by adding 2 args with numbers:
//! `cargo run --example divisibility -- 9 6`
//!
//! The turing machine starts with a tape in the shape:
//! ` _ 1^n _ 1^k _ ` and will output:
//!     - ` _ 1^n _ 1^k _ h _ 1 ` if k is a divisor of n
//!     - ` _ 1^n _ 1^k _ h _ 0 ` if k is __NOT__ a divisor of n
//!
//! here ` _ ` is a empty cell and ` 1^n ` is ` 1 ` repeated n times, and ` h ` is the halt symbol.

use std::{fmt, iter::Cycle};
use turingmachine_rs::*;

#[derive(Clone, PartialEq)]
enum Alphabet {
    StartToken,
    Delta,
    One,
    MarkedOne,
    Halt,
}

impl fmt::Display for Alphabet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Alphabet::*;

        match self {
            StartToken => write!(f, "S"),
            Delta => write!(f, "_"),
            One => write!(f, "1"),
            MarkedOne => write!(f, "!"),
            Halt => write!(f, "h"),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
enum States {
    Start,
    Started,
    CycleStart,
    Found1InDenominator,
    Found1InNuminator,

    LeftOver,
    DivByNull,
    InvalidSyntax,
}

impl TuringStates<Alphabet> for States {
    fn step(&self, t: Alphabet) -> (Self, Alphabet, Move) {
        use Alphabet::*;
        use States::*;

        match self {
            Start => match t {
                Delta => (Started, t, Move::Right),
                _ => (Start, t, Move::Right),
            },
            Started => match t {
                One => (Started, t, Move::Right),
                Delta => (CycleStart, t, Move::Stay),
                _ => (InvalidSyntax, t, Move::Stay),
            },
            _ => (InvalidSyntax, t, Move::Stay),
        }
    }
}

fn main() {
    let n = std::env::args()
        .nth(1)
        .expect("No first argument given. Usage: cargo run --example divisibility -- <int> <int>");
    let k = std::env::args()
        .nth(2)
        .expect("No second argument given. Usage: cargo run --example divisibility -- <int> <int>");

    let n = n
        .parse::<usize>()
        .expect("First argument is not a positive integer");
    let k = k
        .parse::<usize>()
        .expect("Second argument is not a positive integer");

    println!("n: {}, k: {}", n, k);

    let mut ns = vec![Alphabet::One; n];
    let mut ks = vec![Alphabet::One; k];

    let mut delta = vec![Alphabet::Delta];

    let mut initial = Vec::new();

    initial.append(&mut delta.clone());
    initial.append(&mut ns);
    initial.append(&mut delta.clone());
    initial.append(&mut ks);
    initial.append(&mut delta);

    let tape = TuringTape::new(Alphabet::Delta, Alphabet::StartToken, initial);
    println!("Tape: {}", tape);

    println!("\n\nRunning...\n\n");

    use States::*;
    let end_state = tape.run_states(Start, vec![CycleStart, InvalidSyntax, DivByNull, LeftOver]);

    println!("Tape: {}", tape);
    println!("Endstate: {:?}", end_state);
}