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

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);
}
}