0

我正在Python 3.6.3使用PyQt5 5.9.1(GUI 框架)和python-chess 0.21.1(国际象棋库)在Windows 10. 我想获取在 SVG 棋盘(由 提供python-chess)上单击的棋子的值,以便我可以将该棋子移动到另一个方格。

在第一次鼠标左键单击并获取该块后,我想从用户那里获得第二次鼠标左键单击并获取用户单击的方块。然后我的国际象棋 GUI 必须将棋子从起始方格移动到目标方格。

所以,这是我到目前为止的完整工作代码。非常欢迎任何提示或实际代码添加。

#! /usr/bin/env python3

import chess
import chess.svg

from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Chess Titan")
        self.setGeometry(300, 300, 800, 800)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 600, 600)

        self.chessboard = chess.Board()

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            ## How to get the clicked SVG chess piece?

            # Envoke the paint event.
            self.update()

    @pyqtSlot(QWidget)
    def paintEvent(self, event):
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)


if __name__ == "__main__":
    chessTitan = QApplication([])
    window = MainWindow()
    window.show()
    chessTitan.exec()
4

3 回答 3

2

如果棋盘的大小已知,您可以根据 marginwidth 和 squaresize 从 event.pos() resp.event.x() 和 event.y() 中找到鼠标点击的坐标,参见 chess.svg.py line 129 ff。

编辑 11 月 25 日: event.pos()在此示例中,在 MainWindow 坐标中,要找到棋盘上的坐标,所有必须从左上角计算,由self.svgX和表示self.svgY

import chess
import chess.svg
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Chess Titan")
        self.setGeometry(300, 300, 800, 800)

        self.widgetSvg = QSvgWidget(parent=self)
        self.svgX = 50                          # top left x-pos of chessboard
        self.svgY = 50                          # top left y-pos of chessboard
        self.cbSize = 600                       # size of chessboard
        self.widgetSvg.setGeometry(self.svgX,self.svgY, self.cbSize, self.cbSize)
        self.coordinates = True
        # see chess.svg.py line 129
        self.margin = 0.05*self.cbSize if self.coordinates == True else 0
        self.squareSize  = (self.cbSize - 2 * self.margin) / 8.0
        self.chessboard = chess.Board()
        self.pieceToMove = [None, None]

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        if self.svgX < event.x() <= self.svgX + self.cbSize and self.svgY < event.y() <= self.svgY + self.cbSize:   # mouse on chessboard
            if event.buttons() == Qt.LeftButton:
                # if the click is on chessBoard only
                if self.svgX + self.margin < event.x() < self.svgX + self.cbSize - self.margin and self.svgY + self.margin < event.y() < self.svgY + self.cbSize - self.margin:
                    file = int((event.x() - (self.svgX + self.margin))/self.squareSize)             
                    rank = 7 - int((event.y() - (self.svgY + self.margin))/self.squareSize) 
                    square = chess.square(file, rank)                       # chess.sqare.mirror() if white is on top
                    piece = self.chessboard.piece_at(square)
                    coordinates = '{}{}'.format(chr(file + 97), str(rank +1))       
                    if self.pieceToMove[0] is not None:
                        move = chess.Move.from_uci('{}{}'.format(self.pieceToMove[1], coordinates))
                        self.chessboard.push(move)
                        print(self.chessboard.fen())
                        piece = None
                        coordinates= None
                    self.pieceToMove = [piece, coordinates]                                           
                else:
                    print('coordinates clicked')
                # Envoke the paint event.
                self.update()
        else:
            QWidget.mousePressEvent(self, event)

    @pyqtSlot(QWidget)
    def paintEvent(self, event):
        self.chessboardSvg = chess.svg.board(self.chessboard, size = self.cbSize, coordinates = self.coordinates).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)


if __name__ == "__main__":
    chessTitan = QApplication([])
    window = MainWindow()
    window.show()
    chessTitan.exec()

交替移动白色和黑色块,如果相同的颜色移动两次,它们会改变颜色。

于 2017-11-16T12:06:19.527 回答
2

下面是一个功能齐全的国际象棋 GUI 的代码和代码Python,它内置了合法的移动检测,因此棋子移动的行为符合国际象棋规则。PyQt5python-chess

#! /usr/bin/env python

"""
This module is the execution point of the chess GUI application.
"""

import sys

import chess

from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget


class MainWindow(QWidget):
    """
    Create a surface for the chessboard.
    """
    def __init__(self):
        """
        Initialize the chessboard.
        """
        super().__init__()

        self.setWindowTitle("Chess GUI")
        self.setGeometry(300, 300, 800, 800)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 600, 600)

        self.boardSize = min(self.widgetSvg.width(),
                             self.widgetSvg.height())
        self.coordinates = True
        self.margin = 0.05 * self.boardSize if self.coordinates else 0
        self.squareSize = (self.boardSize - 2 * self.margin) / 8.0
        self.pieceToMove = [None, None]

        self.board = chess.Board()
        self.drawBoard()

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        """
        Handle left mouse clicks and enable moving chess pieces by
        clicking on a chess piece and then the target square.

        Moves must be made according to the rules of chess because
        illegal moves are suppressed.
        """
        if event.x() <= self.boardSize and event.y() <= self.boardSize:
            if event.buttons() == Qt.LeftButton:
                if self.margin < event.x() < self.boardSize - self.margin and self.margin < event.y() < self.boardSize - self.margin:
                    file = int((event.x() - self.margin) / self.squareSize)
                    rank = 7 - int((event.y() - self.margin) / self.squareSize)
                    square = chess.square(file, rank)
                    piece = self.board.piece_at(square)
                    coordinates = "{}{}".format(chr(file + 97), str(rank + 1))
                    if self.pieceToMove[0] is not None:
                        move = chess.Move.from_uci("{}{}".format(self.pieceToMove[1], coordinates))
                        if move in self.board.legal_moves:
                            self.board.push(move)
                        piece = None
                        coordinates = None
                    self.pieceToMove = [piece, coordinates]
                    self.drawBoard()

    def drawBoard(self):
        """
        Draw a chessboard with the starting position and then redraw
        it for every new move.
        """
        self.boardSvg = self.board._repr_svg_().encode("UTF-8")
        self.drawBoardSvg = self.widgetSvg.load(self.boardSvg)

        return self.drawBoardSvg


if __name__ == "__main__":
    chessGui = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(chessGui.exec_())
于 2017-11-16T19:00:31.490 回答
0

a_manthey_67 和 Boštjan Mejak,我结合了您的两个解决方案的功能: https ://github.com/vtad4f/chess-ui/blob/master/board.py

完整版将 AI 播放器与您的棋盘 UI 集成:

于 2019-09-08T18:28:17.150 回答