Added Turing machine
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -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]
|
||||
58
src/main.rs
Normal file
58
src/main.rs
Normal file
@@ -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();
|
||||
}
|
||||
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