def __init__(self, automata, reverser_class): self.automata = automata self.reverser_class = reverser_class self.rows = self.automata.rows self.columns = self.automata.columns self.reverser = self.reverser_class(self.automata) self.status_line = '' self.cursor_row = 0 self.cursor_column = 0 self.show_guesses = False self.show_numbers = False self.show_50s = False self.guesses = Guesses()
class Interface(object): def __init__(self, automata, reverser_class): self.automata = automata self.reverser_class = reverser_class self.rows = self.automata.rows self.columns = self.automata.columns self.reverser = self.reverser_class(self.automata) self.status_line = '' self.cursor_row = 0 self.cursor_column = 0 self.show_guesses = False self.show_numbers = False self.show_50s = False self.guesses = Guesses() def guess(self): self.status_line = '\x1b[48;5;21mThinking...\x1b[0m' self._draw_status_line() if self.reverser.impossible: self.reverser.reset() self._draw_reverser() for (row, column), state in self.guesses.as_dict().items(): self.reverser.narrow(row, column, c=state) try: for ((r, c), chance, length) in self.reverser.corroborate(): self._draw_one_guess((r, c), chance, length) self.status_line = '\x1b[48;5;21mThinking...\x1b[0m' self._draw_status_line() except ZeroDivisionError: self.status_line = '\x1b[48;5;196mImpossible!\x1b[0m' self._draw_status_line() else: self.status_line = '' self._draw_status_line() def _eval_and_draw(self): try: for ((r, c), chance, length) in self.reverser.evaluate_guesses(self.guesses): self._draw_one_guess((r, c), chance, length) except ZeroDivisionError: return False return True def autoguess(self): self.status_line = '\x1b[48;5;21mAutoguessing...\x1b[0m' self._draw_status_line() last_failure = None while True: ok = self._eval_and_draw() if ok: # Find the next unguessed spot. last_failure = None rc = self.reverser.next_guessable() if rc is None: self.status_line = '' self._draw_status_line() return # Nothing more to guess. # Guess that the next spot in the list was DEAD. self.guesses.append(rc, 0) else: # Failure. Remove the last guess from the list. last_failure = self.guesses.pop() if last_failure is None: # Uh oh. self.status_line = '\x1b[48;5;196mImpossible!\x1b[0m' self._draw_status_line() return rc, failed_guess = last_failure if failed_guess == 0: # That spot wasn't DEAD. Try ALIVE. self.guesses.append(rc, 1) else: # It wasn't ALIVE either. Unwind. while failed_guess == 1: last_failure = self.guesses.pop() rc, failed_guess = last_failure self.guesses.append(rc, 1) self.status_line = '' self._draw_status_line() self._draw_reverser() def _draw_reverser(self): if self.reverser is None: return cloud = self.reverser.cloud NORMAL = '\x1b[0m' ro, co = 2, 2 if self.reverser is not None: for r, row in enumerate(cloud): R = [self._one_cell(ch, le) for (ch, le) in row] move_cursor(ro + r, co) emit(''.join(R) + NORMAL) move_cursor(self.automata.rows + 3, 2) def _one_cell(self, chance, length): if not length: return '\x1b[48;5;196m ' if chance == 1.0: return '\x1b[48;5;231m[]' if chance == 0.0: return '\x1b[48;5;16m ' if self.show_50s and chance == 0.5: return '\x1b[48;5;22m<>' ansi_grey = 232 + int(round(chance * 23.0)) face = ' ' if self.show_numbers and length < 100: face = '%02i' % length return '\x1b[48;5;%im%s' % (ansi_grey, face) def _draw_one_guess(self, (row, column), chance, length): NORMAL = '\x1b[0m' ro, co = 2, 2 move_cursor(ro + row, co + (column * 2)) emit(self._one_cell(chance, length) + NORMAL)