commit 522f33b221b7ad0d14e2bde9e4fe04ca0137bced Author: Timo Schneider Date: Thu Mar 21 16:00:41 2024 +0100 Added Turing machine diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6ae5a6c --- /dev/null +++ b/Cargo.toml @@ -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] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..263a495 --- /dev/null +++ b/src/main.rs @@ -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(); +} diff --git a/src/turing.rs b/src/turing.rs new file mode 100644 index 0000000..80e25d5 --- /dev/null +++ b/src/turing.rs @@ -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>, + actions: HashMap>, +} + +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 = 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 = 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); + } +} \ No newline at end of file