From 39a3e33a06731ce6847b10a7e77d754ef991ed87 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Sun, 24 Apr 2022 15:43:34 -0500 Subject: [PATCH] ability to create new games as white or black --- .gitignore | 1 + plugin/chess/__init__.py | 75 +++++++++++++++++++++++++++++++++++++--- plugin/chess/draw.py | 17 ++++++--- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index c18dd8d..dff4bd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__/ +data/ diff --git a/plugin/chess/__init__.py b/plugin/chess/__init__.py index dbb7812..21ddb6f 100644 --- a/plugin/chess/__init__.py +++ b/plugin/chess/__init__.py @@ -1,20 +1,36 @@ -from cinput import ControlInput, Button +from os import path from enum import Enum, auto +import re +import itertools +from cinput import ControlInput, Button from graphics import Graphics from .draw import Draw -from .sunfish import initial +from . import sunfish class GameState(Enum): MAIN_MENU = auto() + PLAYING = auto() THINKING = auto() CHOOSE_ROW = auto() CHOOSE_COL = auto() GAME_OVER = auto() +SAVE_FILE = path.join("data", "chess_state.fen") + def execute(cinput: ControlInput, graphics: Graphics, _): graphics.clear() draw = Draw(graphics) - draw.draw_board(initial) + pos: sunfish.Position + + if path.exists(SAVE_FILE): + with open(SAVE_FILE, "r") as fen: + fenstr = fen.read() + pos = parseFEN(fenstr) + else: + pos = sunfish.Position( + sunfish.initial, 0, (True,True), (True,True), 0, 0) + + draw.draw_board(pos.board) state = GameState.MAIN_MENU menu_index = 0 @@ -22,6 +38,8 @@ def execute(cinput: ControlInput, graphics: Graphics, _): while True: if state == GameState.MAIN_MENU: draw.draw_menu(menu_index) + elif state == GameState.PLAYING: + draw.draw_state() key = cinput.get_one_shot() if state == GameState.MAIN_MENU: @@ -31,5 +49,52 @@ def execute(cinput: ControlInput, graphics: Graphics, _): menu_index = 0 elif key == Button.DIR_D: menu_index += 1 - if menu_index > 2: - menu_index = 2 + if menu_index > 3: + menu_index = 3 + elif key == Button.BTN_B: + if menu_index == 0: + state = GameState.PLAYING + elif menu_index == 1: + with open(SAVE_FILE, "w") as fen: + fen.write(renderFEN(pos)) + return + elif menu_index == 2 or menu_index == 3: + pos = sunfish.Position( + sunfish.initial, 0, (True,True), (True,True), 0, 0) + if menu_index == 3: + pos = pos.rotate() + draw.draw_board(pos.board) + state = GameState.PLAYING + + elif state == GameState.PLAYING: + if key == Button.BTN_A: + state = GameState.MAIN_MENU + +def get_color(pos): + return 1 if pos.board.startswith('\n') else 0 + +def parseFEN(fen): + """ Parses a string in Forsyth-Edwards Notation into a Position """ + board, color, castling, enpas, _, _ = fen.split() + board = re.sub(r'\d', (lambda m: '.'*int(m.group(0))), board) + board = list(21*' ' + ' '.join(board.split('/')) + 21*' ') + board[9::10] = ['\n']*12 + board = ''.join(board) + wc = ('Q' in castling, 'K' in castling) + bc = ('k' in castling, 'q' in castling) + ep = sunfish.parse(enpas) if enpas != '-' else 0 + score = sum(sunfish.pst[p][i] for i,p in enumerate(board) if p.isupper()) + score -= sum(sunfish.pst[p.upper()][119-i] for i,p in enumerate(board) if p.islower()) + pos = sunfish.Position(board, score, wc, bc, ep, 0) + return pos if color == 'w' else pos.rotate() + +def renderFEN(pos, half_move_clock=0, full_move_clock=1): + color = 'wb'[get_color(pos)] + if get_color(pos) == 1: + pos = pos.rotate() + board = '/'.join(pos.board.split()) + board = re.sub(r'\.+', (lambda m: str(len(m.group(0)))), board) + castling = ''.join(itertools.compress('KQkq', pos.wc[::-1]+pos.bc)) or '-' + ep = sunfish.render(pos.ep) if not pos.board[pos.ep].isspace() else '-' + clock = '{} {}'.format(half_move_clock, full_move_clock) + return ' '.join((board, color, castling, ep, clock)) diff --git a/plugin/chess/draw.py b/plugin/chess/draw.py index 70766a6..80dc862 100644 --- a/plugin/chess/draw.py +++ b/plugin/chess/draw.py @@ -52,9 +52,10 @@ class Draw: } MENU = [ + "Play", + "Quit", "New (W)", - "New (B)", - "Quit"] + "New (B)"] def __init__(self, graphics: Graphics): self._graphics = graphics @@ -78,11 +79,12 @@ class Draw: self.BOARD_SIZE, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0) def draw_board(self, board: str): + ic(board) + is_black = board.startswith('\n') self._graphics.fill_rect(0, 0, self.BOARD_SIZE, self.BOARD_SIZE, 0) nb = "".join(board.split()) c = True for row in range(8): - c = not c for col in range(8): if c: x = col * self.SQUARE_SIZE @@ -90,9 +92,10 @@ class Draw: 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) - + self._draw_piece( + self.PIECES[p.lower()], p.isupper() if not is_black else p.islower(), col, row, c) c = not c + c = not c self._graphics.show() def draw_menu(self, menu_index: int): @@ -102,3 +105,7 @@ class Draw: marker = "> " if i == menu_index else " " self._graphics.text(marker + self.MENU[i], 12, i + 2, 1) self._graphics.show() + + def draw_state(self): + self._clear_info() + self._graphics.show()