turing_machine_rs/turing.rs
1use crate::instruction::State;
2use crate::state::{Configuration, Tape};
3use crate::Symbol;
4
5/// Provides ability to execute [`crate::state::Configuration`]s and translate
6/// [`crate::state::Tape`]s.
7///
8/// Most of the methods can be implement through the [`TuringMachine::execute_once`]
9/// and [`TuringMachine::execute_until`] methods.
10///
11/// Most important trait.
12///
13/// # Examples
14/// ```rust
15/// extern crate turing_machine_rs;
16///
17/// use turing_machine_rs::instruction::{Move, State};
18/// use turing_machine_rs::machines::Classic;
19/// use turing_machine_rs::program::{Extend, Program};
20/// use turing_machine_rs::state::Tape;
21/// use turing_machine_rs::TuringMachine;
22///
23/// fn main() -> Result<(), String> {
24/// let alphabet = vec!['t', 'e', 's', 'n', 'i', 'c', 'e', '_'];
25/// let mut program = Program::new(alphabet, State(4));
26/// // Trait for more comfortable coding
27/// program.extend([
28/// // Instruction consists of Head and Tail parts
29/// // Head state, Head symbol, Tail state, Tail symbol, Tail Move
30/// (1, 't', 2, 'n', Move::Right),
31/// (2, 'e', 3, 'i', Move::Right),
32/// (3, 's', 4, 'c', Move::Right),
33/// (4, 't', 0, 'e', Move::None),
34/// // Revers
35/// (1, 'n', 2, 't', Move::Right),
36/// (2, 'i', 3, 'e', Move::Right),
37/// (3, 'c', 4, 's', Move::Right),
38/// (4, 'e', 0, 't', Move::None),
39/// ])?;
40/// let machine = Classic::new(program, '_')?;
41///
42/// let test = Tape::from("test");
43/// let nice = machine.translate_nrm(test.clone())?;
44/// println!(
45/// "{} {}!",
46/// String::from_iter(nice.as_vec()),
47/// String::from_iter(test.as_vec())
48/// );
49/// Ok(())
50/// }
51/// ```
52pub trait TuringMachine<S: Symbol> {
53 /// Executes the [`crate::program::Program`] and returns a mutated [`Configuration`]
54 /// using the [`TuringMachine::execute_until`] method with the `conf.state == 0`
55 /// predicate. This is the most commonly used method for [`crate::program::Program`] execution.
56 fn execute(&self, conf: Configuration<S>) -> Result<Configuration<S>, String> {
57 self.execute_until(conf, |conf| conf.state == State(0))
58 }
59
60 /// A Turing machine must have the ability to execute [`crate::program::Program`]
61 /// and change the [`Configuration`] once. This is important for machines,
62 /// and its realization can vary depending on machine type.
63 fn execute_once(&self, conf: Configuration<S>) -> Result<Configuration<S>, String>;
64
65 /// Executes program untill stop predicate equals to `false` and returns
66 /// a mutated [`Configuration`].
67 ///
68 /// # Examples
69 /// ```rust
70 /// use turing_machine_rs::instruction::{Move, State};
71 /// use turing_machine_rs::machines::Classic;
72 /// use turing_machine_rs::program::{Extend, Program};
73 /// use turing_machine_rs::state::{Configuration, Tape};
74 /// use turing_machine_rs::TuringMachine;
75 ///
76 /// fn main() -> Result<(), String> {
77 /// let mut program = Program::new(vec!['0', '1'], State(3));
78 /// program.extend([
79 /// (1, '0', 2, '0', Move::Right),
80 /// (1, '1', 1, '1', Move::Left),
81 /// (2, '0', 3, '1', Move::Left),
82 /// (2, '1', 2, '1', Move::Right),
83 /// (3, '0', 0, '0', Move::None),
84 /// (3, '1', 3, '0', Move::Left),
85 /// ])?;
86 /// let machine = Classic::new(program, '0')?;
87 ///
88 /// let conf = Configuration::new_std(Tape::from("010"))?;
89 /// let result = machine.execute_until(conf, |conf| conf.state == State(3))?;
90 ///
91 /// let expected = Configuration::new(Tape::from("0101"), 2, State(3))?;
92 /// assert_eq!(expected, result);
93 ///
94 /// Ok(())
95 /// }
96 /// ```
97 fn execute_until(
98 &self,
99 conf: Configuration<S>,
100 until: impl Fn(&Configuration<S>) -> bool,
101 ) -> Result<Configuration<S>, String>;
102
103 /// Translates and returns a mutated [`Tape`] using the [`TuringMachine::execute`]
104 /// method as the [`Configuration::new_std`].
105 fn translate_std(&self, tape: Tape<S>) -> Result<Tape<S>, String> {
106 let conf = Configuration::new_std(tape)?;
107 let exec = self.execute(conf)?;
108 Ok(exec.into_tape())
109 }
110
111 /// Translates and returns a mutated [`Tape`] using the [`TuringMachine::execute`]
112 /// method as the [`Configuration::new_nrm`].
113 fn translate_nrm(&self, tape: Tape<S>) -> Result<Tape<S>, String> {
114 let conf = Configuration::new_nrm(tape)?;
115 let exec = self.execute(conf)?;
116 Ok(exec.into_tape())
117 }
118}