class TuringMachine(): def __init__(self, turing_machine_def: str) -> None: # if a placeholder is needed, create it with empty string if not turing_machine_def: return # STATE VARIABLES self.state_start: str = '' self.state_accept: str = '' self.state_reject: str = '' self.state_current: str = '' # BAND VARIABLES self.band: list = [] self.band_num: int = 0 self.band_current: int = 0 # RULE VARIABLES self.rules: list = [] self.rule_used: str = '' # ERR Variables self.errored: bool = False # PARSE BANDS def_split = turing_machine_def.replace(' ', '').replace('\n', '').lower().split(';') self.band_num = int(def_split[0]) # PARSE STATES self.state_start = def_split[1] self.state_current = def_split[1] self.state_accept = def_split[2] self.state_reject = def_split[3] def_split_truncated = def_split[4:] # PARSE RULES for x in def_split_truncated: if not x: continue rule_current = x.split(',') tmp = rule_current[1].split('->') rule_current[1] = tmp[0] rule_current.insert(2, tmp[1]) self.rules.append(rule_current) def turing_run(self) -> None: '''Runs the TM without giving the option to step through manually.''' while not self.turing_finished(): self.turing_step() if self.errored: return def turing_step(self) -> bool: '''Steps through the TM one rule at a time. A step is changing the value of the current element and moving the band by one. Returns whether the TM has finished running or has an empty band.''' if len(self.band) == 0: return True # Add blank if current location is out of bounds and adjust location if self.band_current < 0: self.band.insert(0, '_') self.band_current = 0 if self.band_current == len(self.band): self.band.append('_') for rule in self.rules: # Skip if rule does not apply to current state if not rule[0] == self.state_current: continue # Skip if rule does not apply to current band element if not rule[1] == self.band[self.band_current]: continue # Set band element according to rule self.band[self.band_current] = rule[3] # Set current state according to rule self.state_current = rule[2] # Move band according to rule if rule[4] == '<': self.band_current -= 1; if rule[4] == '>': self.band_current += 1; self.rule_used = ( rule[0] + ', ' + rule[1] + ' -> ' + rule[2] + ', ' + rule[3] + ', ' + rule[4]) break return self.turing_finished() def turing_finished(self) -> bool: '''Returns whether the TM is in accepting state, rejecting state or has halted because no applicable rules are left.''' return ( self.state_current == self.state_accept or self.state_current == self.state_reject or self.errored ) def turing_accepted(self) -> bool: '''Returns whether the TM, with the given input, has reached accepted state.''' return self.state_current == self.state_accept def turing_reset(self) -> None: '''Resets current state to start state and band location to zero.''' self.state_current = self.state_start self.band_current = 0 def get_rules(self) -> list: return self.rules def get_rule_used(self) -> str: return self.rule_used def get_band(self) -> str: return (''.join(self.band)).replace('_', '') def get_band_context(self, context: int) -> str: '''Returns context chars to the left and right of the current element as well as the element.''' ret = "" for i in range(self.band_current - context, self.band_current + context + 1): if i < 0: ret += "_ " elif i+1 > len(self.band): ret += "_ " else: ret += f"{self.band[i]} " return ret.rstrip() def get_band_current_element(self) -> str: if self.band_current < 0 or self.band_current == len(self.band): return '_' return self.band[self.band_current] def get_state_start(self) -> str: return self.state_start def get_state_current(self) -> str: return self.state_current def get_state_accept(self) -> str: return self.state_accept def get_state_reject(self) -> str: return self.state_reject def get_has_errored(self) -> bool: return self.errored def set_band(self, input: str): self.band = list(input) def redefine(self, turing_machine_def: str): self.__init__(turing_machine_def) def test(): tm = TuringMachine(''' 1; q0; q3; q4; q0, 0 -> q0, 0, > ; q0, 1 -> q0, 1, > ; q0, _ -> q1, _, < ; q1, 0 -> q2, 1, < ; q1, 1 -> q1, 0, < ; q1, _ -> q3, 1, - ; q2, 1 -> q2, 1, < ; q2, 0 -> q2, 0, < ; q2, _ -> q3, _, > ''') tm.set_band("1011") tm.turing_run() if tm.get_band() == "1100": print("Successfull") else: print("Failed")