Added Turing machine

This commit is contained in:
2024-03-21 16:00:41 +01:00
commit 522f33b221
4 changed files with 268 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
/Cargo.lock

8
Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "turing_machine"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

58
src/main.rs Normal file
View File

@@ -0,0 +1,58 @@
use crate::turing::*;
mod turing;
// length of the turing machine belt
const LENGTH: usize = 64;
fn main() {
let mut machine = TuringMachine::new();
// config turing machine belt
machine.set_belt(1, Value::Hash);
machine.set_belt(2, Value::One);
machine.set_belt(3, Value::One);
machine.set_belt(4, Value::One);
machine.set_belt(5, Value::One);
machine.set_belt(6, Value::Hash);
machine.set_belt(7, Value::One);
machine.set_belt(8, Value::One);
machine.set_belt(9, Value::One);
machine.set_belt(10, Value::Hash);
// config state transitions
machine.set_transition(0, Value::Hash, 1);
machine.set_transition(1, Value::Hash, 2);
machine.set_transition(2, Value::Hash, 3);
machine.set_transition(3, Value::One, 4);
machine.set_transition(4, Value::Hash, 5);
machine.set_transition(5, Value::Hash, 6);
machine.set_transition(6, Value::One, 1);
machine.set_transition(7, Value::One, 1);
machine.set_transition(7, Value::Hash, 1);
machine.set_transition(3, Value::Hash, 8);
machine.set_transition(8, Value::Hash, 9);
// config state actions
machine.set_actions(0, Value::None, Action {direction: Direction::Right, value: Value::None});
machine.set_actions(0, Value::Hash, Action {direction: Direction::Right, value: Value::Hash});
machine.set_actions(1, Value::One, Action {direction: Direction::Right, value: Value::One});
machine.set_actions(1, Value::Hash, Action {direction: Direction::Right, value: Value::Hash});
machine.set_actions(2, Value::One, Action {direction: Direction::Right, value: Value::One});
machine.set_actions(2, Value::Hash, Action {direction: Direction::Left, value: Value::None});
machine.set_actions(3, Value::One, Action {direction: Direction::Left, value: Value::Hash});
machine.set_actions(3, Value::Hash, Action {direction: Direction::Left, value: Value::Hash});
machine.set_actions(4, Value::One, Action {direction: Direction::Left, value: Value::One});
machine.set_actions(4, Value::Hash, Action {direction: Direction::Left, value: Value::Hash});
machine.set_actions(5, Value::One, Action {direction: Direction::Left, value: Value::One});
machine.set_actions(5, Value::Hash, Action {direction: Direction::Right, value: Value::None});
machine.set_actions(6, Value::One, Action {direction: Direction::Right, value: Value::Hash});
machine.set_actions(8, Value::One, Action {direction: Direction::Left, value: Value::One});
machine.set_actions(8, Value::Hash, Action {direction: Direction::Quit, value: Value::Hash});
// start machine
machine.start();
}

200
src/turing.rs Normal file
View File

@@ -0,0 +1,200 @@
use std::collections::HashMap;
use std::hash::Hash;
use std::process::exit;
use std::time::Instant;
use crate::LENGTH;
// all values possible in a turing machine
#[derive(Copy, Clone, Eq, PartialOrd, PartialEq, Hash)]
pub enum Value {
// Zero,
One,
Hash,
None,
}
// all directions the pointer can go
#[derive(Copy, Clone, Eq, PartialOrd, PartialEq, Hash)]
pub enum Direction {
Left,
Right,
Quit,
}
// an action that can be made
#[derive(Copy, Clone, Eq, PartialOrd, PartialEq, Hash)]
pub struct Action {
pub direction: Direction,
pub value: Value,
}
// the turing machine
pub struct TuringMachine {
belt: [Value; LENGTH],
pointer: usize,
state: u64,
state_next: u64,
transitions: HashMap<u64, HashMap<Value, u64>>,
actions: HashMap<u64, HashMap<Value, Action>>,
}
impl TuringMachine {
// create a new turing machine
pub fn new() -> Self {
// return empty turing machine
return TuringMachine {
belt: [Value::None; LENGTH],
pointer: 0,
state: 0,
state_next: 0,
transitions: HashMap::new(),
actions: HashMap::new(),
};
}
pub fn set_belt(&mut self, index: usize, value: Value) -> () {
// set value on belt
self.belt[index] = value;
}
pub fn set_transition(&mut self, state: u64, value: Value, next_state: u64) -> () {
// If the State is not in the HashMap, add it
if self.transitions.get(&state).is_none() {
self.transitions.insert(state, HashMap::new());
}
// get the inner HashMap with the next state
let mut state_transition: HashMap<Value, u64> = self.transitions.get(&state).unwrap().to_owned();
// update inner HashMap
state_transition.insert(value, next_state);
// update outer HashMap
self.transitions.insert(state, state_transition);
}
pub fn set_actions(&mut self, state: u64, value: Value, output: Action) -> () {
// If the State is not in the HashMap, add it
if self.actions.get(&state).is_none() {
self.actions.insert(state, HashMap::new());
}
// get the inner HashMap with the action
let mut state_action: HashMap<Value, Action> = self.actions.get(&state).unwrap().to_owned();
// update inner HashMap
state_action.insert(value, output);
// update outer HashMap
self.actions.insert(state, state_action);
}
fn print(&self) -> () {
// clear console
print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
// create empty string for line
let mut line = String::new();
// iterate trough belt and add the values to the string
for value in self.belt {
line += match value {
// Value::Zero => {" 0"},
Value::One => {" 1"},
Value::Hash => {" #"},
Value::None => {" u"},
}
}
// print the belt
println!("{}", line);
// reset the line
line = String::new();
// add two space for every state, except for one
for _ in 0..2*self.belt.len()-1 {
line += " ";
}
// insert the pointer to the current location in belt
line.insert(2*self.pointer + 1, '^');
// print pointer
println!("{}", line);
}
fn get(&self) -> Value {
// get the current value from the belt
return self.belt[self.pointer];
}
fn target_next_transition(&mut self) -> () {
// verify there is the state
if self.transitions.get(&self.state).is_none() {
// the state won't switch
self.state_next = self.state;
return;
}
// verify there is a transition for the current symbol
if self.transitions.get(&self.state).unwrap().get(&self.get()).is_some() {
// set next state based on config
self.state_next = self.transitions.get(&self.state).unwrap().get(&self.get()).unwrap().to_owned();
}
}
fn make_action(&mut self) -> Result<(), ()> {
// verify there is the state
if self.actions.get(&self.state).unwrap().get(&self.get()).is_some() {
// make action
return self.execute(self.actions.get(&self.state).unwrap().get(&self.get()).unwrap().to_owned());
}
// action successful
return Ok(());
}
fn execute(&mut self, action: Action) -> Result<(), ()> {
// update belt value at pointer
self.belt[self.pointer] = action.value;
// move pointer or exit
match action.direction {
Direction::Left => {if self.pointer > 0 {self.pointer -= 1} else {panic!("Index out of bounds")}}
Direction::Right => {if self.pointer < LENGTH {self.pointer += 1} else {panic!("Index out of bounds")}}
Direction::Quit => {return Err(())}
}
// pointer moved successfully
return Ok(());
}
fn transition(&mut self) -> () {
// switch to the next state
self.state = self.state_next;
}
pub fn start(&mut self) -> ! {
// Allocate Space for Instant
let mut start: Instant;
// loop until program finishes
'operation: loop {
// track loop start time
start = Instant::now();
// choose next transition
self.target_next_transition();
// make next action. An Error is an alias for quit
if self.make_action().is_err() {
break 'operation;
}
// make transition
self.transition();
// print current state
self.print();
// wait for readability
while start.elapsed().as_millis() < 100 {};
}
// quit program
exit(0);
}
}