Пример #1
0
 def __init__(self, viewer):
     BasePlayer.__init__(self, viewer)
     self.button_events = ButtonEvents()
     self.selected = (2, 2)
     # short timeout after a game starts, it is increased on the first input
     self.timeout = 30
     self.return_position = (None, None)
Пример #2
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
Пример #3
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()
Пример #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"
Пример #5
0
 def __init__(self):
     self.cube = Cube()
     self.button_events = ButtonEvents()
     self.apps = [Rainbow(), Random(), Connect4Demo(), Connect4Human(), SnakeGame()]
     self.selected = 0
     self.show_preview()
Пример #6
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()
Пример #7
0
 def __init__(self):
     self.button_events = ButtonEvents()
     self.cube = Cube()
     self.snake = Snake()
     self.apple = Apple()
Пример #8
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"
Пример #9
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"
Пример #10
0
class GpioPlayer(BasePlayer):
    """
    A binary-joystick controlled player using RasPi GPIOs
    https://gpiozero.readthedocs.io/en/stable/
    """
    def __init__(self, viewer):
        BasePlayer.__init__(self, viewer)
        self.button_events = ButtonEvents()
        self.selected = (2, 2)
        # short timeout after a game starts, it is increased on the first input
        self.timeout = 30
        self.return_position = (None, None)

    def axis_pressed(self, dx, dy):
        LOG.debug("axis button pressed: {} {}".format(dx, dy))
        x, y = self.selected
        x += dx
        y += dy
        if not (0 <= x < 5 and 0 <= y < 5):
            LOG.debug("out of bounds: ignoring {},{}".format(x, y))
            return
        self.selected = (x, y)
        LOG.debug("selected {},{}".format(x, y))
        self.do_select(x, y)

    def drop_pressed(self):
        LOG.debug("drop button pressed")
        if self.board.field(*self.selected, 4) != EMPTY:
            LOG.debug("non playable location, ignoring")
            return
        self.return_position = self.selected

    def undo_pressed(self):
        LOG.debug("undo button pressed")
        self.return_position = (-1, -1)

    def reset_pressed(self):
        LOG.debug("reset button pressed")
        raise PlayerResetError()

    def exit_pressed(self):
        LOG.debug("exit button pressed")
        raise PlayerExitError()

    def do_play(self) -> tuple:
        if self.selected == (-1, -1):
            self.selected = (2, 2)
        self.do_select(*self.selected)  # first show the last selected location
        self.button_events.clear()
        self.return_position = (None, None)
        event_functions = {
            EventEnum.UP_PRESSED: lambda: self.axis_pressed(-1, 0),
            EventEnum.UP_REPEATED: lambda: self.axis_pressed(-1, 0),
            EventEnum.DOWN_PRESSED: lambda: self.axis_pressed(1, 0),
            EventEnum.DOWN_REPEATED: lambda: self.axis_pressed(1, 0),
            EventEnum.LEFT_PRESSED: lambda: self.axis_pressed(0, -1),
            EventEnum.LEFT_REPEATED: lambda: self.axis_pressed(0, -1),
            EventEnum.RIGHT_PRESSED: lambda: self.axis_pressed(0, 1),
            EventEnum.RIGHT_REPEATED: lambda: self.axis_pressed(0, 1),
            EventEnum.A_PRESSED: self.drop_pressed,
            EventEnum.A_REPEATED: self.exit_pressed,
            EventEnum.B_PRESSED: self.undo_pressed,
            EventEnum.B_REPEATED: self.reset_pressed,
        }
        while self.return_position == (None, None):
            event = self.button_events.get_event(timeout=self.timeout)
            if event:
                event_function = event_functions[event]
                if event_function is not None:
                    event_functions[event]()
            else:
                LOG.warning("player idle for too long")
                raise PlayerExitError()

            # increase timeout after first event
            self.timeout = 200
        return self.return_position