From 5999509f7d47a640c9af697c9050be3836071645 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Tue, 27 Dec 2022 13:13:51 -0600 Subject: [PATCH] removed chess, added music menu --- __main__.py | 48 ++++----- plugin/chess/__init__.py | 7 -- plugin/chess/draw.py | 194 --------------------------------- plugin/chess/game.py | 227 --------------------------------------- requirements.txt | 19 ++++ 5 files changed, 39 insertions(+), 456 deletions(-) delete mode 100644 plugin/chess/__init__.py delete mode 100644 plugin/chess/draw.py delete mode 100644 plugin/chess/game.py create mode 100644 requirements.txt diff --git a/__main__.py b/__main__.py index 10a0909..d213877 100644 --- a/__main__.py +++ b/__main__.py @@ -9,44 +9,36 @@ from cinput import ControlInput from graphics import Graphics menu_config = [ - MenuItem("Apps", + MenuItem("Music", MenuType.SUB_MENU, {"sub_menu": [ - MenuItem("Chess Game", + MenuItem("Artists", MenuType.PLUGIN, - {"plugin": "chess", - "arg": "game"}), - MenuItem("Chess Puzzles", + {"plugin": "music", + "arg": "artists"}), + MenuItem("Genres", MenuType.PLUGIN, - {"plugin": "chess", - "arg": "puzzles"}), - MenuItem("Cube Timer", + {"plugin": "music", + "arg": "genres"}), + MenuItem("Playlists", MenuType.PLUGIN, - {"plugin": "cube", - "arg": None}), + {"plugin": "music", + "arg": "playlists"}), ]}), - MenuItem("Information", - MenuType.PLUGIN, - {"plugin": "info", - "arg": None}), - MenuItem("Config", + MenuItem("System", MenuType.SUB_MENU, {"sub_menu": [ - MenuItem("Brightness", + MenuItem("Information", MenuType.PLUGIN, - {"plugin": "config", - "arg": "brightness"}), - MenuItem("Wifi", - MenuType.PLUGIN, - {"plugin": "config", - "arg": "wifi"}), + {"plugin": "info", + "arg": None}), + MenuItem("Reboot", + MenuType.EXIT_CMD, + {"command": "sudo reboot"}), + MenuItem("Shutdown", + MenuType.EXIT_CMD, + {"command": "sudo shutdown now"}) ]}), - MenuItem("Reboot", - MenuType.EXIT_CMD, - {"command": "sudo reboot"}), - MenuItem("Shutdown", - MenuType.EXIT_CMD, - {"command": "sudo shutdown now"})] cinput = ControlInput() graphics = Graphics() diff --git a/plugin/chess/__init__.py b/plugin/chess/__init__.py deleted file mode 100644 index ca560e6..0000000 --- a/plugin/chess/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from cinput import ControlInput -from graphics import Graphics -from .game import ChessGame - -def execute(cinput: ControlInput, graphics: Graphics, arg: str): - if arg == "game": - ChessGame(cinput, graphics).run() diff --git a/plugin/chess/draw.py b/plugin/chess/draw.py deleted file mode 100644 index f57edf0..0000000 --- a/plugin/chess/draw.py +++ /dev/null @@ -1,194 +0,0 @@ -from typing import Optional -from icecream import ic -from graphics import Graphics -from chess import Board, Outcome, Color, WHITE - -class Draw: - BOARD_SIZE = 64 - SQUARE_SIZE = 8 - - PIECES = { - "p": [ - " . . . . . . ", - " . . ■ ■ . . ", - " . ■ - - ■ . ", - " . ■ - - ■ . ", - " . . ■ ■ . . ", - " . . . . . . "], - "r": [ - " ■ ■ ■ ■ ■ ■ ", - " ■ - - - - ■ ", - " . ■ - - ■ . ", - " . ■ - - ■ . ", - " ■ - - - - ■ ", - " ■ ■ ■ ■ ■ ■ "], - "n": [ - " . . ■ ■ ■ . ", - " . ■ - - - ■ ", - " ■ - - - - ■ ", - " . ■ - - - ■ ", - " . . ■ - - ■ ", - " . . ■ ■ ■ ■ "], - "b": [ - " . . ■ ■ . . ", - " . ■ - - ■ . ", - " . ■ - - ■ . ", - " . ■ - - ■ . ", - " ■ - - - - ■ ", - " ■ ■ ■ ■ ■ ■ "], - "q": [ - " ■ . . . . ■ ", - " ■ ■ . . ■ ■ ", - " ■ - ■ ■ - ■ ", - " ■ - - - - ■ ", - " ■ - - - - ■ ", - " ■ ■ ■ ■ ■ ■ "], - - "k": [ - " . . ■ ■ . . ", - " ■ ■ - - ■ ■ ", - " ■ - - - - ■ ", - " ■ ■ - - ■ ■ ", - " . ■ - - ■ . ", - " . ■ ■ ■ ■ . "], - } - - MENU = [ - "Play", - "Quit", - "New (W)", - "New (B)"] - - def __init__(self, graphics: Graphics): - self._graphics = graphics - - def _draw_piece(self, piece: list[str], white: bool, sqx, sqy, sqc): - c = 0 if sqc == 1 else 1 - filled = (white and sqc == 0) or (not white and sqc == 1) - for row in range(len(piece)): - pixels = piece[row].replace(" ", "") - for col in range(len(pixels)): - x = (sqx * self.SQUARE_SIZE) + col + 1 - y = (sqy * self.SQUARE_SIZE) + row + 1 - pixel = pixels[col] - if pixel == '■': - self._graphics.pixel(x, y, c) - elif pixel =='-': - self._graphics.pixel(x, y, c if filled else sqc) - - def _clear_info(self): - self._graphics.fill_rect( - self.BOARD_SIZE, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0) - - def _format_move(self, move: str): - if len(move) == 4: - return move.upper()[:2] + "-" + move.upper()[2:] - return move - - def _invert_pixel(self, x: int, y: int): - c = self._graphics.pixel(x, y) - c = 0 if c != 0 else 1 - self._graphics.pixel(x, y, c) - - def _cursor_clear(self, except_for: list[str], player_color: Color): - c = 1 - for row in range(8): - for col in range(8): # 0,0 w = a8 b = h1 ... 7,7 w = h1 b = a8 - sqx = col if player_color == WHITE else 7 - col - sqy = 7 - row if player_color == WHITE else row - square = chr(sqx + 97) + str(sqy + 1) - if not (square in except_for): - # see if square is right color - sqc = self._graphics.pixel(col * 8, row * 8) - if sqc != c: - self._cursor(square, player_color); - c = 0 if c == 1 else 1 - c = 0 if c == 1 else 1 - - def _cursor(self, square: str, player_color: Color): - sqx = ord(square[0]) - 97 - sqy = int(square[1]) - 1 - if player_color == WHITE: - sqy = 7 - sqy - else: - sqx = 7 - sqx - for i in range(8): - # top and bottom row - self._invert_pixel(sqx * 8 + i, sqy * 8) - self._invert_pixel(sqx * 8 + i, sqy * 8 + 7) - if i > 0 and i < 7: - # sides (skipping top and bottom row) - self._invert_pixel(sqx * 8, sqy * 8 + i) - self._invert_pixel(sqx * 8 + 7, sqy * 8 + i) - - def draw_board(self, board: Board, player_color: Color): - self._graphics.fill_rect(0, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0) - nb = "".join(str(board).split()).replace(" ", "") - nb = nb if player_color == WHITE else nb[::-1] - c = True - for row in range(8): - for col in range(8): - if c: - x = col * self.SQUARE_SIZE - y = row * self.SQUARE_SIZE - self._graphics.fill_rect(x, y, self.SQUARE_SIZE, self.SQUARE_SIZE, 1) - p = nb[(row * 8) + col] - if p.lower() in self.PIECES: - self._draw_piece( - self.PIECES[p.lower()], p.isupper(), col, row, c) - c = not c - c = not c - self._graphics.show() - - def draw_menu(self, menu_index: int): - self._clear_info() - self._graphics.text("Menu:", 12, 0, 1) - for i in range(len(self.MENU)): - marker = "> " if i == menu_index else " " - self._graphics.text(marker + self.MENU[i], 12, i + 2, 1) - self._graphics.show() - - def draw_thinking(self, last_move: str): - self._clear_info() - self._graphics.text(self._format_move(last_move), 12, 0, 1) - self._graphics.text("Shh, I'm", 12, 2, 1) - self._graphics.text("thinking!", 12, 3, 1) - self._graphics.show() - - def draw_checkmate(self, move: str, player_won: bool): - self._clear_info() - self._graphics.text(move, 12, 0, 1) - self._graphics.text("Checkmate", 12, 1, 1) - self._graphics.text( - "you win!" if player_won else "you lose!", 12, 2, 1) - self._graphics.show() - - def draw_select(self, last_move: str, player_color: Color, src: Optional[str], dst: Optional[str] = None): - self._clear_info() - self._graphics.text(self._format_move(last_move), 12, 0, 1) - self._graphics.text("You move:", 12, 2, 1) - if src != None and dst == None: - self._graphics.text("<" + src.upper() + "> - __", 12, 3, 1) - self._cursor_clear([src], player_color) - self._cursor(src, player_color) - elif src != None and dst != None: - self._graphics.text(src.upper() + " - <" + dst.upper() + ">", 12, 3, 1) - self._cursor_clear([src, dst], player_color) - self._cursor(src, player_color) - self._cursor(dst, player_color) - else: - self._cursor_clear(list(), player_color) - - self._graphics.show() - - def draw_game_over(self, outcome: Optional[Outcome]): - self._clear_info() - self._graphics.text("Game over", 12, 0, 1) - if outcome != None: - if outcome.winner == None: - self._graphics.text("Draw!", 12, 2, 1) - else: - self._graphics.text("Winner:", 12, 2, 1) - self._graphics.text("White!" if outcome.winner == WHITE else "Black!", - 12, 3, 1) - self._graphics.show() diff --git a/plugin/chess/game.py b/plugin/chess/game.py deleted file mode 100644 index 64d42e5..0000000 --- a/plugin/chess/game.py +++ /dev/null @@ -1,227 +0,0 @@ -from os import path -from typing import Optional -from enum import Enum, auto -import shutil -from icecream import ic -from cinput import ControlInput, Button -from graphics import Graphics -from .draw import Draw -from chess import Board, Move, WHITE, BLACK -from stockfish import Stockfish - -class GameState(Enum): - MAIN_MENU = auto() - THINKING = auto() - CHOOSE_SRC = auto() - CHOOSE_DST = auto() - GAME_OVER = auto() - -class ChessGame: - SAVE_FILE = path.join("data", "chess_state.fen") - STOCKFISH_MOVE_TIME = 3 - - def __init__(self, cinput: ControlInput, graphics: Graphics): - self._sf = Stockfish(shutil.which("stockfish") or "stockfish") - self._cinput = cinput - self._draw = Draw(graphics) - self._state = GameState.MAIN_MENU - self._menu_index = 0 - - def _init_new_game(self, fen = None, player_color = None): - self._board = Board() if fen == None else Board(fen) - self._move = "Begin!" - self._all_moves = dict() - self._src_idx = 0 - self._dst_idx = 0 - self._player_color = player_color if player_color != None else self._board.turn - self._sf.set_fen_position(self._board.fen()) - self._draw.draw_board(self._board, self._player_color) - - def _load_saved_or_init(self): - if path.exists(self.SAVE_FILE): - with open(self.SAVE_FILE, "r") as fen: - fen = fen.read() - self._init_new_game(fen) - else: - self._init_new_game() - - def _save_game(self): - with open(self.SAVE_FILE, "w") as fen: - fen.write(self._board.fen()) - - def _make_move(self, move: str): - self._move = move - self._board.push(Move.from_uci(move)) - self._sf.make_moves_from_current_position([move]) - self._draw.draw_board(self._board, self._player_color) - - def _square_sort_key(self, square: str): - # convert to number between 00 to 88 - key = (int(square[1]) - 1) * 10 + ord(square[0]) - 97 - return key if self._player_color == WHITE else 88 - key - - def _get_sources(self): - if len(list(self._all_moves)) == 0: - moves = self._board.generate_legal_moves() - mvarray = map(lambda m: [Move.uci(m)[0:2], Move.uci(m)[2:4]], moves) - for src, dst in list(mvarray): - self._all_moves.setdefault(src, []).append(dst) - if len(list(self._all_moves)) > 0: - return sorted( - list(self._all_moves), - key=lambda x: self._square_sort_key(x)) - return list[str]() - - def _get_dests(self): - if self._src_idx < len(list(self._all_moves)): - src = self._get_sources()[self._src_idx] - return sorted( - self._all_moves[src], - key=lambda x: self._square_sort_key(x)) - return list[str]() - - def run(self): - # either load the save game or start a new one - self._load_saved_or_init() - - while True: - key: Optional[Button] = None - src: Optional[str] = None - - ################ - # HANDLE STATE # - ################ - - if self._board.is_game_over() and self._state != GameState.MAIN_MENU: - self._state = GameState.GAME_OVER - - # draw menu - if self._state == GameState.MAIN_MENU: - self._draw.draw_board(self._board, self._player_color) - self._draw.draw_menu(self._menu_index) - key = self._cinput.get_one_shot() - - # computer makes a move - elif self._state == GameState.THINKING: - self._draw.draw_board(self._board, self._player_color) - self._draw.draw_thinking(self._move) - move = self._sf.get_best_move_time(self.STOCKFISH_MOVE_TIME * 1000) - if move != None: - self._make_move(move) - # reset user moves and move state to user's turn - self._all_moves = dict() - self._src_idx = 0 - self._dst_idx = 0 - self._state = GameState.CHOOSE_SRC - else: - self._state = GameState.GAME_OVER - - # user picks source piece - elif self._state == GameState.CHOOSE_SRC: - if len(self._get_sources()) > 0: - src = self._get_sources()[self._src_idx] - self._draw.draw_select(self._move, self._player_color, src) - key = self._cinput.get_one_shot(0.1) - else: - self._state = GameState.GAME_OVER - - # user picks dest square - elif self._state == GameState.CHOOSE_DST: - src = self._get_sources()[self._src_idx] - dst = self._get_dests()[self._dst_idx] - self._draw.draw_select(self._move, self._player_color, src, dst) - key = self._cinput.get_one_shot(0.1) - - # game has ended - else: - self._draw.draw_board(self._board, self._player_color) - self._draw.draw_game_over(self._board.outcome()) - key = self._cinput.get_one_shot() - - ################ - # HANDLE INPUT # - ################ - - if key == None: - continue - - # handle user input on main menu - if self._state == GameState.MAIN_MENU: - - # menu cursor up and down - if key == Button.DIR_U: - self._menu_index -= 1 - if self._menu_index < 0: - self._menu_index = 0 - elif key == Button.DIR_D: - self._menu_index += 1 - if self._menu_index > 3: - self._menu_index = 3 - - # select current menu item - elif key == Button.BTN_B: - if self._menu_index == 0: # play current game - self._state = GameState.CHOOSE_SRC - elif self._menu_index == 1: # save and quit - self._save_game() - return - elif self._menu_index == 2 or self._menu_index == 3: # new game - if self._menu_index == 2: - self._init_new_game(player_color=WHITE) - self._state = GameState.CHOOSE_SRC - else: - self._init_new_game(player_color=BLACK) - self._state = GameState.THINKING - - # handle user input when selecting source piece - # TODO: some kind of cursor indicator on board - elif self._state == GameState.CHOOSE_SRC: - # move between source pieces - cur_src = self._get_sources()[self._src_idx] - - if key == Button.DIR_D or key == Button.DIR_R: - self._src_idx += 1 - if self._src_idx >= len(self._all_moves.keys()): - self._src_idx = 0 - elif key == Button.DIR_U or key == Button.DIR_L: - self._src_idx -= 1 - if self._src_idx < 0: - self._src_idx = len(list(self._all_moves)) - 1 - - # back out to main menu - elif key == Button.BTN_A: - self._state = GameState.MAIN_MENU - - # move to destination picker - elif key == Button.BTN_B: - self._dst_idx = 0 - self._state = GameState.CHOOSE_DST - - # handle user input when selecting dest piece - elif self._state == GameState.CHOOSE_DST: - # move between dest squares for the given source - if key == Button.DIR_D or key == Button.DIR_R: - self._dst_idx += 1 - if self._dst_idx >= len(self._all_moves[src]): - self._dst_idx = 0 - elif key == Button.DIR_U or key == Button.DIR_L: - self._dst_idx -= 1 - if self._dst_idx < 0: - self._dst_idx = len(self._all_moves[src]) - 1 - - # back out to choose a different source piece - elif key == Button.BTN_A: - self._dst_idx = 0 - self._state = GameState.CHOOSE_SRC - - # make the move - elif key == Button.BTN_B: - src = self._get_sources()[self._src_idx] - dst = self._get_dests()[self._dst_idx] - self._make_move(src + dst) - self._state = GameState.THINKING - - # handle user input on game over - else: - if key == Button.BTN_A or key == Button.BTN_B: - self._state = GameState.MAIN_MENU diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2c90e37 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,19 @@ +Adafruit-Blinka==8.10.0 +adafruit-circuitpython-busdevice==5.2.3 +adafruit-circuitpython-framebuf==1.5.0 +adafruit-circuitpython-requests==1.12.11 +adafruit-circuitpython-ssd1306==2.12.12 +adafruit-circuitpython-typing==1.8.3 +Adafruit-PlatformDetect==3.38.0 +Adafruit-PureIO==1.1.9 +asttokens==2.2.1 +colorama==0.4.6 +executing==1.2.0 +icecream==2.1.3 +pyftdi==0.54.0 +Pygments==2.13.0 +pyserial==3.5 +pyusb==1.2.1 +RPi.GPIO==0.7.1 +six==1.16.0 +typing_extensions==4.4.0