class TripleDoohickey(object):
    def __init__(self):
        self.first = Doohickey()
        self.second = Doohickey()
        self.third = Doohickey()
        self.a()
    def a(self):
        """Returns 'aba' and sets the Doohickies to a, b, and a.
        
        >>> doo = TripleDoohickey()
        >>> doo.a()
        'aba'
        """
        result = ''
        result += self.first.a()
        result += self.second.b()
        result += self.third.a()
        return result
    def b(self):
        """Returns 'bab' and sets the Doohickies to b, a and b.

        >>> doo = TripleDoohickey()
        >>> doo.b()
        'bab'
        """
        result = ''
        result += self.first.b()
        result += self.second.a()
        result += self.third.b()
        return result
    def other(self):
        """Returns the opposite of the last time, or 'bab' at first.

        >>> doo = TripleDoohickey()
        >>> doo.other()
        'bab'
        >>> doo.other()
        'aba'
        >>> doo.a()
        'aba'
        >>> doo.other()
        'bab'
        >>> doo.b()
        'bab'
        >>> doo.other()
        'aba'
        >>> doo.other()
        'bab'
        >>> doo.other()
        'aba'
        """
        result = ''
        result += self.first.other()
        result += self.second.other()
        result += self.third.other()
        return result
 def reset_everything(self):
     empty_row = collections.deque()
     empty_row.append('*')
     self.display = collections.deque()
     self.display.append(empty_row)
     self.buttons_pressed = collections.deque()
     self.cursor_stack = collections.deque()
     self.background_instructions = collections.deque()
     self.background_current_instruction = -1 # So it starts at zero. 
     self.background_processing_on = False
     self.alternator = True
     self.cursor_row = 0
     self.cursor_column = 0
     self.rotation_direction = 1
     self.doohickey = Doohickey()
     self.remembered_character = ' '
class Fnooblatz1000(object):
    def __init__(self):
        self.reset_everything()
    def printable_display(self):
        printable = '\n'
        for row in self.display:
            for column in row:
                printable += column
            printable += '\n'
        return printable
    def print_curses(self,stdscr):
        for y in range(len(self.display)):
            for x in range(len(self.display[y])):
                stdscr.addch(y,x,ord(self.display[y][x]))
        stdscr.refresh()
    def set_width(self,width):
        if width < 1:
            return False
        while len(self.display[0]) > width:
            self.press_button(3)
        while len(self.display[0]) < width:
            self.press_button(1)
        assert(len(self.display[0]) == width)
        return True
    def set_height(self,height):
        if height < 1:
            return False
        while len(self.display) > height:
            self.press_button(4)
        while len(self.display) < height:
            self.press_button(2)
        assert(len(self.display) == height)
        return True
    def reset_everything(self):
        empty_row = collections.deque()
        empty_row.append('*')
        self.display = collections.deque()
        self.display.append(empty_row)
        self.buttons_pressed = collections.deque()
        self.cursor_stack = collections.deque()
        self.background_instructions = collections.deque()
        self.background_current_instruction = -1 # So it starts at zero. 
        self.background_processing_on = False
        self.alternator = True
        self.cursor_row = 0
        self.cursor_column = 0
        self.rotation_direction = 1
        self.doohickey = Doohickey()
        self.remembered_character = ' '
    def check_cursor_bounds(self):
        if self.cursor_row < 0:
            self.cursor_row = 0
        if self.cursor_column < 0:
            self.cursor_column = 0
        while self.cursor_row >= len(self.display):
            self.cursor_row -= 1
        while self.cursor_column >= len(self.display[0]):
            self.cursor_column -= 1
    def execute_sequence(self,sequence):
        for instruction in sequence:
            self.press_button(instruction)
    def execute_background_instruction(self):
        if len(self.background_instructions) < 1:
            return # If there are no instructions, there's nothing to do. 
        self.background_current_instruction += 1
        if self.background_current_instruction >= len(self.background_instructions):
            self.background_current_instruction = 0
        instruction = \
            self.background_instructions[self.background_current_instruction]
        self.execute_single_instruction(instruction)
    def press_button(self,button_number):
        self.buttons_pressed.append(button_number)
        if len(self.buttons_pressed) > 1024:
            self.buttons_pressed.popleft()
        if self.alternator:
            self.alternator = False
        else:
            self.alternator = True
        # The alternator, as you can see, alternates 
        # BEFORE each instruction is executed.  Confusing
        # but true! 
        self.execute_single_instruction(button_number)
        if self.background_processing_on:
            self.execute_background_instruction()
    def execute_single_instruction(self,button_number):
        if button_number == 0:
            self.reset_everything()
            return
        # Resets everything.
        #
        # This functionality was desperately necessary 
        # of course on actual Fnooblatz 1000s, which if 
        # given difficult computations would overheat and 
        # smoke furiously.  I don't think there's an FB1000 
        # would have made it through the first night without 
        # this button.  Hopefully on this simulator it 
        # should be necessary slightly less desperately, 
        # but it's still useful for getting out of any of 
        # the confusing internal states a Fnooblatz is 
        # prone to! 
        if button_number == 1:
            for row in self.display:
                row.append('*')
            return
        if button_number == 2:
            new_row = collections.deque()
            for column in self.display[0]:
                new_row.append('*')
            self.display.append(new_row)
            return
        # The above commands to expand the Fnooblatz screen 
        # are necessary because the display starts 1 pixel by 
        # 1 pixel.  But why does it?  Well, besides the fact 
        # that in the old days people would run their Fnooblatz 
        # at as small a resolution as they actually needed, to 
        # conserve energy, or that a cheap one-pixel display 
        # would often be used to diagnose what's wrong with a 
        # sick Fnooblatz (so it couldn't burn out a whole 
        # expensive display), there's also the case of those 
        # folks who would insist that they just didn't need 
        # more than a one-pixel display to get by.  And it's 
        # true, you can read the news quite adequately one 
        # character at a time, if you're patient. 
        if button_number == 3:
            if len(self.display[0]) > 1:
                for row in self.display:
                    row.pop()
            self.check_cursor_bounds()
            return
        if button_number == 4:
            if len(self.display) > 1:
                self.display.pop()
            self.check_cursor_bounds()
            return
        # If you can make the display bigger, it's convenient 
        # to be able to make it smaller too, instead of just 
        # having to start all over! 
        if button_number == 5:
            for row in self.display:
                row.rotate(self.rotation_direction)
            return
        if button_number == 6:
            self.display.rotate(self.rotation_direction)
            return
        # Rotating the display, which gives us just barely
        # enough instructions to paint pictures! :D 
        if button_number == 7:
            return
        # Button seven doesn't do anything, 'anything' that is
        # except for all the stuff the Fnooblatz does every
        # instruction (alternate the alternator, etc.)-- but,
        # like, nothing EXTRA. 
        if button_number == 8:
            self.check_cursor_bounds()
            if self.alternator:
                self.display[self.cursor_row][self.cursor_column] = '|'
            else:
                self.display[self.cursor_row][self.cursor_column] = '-'
            return
        # This allows you to see the behavior of the alternator, 
        # and combined with the following instructions to move the
        # cursor can be useful for drawing. 
        if button_number == 9:
            if self.alternator:
                self.cursor_row += 1
            else:
                self.cursor_row -= 1
            self.check_cursor_bounds()
            return
        # The previous instruction allows you to go either up OR down!
        if button_number == 10:
            if self.alternator:
                self.cursor_column += 1
            else:
                self.cursor_column -= 1
            self.check_cursor_bounds()
            return
        # The previous instruction allows you to go either left OR right!
        if button_number == 11:
            self.check_cursor_bounds()
            self.display[self.cursor_row][self.cursor_column] = ' '
            return
        # Spaces.      Ah.          Relaxing. 
        if button_number == 12:
            self.display[self.cursor_row][self.cursor_column] = self.doohickey.other()
            return
        # The Fnooblatz1000 contains a simple interface 
        # to access its contained Doohickey!  This presses 
        # the 'other' button on the Doohickey and prints 
        # the result. 
        if button_number == 13:
            self.display[self.cursor_row][self.cursor_column] = self.doohickey.a()
            return
        if button_number == 14:
            self.display[self.cursor_row][self.cursor_column] = self.doohickey.b()
            return
        # With these you can use the Doohickey to write 'a' and 
        # 'b', which is useful for talking about ABBA! 
        if button_number == 15:
            self.buttons_pressed.pop() # Otherwise it gets weird.
            self.background_instructions = self.buttons_pressed
            self.background_current_instruction = -1 # So we start at zero.
            self.buttons_pressed = collections.deque()
            return
        # Moves what you've done recently to the background, 
        # where it will continue to happen as you go on doing 
        # other things.  Fun! 
        if button_number == 16:
            self.buttons_pressed.pop() # Otherwise it gets weird.
            if self.background_processing_on:
                self.background_processing_on = False
            else:
                self.background_processing_on = True
            return
        # Toggles background processing.  If it's turned 
        # on it will start quite immediately, before the 
        # next instruction. 
        if button_number == 17:
            self.cursor_row = 0
            self.cursor_column = 0
            return
        # An orderly instruction for finding one's place.
        if button_number == 18:
            self.check_cursor_bounds()
            if self.display[self.cursor_row][self.cursor_column] != '|':
                self.cursor_column -= 1
                self.check_cursor_bounds()
            return
        if button_number == 19:
            self.check_cursor_bounds()
            if self.display[self.cursor_row][self.cursor_column] != '|':
                self.cursor_column += 1
                self.check_cursor_bounds()
            return
        if button_number == 20:
            self.check_cursor_bounds()
            if self.display[self.cursor_row][self.cursor_column] != '-':
                self.cursor_row -= 1
                self.check_cursor_bounds()
            return
        if button_number == 21:
            self.check_cursor_bounds()
            if self.display[self.cursor_row][self.cursor_column] != '-':
                self.cursor_row += 1
                self.check_cursor_bounds()
            return
        # The above instructions allow you to travel easily in 
        # all four directions, while also allowing you to safely 
        # contain yourself in a box-- or a maze perhaps!
        if button_number == 22:
            if self.rotation_direction == 1:
                self.rotation_direction = -1
            else:
                self.rotation_direction = 1
            return
        # Allows you to switch to rotating the display in the 
        # opposite direction.  This might make you less dizzy.
        if button_number == 23:
            self.check_cursor_bounds()
            self.remembered_character = self.display[self.cursor_row][self.cursor_column]
            return
        if button_number == 24:
            self.check_cursor_bounds()
            self.display[self.cursor_row][self.cursor_column] = self.remembered_character
            return
        # Allows you to remember a character for a little 
        # while.  Useful for smearing things around! 
        if button_number == 25:
            self.check_cursor_bounds()
            self.display[self.cursor_row][self.cursor_column] = \
                alphabetrotator.rotate(self.display[self.cursor_row][self.cursor_column])
            return
        # Combined with the Doohickey, which prints out 
        # 'a's and 'b's, this allows you to write any 
        # letter of the alphabet! 
        if button_number == 26:
            self.check_cursor_bounds()
            if self.display[self.cursor_row][self.cursor_column] == ' ':
                return # Do nothing to blank spaces. 
            self.display[self.cursor_row][self.cursor_column] = 'g'
            return
        # This is useful for GIG.
        if button_number == 27:
            self.cursor_stack.append((self.cursor_row, self.cursor_column))
            if len(self.cursor_stack) > 1024:
                self.cursor_stack.popleft()
            return
        if button_number == 28:
            if len(self.cursor_stack) > 0:
                (self.cursor_row, self.cursor_column) = self.cursor_stack.pop()
            return
        # Whereever you go, there you are, but it's also nice 
        # to remember where else you've been recently. 
        self.display[0][0] = '@' 
 def __init__(self):
     self.first = Doohickey()
     self.second = Doohickey()
     self.third = Doohickey()
     self.a()