Added Turing machine
This commit is contained in:
200
src/turing.rs
Normal file
200
src/turing.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user