Beispiel #1
0
    def place_snake_at_starting_location(self):
        display_width = Config.get_or_throw('leds.display_width')
        display_height = Config.get_or_throw('leds.display_height')

        starting_height = int(
            round((self.__player_index + 1) *
                  (display_height / (self.__settings['num_players'] + 1)), 1))

        if self.__settings['num_players'] == 1:
            starting_width = int(round(display_width / 2, 1))
        else:
            if self.__player_index % 2 == 0:
                starting_width = int(round(display_width / 3, 1))
            else:
                starting_width = int(round((2 / 3) * display_width, 1))

        if self.__player_index % 2 == 0:
            self.__direction = self.RIGHT
        else:
            self.__direction = self.LEFT

        for x in range(self.__SNAKE_STARTING_LENGTH):
            if self.__player_index % 2 == 0:
                coordinate = (starting_height, starting_width - x)
            else:
                coordinate = (starting_height, starting_width + x)
            self.__snake_linked_list.append(coordinate)
            self.__snake_set.add(coordinate)
Beispiel #2
0
    def fade_to_frame(self, frame):
        if (self.__current_frame is None):
            self.__current_frame = frame
            return self.play_frame(frame)

        display_width = Config.get_or_throw('leds.display_width')
        display_height = Config.get_or_throw('leds.display_height')
        frame_steps = np.zeros([display_height, display_width, 3], np.int8)

        for x in range(display_width):
            for y in range(display_height):
                for rgb in range(0, 3):
                    frame_steps[y, x, rgb] = (
                        (frame[y, x, rgb].astype(np.int16) -
                         self.__current_frame[y, x, rgb].astype(np.int16)) /
                        self.__FADE_STEPS).astype(np.int8)

        for current_step in range(1, self.__FADE_STEPS):
            new_frame = np.zeros([display_height, display_width, 3], np.uint8)
            for x in range(display_width):
                for y in range(display_height):
                    for rgb in range(0, 3):
                        new_frame[y, x,
                                  rgb] = self.__current_frame[y, x, rgb] + (
                                      frame_steps[y, x, rgb] * current_step)

            # no need to sleep since the above calculation takes some small amount of time
            self.__set_frame_pixels(new_frame)

        self.__current_frame = frame
        self.__set_frame_pixels(frame)
Beispiel #3
0
    def tick(self):
        was_apple_eaten = False
        if self.__is_eliminated:
            return was_apple_eaten

        old_head_y, old_head_x = self.__snake_linked_list[0]
        display_width = Config.get_or_throw('leds.display_width')
        display_height = Config.get_or_throw('leds.display_height')

        if self.__direction == self.UP:
            new_head = ((old_head_y - 1) % display_height, old_head_x)
        elif self.__direction == self.DOWN:
            new_head = ((old_head_y + 1) % display_height, old_head_x)
        elif self.__direction == self.LEFT:
            new_head = (old_head_y, (old_head_x - 1) % display_width)
        elif self.__direction == self.RIGHT:
            new_head = (old_head_y, (old_head_x + 1) % display_width)

        self.__snake_linked_list.insert(0, new_head)

        # Must call this before placing the apple to ensure the apple is not placed on the new head
        self.__snake_set.add(new_head)

        if new_head == self.__snake_game.get_apple():
            was_apple_eaten = True
        else:
            old_tail = self.__snake_linked_list[-1]
            del self.__snake_linked_list[-1]
            if old_tail != new_head:
                # Prevent edge case when the head is "following" the tail.
                # If the old_tail is the same as the new_head, we don't want to remove the old_tail from the set
                # because  the call to `self.__snake_set.add(new_head)` would have been a no-op above.
                self.__snake_set.remove(old_tail)

        return was_apple_eaten
Beispiel #4
0
    def __init__(self, clear_screen=True):
        options = RGBMatrixOptions()
        options.rows = Config.get_or_throw('leds.display_height')
        options.cols = Config.get_or_throw('leds.display_width')
        options.chain_length = 1
        options.parallel = 1
        options.hardware_mapping = 'adafruit-hat'
        options.drop_privileges = False

        self.__matrix = RGBMatrix(options=options)
        self.__pixels = self.__matrix.CreateFrameCanvas()
        if clear_screen:
            self.clear_screen()
Beispiel #5
0
    def __init__(self):
        self.__secure = Config.get('server.use_ssl', False)

        if not self.__secure:
            self.__server = PifiThreadingHTTPServer(('0.0.0.0', 80),
                                                    PifiServerRequestHandler)
        else:
            self.__server = PifiThreadingHTTPServer(('0.0.0.0', 443),
                                                    PifiServerRequestHandler)
            self.__server.socket = ssl.wrap_socket(
                self.__server.socket,
                keyfile=Config.get_or_throw('server.keyfile'),
                certfile=Config.get_or_throw('server.certfile'),
                server_side=True)
Beispiel #6
0
 def __place_apple(self):
     display_width = Config.get_or_throw('leds.display_width')
     display_height = Config.get_or_throw('leds.display_height')
     while True:
         x = random.randint(0, display_width - 1)
         y = random.randint(0, display_height - 1)
         is_coordinate_occupied_by_a_snake = False
         for i in range(self.__settings['num_players']):
             is_coordinate_occupied_by_a_snake = self.__players[
                 i].is_coordinate_occupied(y, x)
             if is_coordinate_occupied_by_a_snake:
                 break
         if not is_coordinate_occupied_by_a_snake:
             break
     self.__apple = (y, x)
Beispiel #7
0
    def _board_to_frame(self):
        frame = np.zeros([
            Config.get_or_throw('leds.display_height'),
            Config.get_or_throw('leds.display_width'), 3
        ], np.uint8)
        rgb = self.__game_color_helper.get_rgb(self.__game_color_mode,
                                               self.__COLOR_CHANGE_FREQ,
                                               self._num_ticks)
        frame[(self._board[1:-1, 1:-1] == 1)] = rgb

        if self.__variant == self.__VARIANT_IMMIGRATION:
            rgb2 = self.__game_color_helper.get_rgb2(self.__game_color_mode,
                                                     self.__COLOR_CHANGE_FREQ,
                                                     self._num_ticks)
            frame[(self._board[1:-1, 1:-1] == 2)] = rgb2

        return frame
Beispiel #8
0
    def __get_ffmpeg_pixel_conversion_cmd(self):
        pix_fmt = 'gray'
        if VideoColorMode.is_color_mode_rgb(
                Config.get('video.color_mode',
                           VideoColorMode.COLOR_MODE_COLOR)):
            pix_fmt = 'rgb24'

        return (self.get_standard_ffmpeg_cmd() + ' '
                '-i pipe:0 ' +  # read input video from stdin
                '-filter:v ' + shlex.quote(  # resize video
                    'scale=' + str(Config.get_or_throw('leds.display_width')) +
                    'x' + str(Config.get_or_throw('leds.display_height'))) +
                " "
                '-c:a copy ' +  # don't process the audio at all
                '-f rawvideo -pix_fmt ' + shlex.quote(pix_fmt) +
                " "  # output in numpy compatible byte format
                'pipe:1'  # output to stdout
                )
Beispiel #9
0
    def __init__(self, clear_screen=True):
        self.__pixels = apa102.APA102(
            num_led=(Config.get_or_throw('leds.display_width') *
                     Config.get_or_throw('leds.display_height')),
            mosi=self.__MOSI_PIN,
            sclk=self.__SCLK_PIN,
            order=self.__LED_ORDER)

        brightness = Config.get('leds.brightness', 3)
        self.__pixels.set_global_brightness(brightness)
        if clear_screen:
            self.clear_screen()

        # Look up the order in which to write each color value to the LED strip.
        # It's 1-indexed, so subtract by 1.
        self.__color_order = [x - 1 for x in apa102.RGB_MAP[self.__LED_ORDER]]

        # Calculate the LED start "frame": 3 1 bits followed by 5 brightness bits. See
        # set_pixel in the apa102 implementation for this calculation.
        self.__ledstart = (brightness & 0b00011111) | self.__pixels.LED_START
Beispiel #10
0
 def _seed_hook(self):
     # Create the board with an extra edge cell on all sides to simplify the
     # neighborhood calculation and avoid edge checks.
     shape = [
         Config.get_or_throw('leds.display_height') + 2,
         Config.get_or_throw('leds.display_width') + 2
     ]
     self._board = np.zeros(shape, np.uint8)
     probability = Config.get('game_of_life.seed_liveness_probability',
                              1 / 3)
     if self.__variant == self.__VARIANT_IMMIGRATION:
         seed = np.random.random_sample([x - 2 for x in shape
                                         ]) < (probability / 2)
         seed2 = np.random.random_sample([x - 2 for x in shape
                                          ]) < (probability / 2)
         self._board[1:-1, 1:-1][seed] = 1
         self._board[1:-1, 1:-1][seed2] = 2
     else:  # __VARIANT_NORMAL
         seed = np.random.random_sample([x - 2
                                         for x in shape]) < probability
         self._board[1:-1, 1:-1][seed] = 1
Beispiel #11
0
    def __show_board(self):
        frame = np.zeros([
            Config.get_or_throw('leds.display_height'),
            Config.get_or_throw('leds.display_width'), 3
        ], np.uint8)

        for i in range(self.__settings['num_players']):
            if (not self.__players[i].should_show_snake()):
                # Blink snakes for the first few ticks after they are eliminated.
                continue

            for (y, x) in self.__players[i].get_snake_linked_list():
                frame[y, x] = self.__players[i].get_snake_rgb()

        if self.__apple is not None:
            apple_rgb = self.__game_color_helper.get_rgb(
                GameColorHelper.GAME_COLOR_MODE_RAINBOW,
                self.__APPLE_COLOR_CHANGE_FREQ, self.__num_ticks)
            frame[self.__apple[0], self.__apple[1]] = apple_rgb

        self.__led_frame_player.play_frame(frame)
Beispiel #12
0
    def display_score(self, rgb=[255, 0, 0]):
        score_string = str(self.__score)
        digit_component_length = self.__get_digit_component_length()

        # omitted left corner + component length + omitted right corner + padding
        digit_width = 1 + digit_component_length + 1 + 1

        # omitted top pixel + component length + omitted middle pixel + component length + omitted bottom pixel
        digit_height = 1 + digit_component_length + 1 + digit_component_length + 1

        num_digits = len(score_string)
        score_width = digit_width * num_digits
        display_width = Config.get_or_throw('leds.display_width')
        display_height = Config.get_or_throw('leds.display_height')
        x = round((display_width - score_width) / 2)
        y = round((display_height - digit_height) / 2)
        frame = np.zeros([display_height, display_width, 3], np.uint8)
        for i in range(0, num_digits):
            self.__write_digit(x, y, int(score_string[i]),
                               digit_component_length, frame, rgb)
            x = x + digit_width

        self.__led_frame_player.play_frame(frame)
Beispiel #13
0
    def __init__(self,
                 clear_screen=True,
                 video_color_mode=VideoColorMode.COLOR_MODE_COLOR):
        self.__current_frame = None
        self.__gamma_controller = Gamma(video_color_mode=video_color_mode)

        # static gamma curve
        self.__scale_red_gamma_curve = None
        self.__scale_green_gamma_curve = None
        self.__scale_blue_gamma_curve = None

        # dynamic gamma curves
        self.__scale_red_gamma_curves = None
        self.__scale_green_gamma_curves = None
        self.__scale_blue_gamma_curves = None

        # Memoizing the specific gamma curve index for static gamma videos enables us to shave
        # 1 or 2 milliseconds off the loop per frame. See: self.__set_frame_pixels
        if VideoColorMode.is_color_mode_rgb(video_color_mode):
            # static gamma
            self.__scale_red_gamma_curve = self.__gamma_controller.scale_red_curves[
                Gamma.DEFAULT_GAMMA_INDEX]
            self.__scale_green_gamma_curve = self.__gamma_controller.scale_green_curves[
                Gamma.DEFAULT_GAMMA_INDEX]
            self.__scale_blue_gamma_curve = self.__gamma_controller.scale_blue_curves[
                Gamma.DEFAULT_GAMMA_INDEX]
        else:
            # dynamic gamma
            self.__scale_red_gamma_curves = self.__gamma_controller.scale_red_curves
            self.__scale_green_gamma_curves = self.__gamma_controller.scale_green_curves
            self.__scale_blue_gamma_curves = self.__gamma_controller.scale_blue_curves

        led_driver = Config.get_or_throw('leds.driver')
        if led_driver == LedDrivers.DRIVER_APA102:
            from pifi.led.drivers.driverapa102 import DriverApa102
            self.__driver = DriverApa102(clear_screen)
        elif led_driver == LedDrivers.DRIVER_RGBMATRIX:
            from pifi.led.drivers.driverrgbmatrix import DriverRgbMatrix
            self.__driver = DriverRgbMatrix(clear_screen)
        else:
            raise Exception(f'Unsupported driver: {led_driver}.')

        self.__video_color_mode = video_color_mode
Beispiel #14
0
    def __transform_frame(self, frame):
        if not (VideoColorMode.is_color_mode_rgb(self.__video_color_mode)):
            gamma_index = self.__gamma_controller.getGammaIndexForMonochromeFrame(
                frame)

        shape = [
            Config.get_or_throw('leds.display_height'),
            Config.get_or_throw('leds.display_width'), 3
        ]
        transformed_frame = np.zeros(shape, np.uint8)
        # calculate gamma corrected colors
        if self.__video_color_mode == VideoColorMode.COLOR_MODE_COLOR:
            transformed_frame[:, :, 0] = np.take(self.__scale_red_gamma_curve,
                                                 frame[:, :, 0])
            transformed_frame[:, :,
                              1] = np.take(self.__scale_green_gamma_curve,
                                           frame[:, :, 1])
            transformed_frame[:, :, 2] = np.take(self.__scale_blue_gamma_curve,
                                                 frame[:, :, 2])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_R:
            transformed_frame[:, :, 0] = np.take(
                self.__scale_red_gamma_curves[gamma_index], frame[:, :])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_G:
            transformed_frame[:, :, 1] = np.take(
                self.__scale_green_gamma_curves[gamma_index], frame[:, :])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_B:
            transformed_frame[:, :, 2] = np.take(
                self.__scale_blue_gamma_curves[gamma_index], frame[:, :])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_BW:
            transformed_frame[:, :, 0] = np.take(
                self.__scale_red_gamma_curves[gamma_index], frame[:, :])
            transformed_frame[:, :, 1] = np.take(
                self.__scale_green_gamma_curves[gamma_index], frame[:, :])
            transformed_frame[:, :, 2] = np.take(
                self.__scale_blue_gamma_curves[gamma_index], frame[:, :])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_INVERT_COLOR:
            transformed_frame[:, :, 0] = np.take(self.__scale_red_gamma_curve,
                                                 255 - frame[:, :, 0])
            transformed_frame[:, :,
                              1] = np.take(self.__scale_green_gamma_curve,
                                           255 - frame[:, :, 1])
            transformed_frame[:, :, 2] = np.take(self.__scale_blue_gamma_curve,
                                                 255 - frame[:, :, 2])
        elif self.__video_color_mode == VideoColorMode.COLOR_MODE_INVERT_BW:
            transformed_frame[:, :, 0] = np.take(
                self.__scale_red_gamma_curves[gamma_index], 255 - frame[:, :])
            transformed_frame[:, :, 1] = np.take(
                self.__scale_green_gamma_curves[gamma_index],
                255 - frame[:, :])
            transformed_frame[:, :, 2] = np.take(
                self.__scale_blue_gamma_curves[gamma_index], 255 - frame[:, :])
        else:
            raise Exception(
                f'Unexpected color mode: {self.__video_color_mode}.')

        flips = ()
        if Config.get('leds.flip_y', False):
            flips += (0, )
        if Config.get('leds.flip_x', False):
            flips += (1, )
        if flips:
            transformed_frame = np.flip(transformed_frame, flips)

        return transformed_frame
Beispiel #15
0
 def _seed_hook(self):
     # Create the board with an extra edge cell on all sides to simplify the
     # neighborhood calculation and avoid edge checks.
     shape = [Config.get_or_throw('leds.display_height') + 2, Config.get_or_throw('leds.display_width') + 2]
     self._board = np.random.randint(0, self.__num_states, shape)
Beispiel #16
0
 def __clear_board(self):
     frame = np.zeros([
         Config.get_or_throw('leds.display_height'),
         Config.get_or_throw('leds.display_width'), 3
     ], np.uint8)
     self.__led_frame_player.play_frame(frame)
Beispiel #17
0
    def __process_and_play_video(self):
        ffmpeg_to_python_fifo_name = self.__make_fifo(
            additional_prefix='ffmpeg_to_python')
        fps_fifo_name = self.__make_fifo(additional_prefix='fps')

        process_and_play_vid_cmd = self.__get_process_and_play_vid_cmd(
            ffmpeg_to_python_fifo_name, fps_fifo_name)
        self.__logger.info('executing process and play cmd: ' +
                           process_and_play_vid_cmd)
        process_and_play_vid_proc = subprocess.Popen(
            process_and_play_vid_cmd,
            shell=True,
            executable='/usr/bin/bash',
            start_new_session=True)
        # Store the PGID separately, because attempting to get the PGID later via `os.getpgid` can
        # raise `ProcessLookupError: [Errno 3] No such process` if the process is no longer running
        self.__process_and_play_vid_proc_pgid = os.getpgid(
            process_and_play_vid_proc.pid)

        display_width = Config.get_or_throw('leds.display_width')
        display_height = Config.get_or_throw('leds.display_height')
        bytes_per_frame = display_width * display_height
        np_array_shape = [display_height, display_width]
        if VideoColorMode.is_color_mode_rgb(
                Config.get('video.color_mode',
                           VideoColorMode.COLOR_MODE_COLOR)):
            bytes_per_frame = bytes_per_frame * 3
            np_array_shape.append(3)

        vid_start_time = None
        last_frame = None
        vid_processing_lag_counter = 0
        is_ffmpeg_done_outputting = False
        frames = ReadOnceCircularBuffer(self.__FRAMES_BUFFER_LENGTH)
        ffmpeg_to_python_fifo = open(ffmpeg_to_python_fifo_name, 'rb')

        fps = self.__read_fps_from_fifo(fps_fifo_name)
        frame_length = 1 / fps
        pathlib.Path(self.__FPS_READY_FILE).touch()
        while True:
            if is_ffmpeg_done_outputting or frames.is_full():
                pass
            else:
                is_ffmpeg_done_outputting, vid_start_time = self.__populate_frames(
                    frames, ffmpeg_to_python_fifo, vid_start_time,
                    bytes_per_frame, np_array_shape)

            if vid_start_time is None:
                # video has not started being processed yet
                pass
            else:
                if self.__init_time:
                    self.__logger.info(
                        f"Started playing video after {round(time.time() - self.__init_time, 3)} s."
                    )
                    self.__init_time = None

                is_video_done_playing, last_frame, vid_processing_lag_counter = self.__play_video(
                    frames, vid_start_time, frame_length,
                    is_ffmpeg_done_outputting, last_frame,
                    vid_processing_lag_counter)
                if is_video_done_playing:
                    break

        self.__logger.info("Waiting for process_and_play_vid_proc to end...")
        while True:  # Wait for proc to end
            if process_and_play_vid_proc.poll() is not None:
                if process_and_play_vid_proc.returncode != 0:
                    raise YoutubeDlException(
                        "The process_and_play_vid_proc process exited non-zero: "
                        +
                        f"{process_and_play_vid_proc.returncode}. This could mean an issue with youtube-dl; "
                        + "it may require updating.")
                self.__logger.info("The process_and_play_vid_proc proc ended.")
                break
            time.sleep(0.1)
Beispiel #18
0
 def __get_digit_component_length(self):
     return min(round(3 * Config.get_or_throw('leds.display_width') / 28),
                round(3 * Config.get_or_throw('leds.display_height') / 18))