PySimpleGUI/Chess/Demo_Chess_Board.py

174 lines
6.6 KiB
Python

import PySimpleGUI as sg
import os
import io
from PIL import Image, ImageDraw, ImageTk, ImageFont
import sys
from random import randint as rand
import chess
import chess.pgn
import copy
button_names = ('close', 'cookbook', 'cpu', 'github', 'pysimplegui', 'run', 'storage', 'timer')
# path to the chess pieces
CHESS_PATH = '.'
BLANK = 0 # piece names
PAWNB = 1
KNIGHTB = 2
BISHOPB = 3
ROOKB = 4
KINGB = 5
QUEENB = 6
PAWNW = 7
KNIGHTW = 8
BISHOPW = 9
ROOKW = 10
KINGW = 11
QUEENW = 12
initial_board = [[ROOKB, KNIGHTB, BISHOPB, KINGB, QUEENB, BISHOPB, KNIGHTB, ROOKB ],
[PAWNB,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[PAWNW,]*8,
[ROOKW, KNIGHTW, BISHOPW, KINGW, QUEENW, BISHOPW, KNIGHTW, ROOKW]]
blank = os.path.join(CHESS_PATH, 'blank.png')
bishopB = os.path.join(CHESS_PATH, 'bishopb.png')
bishopW = os.path.join(CHESS_PATH, 'bishopw.png')
pawnB = os.path.join(CHESS_PATH, 'pawnb.png')
pawnW = os.path.join(CHESS_PATH, 'pawnw.png')
knightB = os.path.join(CHESS_PATH, 'knightb.png')
knightW = os.path.join(CHESS_PATH, 'knightw.png')
rookB = os.path.join(CHESS_PATH, 'rookb.png')
rookW = os.path.join(CHESS_PATH, 'rookw.png')
queenB = os.path.join(CHESS_PATH, 'queenB.png')
queenW = os.path.join(CHESS_PATH, 'queenW.png')
kingB = os.path.join(CHESS_PATH, 'kingb.png')
kingW = os.path.join(CHESS_PATH, 'kingw.png')
images = {BISHOPB: bishopB, BISHOPW: bishopW, PAWNB: pawnB, PAWNW: pawnW, KNIGHTB: knightB, KNIGHTW: knightW,
ROOKB: rookB, ROOKW: rookW, KINGB: kingB, KINGW: kingW, QUEENB: queenB, QUEENW: queenW, BLANK: blank}
def get_a_move():
pgn = open('C:/Python/PycharmProjects/GooeyGUI/Chess/game.pgn')
first_game = chess.pgn.read_game(pgn)
for move in first_game.main_line():
print(move)
yield move
def open_pgn_file(filename):
pgn = open(filename)
first_game = chess.pgn.read_game(pgn)
moves = [move for move in first_game.main_line()]
return moves
def render_square(image, key, location):
if (location[0] + location[1]) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
return sg.RButton('', image_filename=image, size=(1, 1), button_color=('white', color), pad=(0, 0), key=key)
def redraw_board(window, board):
for i in range(8):
for j in range(8):
if (i+j) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
piece_image = images[board[i][j]]
elem = window.FindElement(key=(i,j))
elem.Update(button_color = ('white', color),
image_filename=piece_image,)
def PlayGame():
menu_def = [['&File', ['&Open PGN File', 'E&xit' ]],
['&Help', '&About...'],]
sg.SetOptions(auto_size_buttons=True, margins=(0,0))
# create initial board setup
board = copy.deepcopy(initial_board)
# the main board display layout
board_layout = [[sg.T(' ')] + [sg.T(f'{a}', pad=((23,27),0), font='Any 13') for a in 'abcdefgh']]
# loop though board and create buttons with images
for i in range(8):
row = [sg.T(str(8-i)+' ', font='Any 13')]
for j in range(8):
piece_image = images[board[i][j]]
row.append(render_square(piece_image, key=(i,j), location=(i,j)))
row.append(sg.T(str(8-i)+' ', font='Any 13'))
board_layout.append(row)
# add the labels across bottom of board
board_layout.append([sg.T(' ')] + [sg.T(f'{a}', pad=((23,27),0), font='Any 13') for a in 'abcdefgh'])
# setup the controls on the right side of screen
openings = ('Any', 'Defense', 'Attack', 'Trap', 'Gambit','Counter', 'Sicillian', 'English','French', 'Queen\'s openings', 'King\'s Openings','Indian Openings')
board_controls = [[sg.RButton('New Game', key='Open PGN File'), sg.RButton('Draw')],
[sg.RButton('Resign Game'), sg.RButton('Set FEN')],
[sg.RButton('Player Odds'),sg.RButton('Training') ],
[sg.Drop(openings),sg.Text('Opening/Style')],
[sg.CBox('Play a White', key='_white_')],
[sg.Text('Move List')],
[sg.Multiline([], do_not_clear=True, autoscroll=True, size=(15,10),key='_movelist_')],]
# layouts for the tabs
controls_layout = [[sg.Text('Performance Parameters', font='_ 20')],
[sg.T('Put stuff like AI engine tuning parms on this tab')]]
statistics_layout = [[sg.Text('Statistics', font=('_ 20'))],
[sg.T('Game statistics go here?')]]
board_tab = [[sg.Column(board_layout)]]
# the main window layout
layout = [[sg.Menu(menu_def, tearoff=False)],
[sg.TabGroup([[sg.Tab('Board',board_tab),
sg.Tab('Controls', controls_layout),
sg.Tab('Statistics', statistics_layout)]]),
sg.Column(board_controls)],
[sg.Text('Click anywhere on board for next move', font='_ 14')]]
window = sg.Window('Chess',
default_button_element_size=(12,1),
auto_size_buttons=False,
icon='kingb.ico').Layout(layout)
# ---===--- Loop taking in user input --- #
i = 0
moves = None
while True:
button, value = window.Read()
if button in (None, 'Exit'):
break
if button == 'Open PGN File':
filename = sg.PopupGetFile('', no_window=True)
if filename is not None:
moves = open_pgn_file(filename)
i = 0
board = copy.deepcopy(initial_board)
window.FindElement('_movelist_').Update(value='')
if button == 'About...':
sg.Popup('Powerd by Engine Kibitz Chess Engine')
if type(button) is tuple and moves is not None and i < len(moves):
move = moves[i] # get the current move
window.FindElement('_movelist_').Update(value='{} {}\n'.format(i+1, str(move)), append=True)
move_from = move.from_square # parse the move-from and move-to squares
move_to = move.to_square
row = move_from // 8
col = move_from % 8
piece = board[row][col] # get the move-from piece
board[row][col] = BLANK # place blank where piece was
row = move_to // 8 # compute move-to square
col = move_to % 8
board[row][col] = piece # place piece in the move-to square
redraw_board(window, board)
i += 1
PlayGame()