Exemple #1
0
class Selector:
    """
    App selector to show previews and run apps
    """
    def __init__(self):
        self.cube = Cube()
        self.button_events = ButtonEvents()
        self.apps = [Rainbow(), Random(), Connect4Demo(), Connect4Human(), SnakeGame()]
        self.selected = 0
        self.show_preview()

    def run(self):
        event = self.button_events.get_event()
        if event == EventEnum.UP_PRESSED or event == EventEnum.LEFT_PRESSED:
            self.selected = (self.selected - 1) % len(self.apps)
            self.show_preview()
        elif event == EventEnum.DOWN_PRESSED or event == EventEnum.RIGHT_PRESSED:
            self.selected = (self.selected + 1) % len(self.apps)
            self.show_preview()
        elif event == EventEnum.A_PRESSED:
            # create new instance
            self.apps[self.selected] = type(self.apps[self.selected])()
            self.apps[self.selected].run()
            self.show_preview()

    def show_preview(self):
        preview = self.apps[self.selected].get_preview()
        self.cube.draw(preview)
        self.cube.show()
Exemple #2
0
 def __init__(self, mode=CYCLE):
     super().__init__()
     self.cube = Cube()
     self.queue = Queue()
     self.mode = mode
     self.animation_thread = StoppableThread(target=self.animation)
     self.animation_thread.setDaemon(True)
     self.animation_thread.start()
Exemple #3
0
 def __init__(self):
     self.button_events = ButtonEvents()
     self.cube = Cube()
     self.cube_buffer = get_empty_cube_buffer()
     self.theta = 0.0
     self.phi = 0.0
     self.wheel_offset = 0.0
     self.theta_d = 0.0
     self.phi_d = 0.0
     self.wheel_offset_d = 0.0
Exemple #4
0
class Random(App):
    """
    fill the cube with random stuff and change it slowly
    """
    def __init__(self):
        self.button_events = ButtonEvents()
        self.cube = Cube()
        self.cube_buffer = get_empty_cube_buffer()
        self.wheel_start = self.get_random_wheel()
        self.wheel_stop = self.get_random_wheel()

    def run(self):
        steps = 100
        try:
            while True:
                self.wheel_stop = self.get_random_wheel()
                for i in range(steps):
                    if self.button_events.get_event(block=False):
                        LOG.debug("button pressed, interrupting rainbow")
                        raise RandomInterrupted()
                    self.step(self.wheel_start, self.wheel_stop, float(i) / steps)
                    self.cube.draw(self.cube_buffer)
                    self.cube.show()
                    if not is_a_raspberry():
                        sleep(0.02)
                self.wheel_start = copy.deepcopy(self.wheel_stop)
        except RandomInterrupted:
            return

    def step(self, start, stop, step):
        for x in range(5):
            for y in range(5):
                for z in range(5):
                    color = wheel(int(start[x][y][z] + (stop[x][y][z] - start[x][y][z]) * step) % 256)
                    self.cube_buffer[x][y][z] = color

    def get_random_wheel(self):
        random_wheel = [[[randint(0, 255) for _ in range(5)] for _ in range(5)] for _ in range(5)]
        return random_wheel

    def get_random_cube(self, cube_buffer):
        random_wheel = self.get_random_wheel()
        for x in range(5):
            for y in range(5):
                for z in range(5):
                    cube_buffer[x][y][z] = wheel(random_wheel[x][y][z])

    def get_preview(self):
        preview = get_empty_cube_buffer()
        self.get_random_cube(preview)
        return preview

    def get_description(self) -> str:
        return "random"
Exemple #5
0
class TextWriter:
    def __init__(self):
        self.cube = Cube()

    def draw_character(self, char, pos, color):
        bitmap = CHARS.get(char.lower(), None)
        if bitmap:
            for y in range(len(bitmap[0])):
                for z in range(len(bitmap) - 1, -1, -1):
                    if bitmap[4 - z][y] == 0:
                        continue
                    if y + pos < 0 or y + pos >= 5:
                        continue
                    self.cube.set_color(4, y + pos, z, *color)

    def clear(self):
        for y in range(5):
            for z in range(5):
                self.cube.set_color(4, y, z, 0, 0, 0)

    def draw_string(self, string, delay):
        for pos in range(-1, len(string)):
            for i in range(4):
                self.clear()
                if pos >= 0:
                    self.draw_character(string[pos], -i, (255, 255, 255))
                if pos + 1 < len(string):
                    self.draw_character(string[pos + 1], 4 - i,
                                        (255, 255, 255))
                self.cube.show()
                sleep(delay)
Exemple #6
0
 def __init__(self):
     self.cube = Cube()
     self.button_events = ButtonEvents()
     self.apps = [Rainbow(), Random(), Connect4Demo(), Connect4Human(), SnakeGame()]
     self.selected = 0
     self.show_preview()
Exemple #7
0
 def __init__(self):
     self.button_events = ButtonEvents()
     self.cube = Cube()
     self.cube_buffer = get_empty_cube_buffer()
     self.wheel_start = self.get_random_wheel()
     self.wheel_stop = self.get_random_wheel()
Exemple #8
0
 def __init__(self):
     self.button_events = ButtonEvents()
     self.cube = Cube()
     self.snake = Snake()
     self.apple = Apple()
Exemple #9
0
class SnakeGame(App):
    def __init__(self):
        self.button_events = ButtonEvents()
        self.cube = Cube()
        self.snake = Snake()
        self.apple = Apple()

    def run(self) -> None:
        try:
            last_time = monotonic()
            self.apple.set_random_position(self.snake.snake)
            while True:
                self.handle_events()
                current_time = monotonic()
                if (current_time - last_time) > DELAY:
                    last_time = current_time
                    self.snake.move(self.apple)
                cube_buffer = get_empty_cube_buffer()
                cube_buffer = self.apple.draw(cube_buffer)
                cube_buffer = self.snake.draw(cube_buffer)
                self.cube.draw(cube_buffer)
                self.cube.show()
                if not is_a_raspberry():
                    sleep(0.01)
        except SnakeCollision:
            LOG.debug("collision")
            self.death_animation()
            return
        except SnakeInterrupted:
            return

    def death_animation(self) -> None:
        cube_buffer = get_empty_cube_buffer()
        for x in range(5):
            for y in range(5):
                for z in range(5):
                    cube_buffer[x][y][z] = wheel(85)
        self.cube.draw(cube_buffer)
        self.cube.show()
        sleep(1)

    def handle_events(self) -> None:
        """
        get user input to move snake
        """
        event = self.button_events.get_event(block=False)
        if event:
            if event == EventEnum.UP_PRESSED:
                self.snake.set_direction(Direction.FORWARD.value)
            elif event == EventEnum.DOWN_PRESSED:
                self.snake.set_direction(Direction.BACKWARD.value)
            elif event == EventEnum.LEFT_PRESSED:
                self.snake.set_direction(Direction.LEFT.value)
            elif event == EventEnum.RIGHT_PRESSED:
                self.snake.set_direction(Direction.RIGHT.value)
            elif event == EventEnum.A_PRESSED:
                self.snake.set_direction(Direction.UP.value)
            elif event == EventEnum.A_REPEATED:
                LOG.debug("interrupting snake")
                raise SnakeInterrupted()
            elif event == EventEnum.B_PRESSED:
                self.snake.set_direction(Direction.DOWN.value)

    def get_preview(self) -> CubeType:
        snake = Snake([(4, 4, 0), (4, 3, 0), (4, 2, 0), (4, 2, 1), (4, 2, 2),
                       (3, 2, 2)])
        apple = Apple()
        apple.set_random_position(snake.snake)
        cube_buffer = get_empty_cube_buffer()
        cube_buffer = apple.draw(cube_buffer)
        cube_buffer = snake.draw(cube_buffer)
        return cube_buffer

    def get_description(self) -> str:
        return "snake"
Exemple #10
0
class Rainbow(App):
    def __init__(self):
        self.button_events = ButtonEvents()
        self.cube = Cube()
        self.cube_buffer = get_empty_cube_buffer()
        self.theta = 0.0
        self.phi = 0.0
        self.wheel_offset = 0.0
        self.theta_d = 0.0
        self.phi_d = 0.0
        self.wheel_offset_d = 0.0

    def run(self):
        try:
            while True:
                self.handle_events()
                v = [
                    sin(self.theta) * cos(self.phi),
                    sin(self.theta) * sin(self.phi),
                    cos(self.theta)
                ]
                self.rainbow(self.cube_buffer, v, self.wheel_offset)
                self.cube.draw(self.cube_buffer)
                self.cube.show()
                # Rotate vector
                self.theta += self.theta_d
                self.phi += self.phi_d
                # Cycle through all colors so the rainbow not only rotates, but also
                # moves through the cube.
                self.wheel_offset += self.wheel_offset_d
                self.wheel_offset %= 256
                if not is_a_raspberry():
                    sleep(0.02)
        except RainbowInterrupted:
            return

    def handle_events(self):
        """
        adjust the rotation settings of the rainbow
        """
        event = self.button_events.get_event(block=False)
        if event:
            if event == EventEnum.UP_PRESSED or event == EventEnum.UP_REPEATED:
                self.theta_d += THETA_D
            elif event == EventEnum.DOWN_PRESSED or event == EventEnum.DOWN_REPEATED:
                self.theta_d -= THETA_D
            elif event == EventEnum.LEFT_PRESSED or event == EventEnum.LEFT_REPEATED:
                self.phi_d -= PHI_D
            elif event == EventEnum.RIGHT_PRESSED or event == EventEnum.RIGHT_REPEATED:
                self.phi_d += PHI_D
            elif event == EventEnum.A_PRESSED:
                self.wheel_offset_d -= WHEEL_OFFSET_D
            elif event == EventEnum.A_REPEATED:
                LOG.debug("interrupting rainbow")
                raise RainbowInterrupted()
            elif event == EventEnum.B_PRESSED:
                self.wheel_offset_d += 0.5
            elif event == EventEnum.B_REPEATED:
                self.theta = 0.0
                self.phi = 0.0
                self.wheel_offset = 0.0
                self.theta_d = 0.0
                self.phi_d = 0.0
                self.wheel_offset_d = 0.0

    def rainbow(self, cube_buffer, v, wheel_offset):
        """
        draw a rainbow across the cube, oriented according to the given vector
        :param cube_buffer: cube buffer to modify
        :param v: vector for rainbow orientation and scaling (unit vector results in one rainbow across the cube)
        :param wheel_offset: color wheel offset
        """
        for x in range(5):
            for y in range(5):
                for z in range(5):
                    dot_product = ((x - 2) * v[0] + (y - 2) * v[1] +
                                   (z - 2) * v[2])
                    # 37 is the number to have the full rainbow range from [-2, -2, -2] to [2, 2, 2]
                    # if v is a unit vector.
                    cube_buffer[x][y][z] = wheel(
                        int(dot_product * 37 + wheel_offset))

    def get_preview(self):
        preview = get_empty_cube_buffer()
        self.rainbow(preview, [0.5, 0.5, 0.5], 0)
        return preview

    def get_description(self) -> str:
        return "rainbow"
Exemple #11
0
 def __init__(self):
     self.cube = Cube()
Exemple #12
0
class LedViewer(BoardViewer):
    def __init__(self, mode=CYCLE):
        super().__init__()
        self.cube = Cube()
        self.queue = Queue()
        self.mode = mode
        self.animation_thread = StoppableThread(target=self.animation)
        self.animation_thread.setDaemon(True)
        self.animation_thread.start()

    def player_plays(self, x, y):
        self.queue.put((PLAY, x, y))

    def player_undoes(self):
        last_move = self.board.get_last()
        self.board.undo()
        if last_move != (None, None):
            self.queue.put((UNDO, *last_move))

    def player_selects(self, x, y):
        self.queue.put((SELECT, x, y))

    def finish(self, winning_coords):
        self.queue.put((FINISH, winning_coords))

    def close(self):
        self.animation_thread.stop()
        self.animation_thread.join()

    def animation(self):
        animation_state = AnimationState(self.mode)
        animation_list = [FieldColorsAnimation(animation_state, self.board.field)]
        while not self.animation_thread.stopped() or animation_list[-1].is_blocking() or not self.queue.empty():
            if not animation_list[-1].is_blocking():
                try:
                    event = self.queue.get_nowait()
                    # some animations have to stop when a new one is started
                    animation_list[-1].new_animation_available()
                    if event[0] == PLAY:
                        super().player_plays(*event[1:3])
                        animation_list.append(PlayAnimation(animation_state))
                    elif event[0] == UNDO:
                        x = event[1]
                        y = event[2]
                        z = self.get_z(x, y)
                        c = self.board.next_color
                        animation_list.append(UndoAnimation(animation_state, x, y, z, c))
                    elif event[0] == SELECT:
                        x = event[1]
                        y = event[2]
                        z = self.get_z(x, y)
                        c = self.board.next_color
                        top = self.board.field(x, y, z) is not EMPTY
                        animation_list.append(SelectAnimation(animation_state, x, y, z, c, top))
                    elif event[0] == FINISH:
                        c = RED
                        if self.board.next_color == RED:
                            c = BLUE
                        animation_list.append(FinishAnimation(animation_state, event[1], c))
                except Empty:
                    pass

            cube_buffer = get_empty_cube_buffer()
            for a in animation_list:
                a.animate(cube_buffer)

            # remove completed animations from list
            animation_list[:] = [a for a in animation_list if not a.is_done()]

            # draw the completed cube
            self.cube.draw(cube_buffer)
            self.cube.show()

            animation_state.update()

            if not is_a_raspberry():
                sleep(0.01)

    def get_z(self, x, y):
        z = 4
        while z > 0 and self.board.field(x, y, z - 1) == EMPTY:
            z -= 1
        return z