from .game import Game from . import menu from .command import Command import os import logging import pygame from .serial import Serial import json from .games import benchmark from .games.snake import Snake from .games.breakout import Breakout from .games.pong import Pong def main() -> int: logger = logging.getLogger(__name__) pygame.init() serial = Serial(os.getenv("SERIAL_DEVICE", "/dev/null"), 115200) INSTANCE = os.getenv("INSTANCE", "Unknown") is_joint_mode = [False] pygame.display.set_caption(f"SplitScreen Duo ({INSTANCE})") logging.basicConfig( level=(logging.DEBUG if os.getenv("DEVELOPMENT", "").lower() else logging.INFO) ) print("The Dual Screen Console") logger.info(f"running as {os.getenv('INSTANCE', 'unknown')}") menu.init_display() menu.set_screen_orientation(is_joint_mode[0]) font = pygame.font.Font(None, 36) BLACK = (0, 0, 0) WHITE = (255, 255, 255) score = 0 game_handlers = { Game.BENCHMARK.value: ( "benchmark", lambda: benchmark.main_loop(menu.screen, serial), ), Game.SNAKE.value: ( "snake", lambda: Snake(menu.screen, serial, INSTANCE, is_joint_mode[0]).main_loop(), ), Game.BREAKOUT.value: ( "breakout", lambda: Breakout( menu.screen, serial, INSTANCE, is_joint_mode[0] ).main_loop(), ), Game.PONG.value: ( "pong", lambda: Pong(menu.screen, serial, INSTANCE, is_joint_mode[0]).main_loop(), ), } def handle_game_selection(message_or_command, is_secondary=False): game_value = message_or_command.get("value") if game_value in game_handlers: game_name, game_func = game_handlers[game_value] logger.info( f"{'received' if is_secondary else 'starting'} {game_name} game selection from {'primary' if is_secondary else 'menu'}" ) game_result = game_func() if is_joint_mode[0] and INSTANCE == "primary": serial.write( json.dumps({"command": Command.GAME_ENDED.value}).encode("utf-8") ) if game_result and game_result.get("command") == Command.QUIT.value: logger.info(f"{game_name} game returned QUIT, shutting down") pygame.quit() return 0 return None is_running = True while is_running: if serial.in_waiting() > 0: data = serial.readline().decode("utf-8").strip() try: message = json.loads(data) command = message.get("command") if command == Command.ENTER_JOINT_MODE.value: is_joint_mode[0] = True menu.set_screen_orientation(is_joint_mode[0]) logger.info("secondary entering joint mode") elif command == Command.EXIT_JOINT_MODE.value: is_joint_mode[0] = False menu.set_screen_orientation(is_joint_mode[0]) logger.info("secondary exiting joint mode") elif command == Command.QUIT.value: pygame.quit() return 0 elif INSTANCE == "secondary" and is_joint_mode[0]: if command == Command.STATS.value: score = message.get("value", 0) elif command == Command.GAME_ENDED.value: menu.screen.fill(BLACK) text = font.render("Game Ended", True, WHITE) menu.screen.blit( text, ( menu.screen.get_width() // 2 - text.get_width() // 2, menu.screen.get_height() // 2, ), ) pygame.display.flip() pygame.time.wait(2000) score = 0 elif ( INSTANCE == "secondary" and not is_joint_mode[0] and command == Command.SELECT_GAME.value ): result = handle_game_selection(message, is_secondary=True) if result == 0: return 0 except json.JSONDecodeError: logger.error("failed to decode serial message") except Exception as e: logger.error(f"error processing serial data: {e}") if INSTANCE == "secondary" and is_joint_mode[0]: menu.screen.fill(BLACK) text = font.render(f"Score: {score}", True, WHITE) menu.screen.blit( text, ( menu.screen.get_width() // 2 - text.get_width() // 2, menu.screen.get_height() // 2, ), ) pygame.display.flip() pygame.time.delay(100) else: serial_command = menu.process_events(serial, INSTANCE, is_joint_mode) if serial_command: if not is_joint_mode[0] or INSTANCE == "primary": serial.write(json.dumps(serial_command).encode("utf-8")) if serial_command.get("command") == Command.QUIT.value: pygame.quit() return 0 elif serial_command.get("command") == Command.SELECT_GAME.value: result = handle_game_selection(serial_command) if result == 0: return 0 pygame.quit() return 0 if __name__ == "__main__": main()