use std::fmt::{Display, Error, Formatter};
use crate::instruction::{Move, State};
use crate::state::Tape;
use crate::Symbol;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Configuration<S: Symbol> {
tape: Tape<S>,
index: usize,
pub state: State,
}
impl<S: Symbol> Configuration<S> {
pub fn new(tape: Tape<S>, index: usize, state: State) -> Result<Self, String> {
match tape.len() > index {
true => Ok(Configuration { tape, index, state }),
false => Err(format!(
"index out of bounds: the len is {} but the index is {}",
tape.len(),
index
)),
}
}
pub fn new_nrm(tape: Tape<S>) -> Result<Self, String> {
Configuration::new(tape, 0, State(1))
}
pub fn new_std(tape: Tape<S>) -> Result<Self, String> {
let last = tape.len() - 1;
Configuration::new(tape, last, State(1))
}
pub fn destruct(self) -> (Tape<S>, usize, State) {
(self.tape, self.index, self.state)
}
pub fn tape(&self) -> &Tape<S> {
&self.tape
}
pub fn into_tape(self) -> Tape<S> {
self.tape
}
pub fn get_symbol(&self) -> &S {
self.tape
.get(self.index)
.expect("get_symbol error: returned value must be Some because of bound checking")
}
pub fn index(&self) -> usize {
self.index
}
pub fn is_empty(&self) -> bool {
self.tape.is_empty()
}
pub fn len(&self) -> usize {
self.tape.len()
}
pub fn set_symbol(&mut self, symbol: S) {
self.tape.set(self.index, symbol);
}
pub fn shift(&mut self, movement: Move, default: S) {
match movement {
Move::Left if self.index == 0 => self.tape.insert(0, default),
Move::Left => self.index -= 1,
Move::None => {}
Move::Right => {
self.index += 1;
if self.index == self.tape.len() {
self.tape.insert(self.index, default);
}
}
};
}
}
impl<S: Symbol> Display for Configuration<S> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(
f,
"Configuration {{ Tape: \"{}\", Index: {}, State: {} }}",
self.tape, self.index, self.state
)
}
}