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_pointer(&mut self, index: usize) -> () { // set pointer start position self.pointer = index; } 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); } }