205 lines
5.9 KiB
Rust
205 lines
5.9 KiB
Rust
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_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<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);
|
|
}
|
|
} |