'''
The use of the chessboard requires a mouse or a mousepad. A piece is moved like that:
* :kbd:`mouse-left-press`: begin move of selected piece
* :kbd:`mouse-left-release`: end move
For training purposes, several helpers are available.
Warn of Danger
===================
The *Warn of Danger* is enabled by the ``Game/Warn of Danger`` action.
It runs as follows:
#. assign material scores to each attack and reply for every ply
#. create a combined list of attacks and replies (cheapest first)
#. create a list of total scores for every ply
Effect on other pieces like discovered check are not considered. An example:
|WarnOfDanger|
Obviously, the rook at ``b8`` is danger.
Move Options
===================
The *Move Options* are enabled by the ``Game/Show Move Options`` action.
By pressing the left mouse button at ``b8``, we see:
|MoveOptions|
It seem that ``b8-d8`` is the best move, but it is dubious ...
.. |WarnOfDanger| image:: warnOfDanger.png
:width: 600
:alt: Warn of Danger
.. |MoveOptions| image:: moveOptions.png
:width: 600
:alt: Move Options
'''
from typing import Optional
import sys, os, os.path
import copy
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import MzChess
if MzChess.useQt5():
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtSvg import QGraphicsSvgItem
else:
from PyQt6 import QtWidgets, QtGui, QtCore
from PyQt6.QtSvgWidgets import QGraphicsSvgItem
import chess, chess.pgn
import chessengine
from specialDialogs import ButtonLine
import warnOfDanger
def showStatus(board):
print('fen = {}'.format(board.fen()))
for row in range(8):
for col in range(8):
chessSquare = chess.square(col, row)
piece = board.piece_at(chessSquare)
if piece is not None:
print(' square = {}, name = {}, symbol = {}'.format(
chessSquare, chess.square_name(chessSquare), piece.symbol()))
for n, move in enumerate(board.move_stack):
print('{}. {}'.format(n, move.uci()))
[docs]class QBoardViewClass(QtWidgets.QGraphicsView):
'''The *chessboard* is based on Qt's QGraphicsView.
'''
def __init__(self, parent = None) -> None:
super(QBoardViewClass, self).__init__(parent)
self.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.border = 0
self.game = Game()
self.setMouseTracking(True)
self.setScene(self.game)
self.game.installEventFilter(self.game)
[docs] def setup(self, notifyNewGameNodeSignal : Optional[QtCore.pyqtSignal] = None,
notifyGameNodeSelectedSignal : Optional[QtCore.pyqtSignal] = None,
materialLabel : Optional[QtWidgets.QLabel] = None,
squareLabel : Optional[QtWidgets.QLabel] = None,
turnFrame : Optional[QtWidgets.QFrame] = None,
hintLabel : Optional[QtWidgets.QLabel] = None,
flipped : bool = False) -> None:
'''Set up of the game editor
:param notifyNewGameNodeSignal: signal to be emitted if a move is added
:param notifyGameNodeSelectedSignal: signal to be emitted if a game node is selected
:param materialLabel: label showing the material budget
:param squareLabel: label showing the square under mouse pointer (usually in the status bar)
:param turnFrame: frame showing the color of player making the move
:param hintLabel: label showing the engine's hints and scores (usually in the status bar)
:param flipped: if True, the square *a1* is on top
'''
self.notifyGameNodeSelectedSignal = notifyGameNodeSelectedSignal
self.game.setup(notifyNewGameNodeSignal = notifyNewGameNodeSignal, materialLabel = materialLabel, squareLabel = squareLabel,
hintLabel = hintLabel, turnFrame =turnFrame, flipped = flipped)
self._configureScene()
self.game.draw_board()
[docs] def setHint(self, enableHint : int = 0, enableScore : bool = False,
engine : Optional[chessengine.ChessEngine] = None) -> None:
'''Controls the usage of the hint label
:param enableHint: If True, the *hintLabel* shows the *engine* hint
:param enableScore: If True, the *hintLabel* shows the *engine* scores
:param engine: engine to be used (required, if *enableHint or enableScore*
'''
self.game.setHint(enableHint, enableScore, engine = engine)
[docs] def setFlipped(self, enable : bool) -> None:
'''Controls the board orientation
:param enable: if True, the square *a1* is on top
'''
self.game.setFlipped(enable)
[docs] def setDrawOptions(self, enable : bool) -> None:
'''Controls the draw options. Draw options are shown when :kbd:`mouse-left-press` on a piece
:param enable: if True, the draw options are enabled
'''
self.game.setDrawOptions(enable)
[docs] def setWarnOfDanger(self, enable : bool) -> None:
'''Controls the warn of danger, i.e. shows attacked pieces
:param enable: if True, the warn of danger is enabled
'''
self.game.setWarnOfDanger(enable)
def _fen(self) -> str:
return self.game.fen()
[docs] def set_fen(self, fen : str) -> None:
'''Configures the *chessboard*
:param fen: position in `Forsyth-Edwards` Notation
.. _Forsyth-Edwards: https://github.com/fsmosca/PGN-Standard
'''
self.game.set_fen(fen)
[docs] def setGameNode(self, gameNode : chess.pgn.GameNode) -> None:
'''Sets the game node displayed by the *chessBoard*
:param gameNode : game node to be displayed
'''
self.game.setGameNode(gameNode)
[docs] def nextMove(self) -> None:
'''Go 1 move forward, if possible
'''
return self.game.nextMove()
[docs] def previousMove(self) -> None:
'''Go 1 move backward, if possible
'''
return self.game.previousMove()
def _configureScene(self):
self.fitInView(QtCore.QRectF(0, 0, 8 * Game.pieceSize, 8 * Game.pieceSize), mode = QtCore.Qt.AspectRatioMode.KeepAspectRatio)
# self.setScene(self.game)
[docs] def resizeEvent(self, ev) -> None:
# print('oldSize = {}, size = {}'.format(ev.oldSize(), ev.size()))
QtWidgets.QGraphicsView.resizeEvent(self, ev)
self._configureScene()
if self.game.pressedPiece is None:
self.game.draw_board()
[docs] @QtCore.pyqtSlot(QtGui.QKeyEvent)
def keyPressEvent(self, ev):
if ev.key() == QtCore.Qt.Key.Key_Up:
newGameNode = self.game.gameNode.parent
else:
newGameNode = self.game.gameNode.next()
if newGameNode is not None:
self.notifyGameNodeSelectedSignal.emit(newGameNode)
[docs]class Piece(QGraphicsSvgItem):
'''Internal class
'''
piecesDirectory = os.path.join(os.path.dirname(os.path.abspath(__file__)), ':/pieces/')
colorChars = ('black', 'white')
def __init__(self, symbolName : str, size : int, parent = None) -> None:
'''
symbol values (according to PGN spec)
p,P = white pawn, black ~
n,N = white knight, black ~
b,B = white bishop, black ~
r,R = white rook, black ~
q,Q = white queen, black ~
k,K = white king, black ~
'''
self.llPiece = chess.Piece.from_symbol(symbolName)
fileDirectory = os.path.dirname(os.path.abspath(__file__))
svgPath = os.path.join(fileDirectory , 'pieces',
'{}-{}.svg'.format(self.colorChars[self.llPiece.color], chess.piece_name(self.llPiece.piece_type)))
super(Piece, self).__init__(svgPath, parent)
self.setFlags(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable | QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
bwidth = self.boundingRect().width()
self.setScale(size/bwidth)
# self.setAcceptHoverEvents(True)
self.setCacheMode(QtWidgets.QGraphicsItem.CacheMode.NoCache)
self.setZValue(1)
[docs]class Game(QtWidgets.QGraphicsScene):
'''Internal class
'''
whiteSquareBrush = QtGui.QBrush( QtCore.Qt.GlobalColor.white, QtCore.Qt.BrushStyle.SolidPattern)
blackSquareBrush = QtGui.QBrush( QtCore.Qt.GlobalColor.gray, QtCore.Qt.BrushStyle.SolidPattern)
goodSquareBrush = QtGui.QBrush( QtCore.Qt.GlobalColor.green, QtCore.Qt.BrushStyle.SolidPattern)
intermediateSquareBrush = QtGui.QBrush( QtCore.Qt.GlobalColor.yellow, QtCore.Qt.BrushStyle.SolidPattern)
badSquareBrush = QtGui.QBrush( QtCore.Qt.GlobalColor.red, QtCore.Qt.BrushStyle.SolidPattern)
requestHint = QtCore.pyqtSignal(str)
pieceSize = 45
leipzigEncodeDict = {
'P' : 'p', 'N' : 'n', 'B' : 'b', 'R' : 'r', 'Q' : 'q',
'p' : 'o', 'n' : 'm', 'b' : 'v', 'r' : 't', 'q' : 'w'
}
chessFigures = { '♕' : chess.QUEEN, '♖' : chess.ROOK, '♗' : chess.BISHOP, '♘' : chess.KNIGHT}
chessFiguresDescription = { '♕' : 'Queen', '♖' : 'Rook', '♗' : 'Bishop', '♘' : 'Knight'}
encodePiece = lambda piece_type, color : Game.leipzigEncodeDict[chess.Piece(piece_type, color).symbol()]
def __init__(self, parent = None) -> None:
super(Game, self).__init__(parent)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.flushHint)
self.requestHint.connect(self.hintRequested)
self.hintDelay = 100
self.promotePawn = ButtonLine(self.chessFigures, hintDict = self.chessFiguresDescription, title = 'Promotion', pointSize = 30)
self.gameNode = chess.pgn.Game()
self.boardElementGroup = None
self.drawOptionsGroup = list()
self.boardPieces = list()
self.flipped = False
self.engine = None
self.hint = False
self.score = False
self.drawOptions = False
self.warnOfDanger = False
self.materialLabel = None
self.squareLabel = None
self.turnFrame = None
self.hintLabel = None
def needHint(self):
board = self.gameNode.board()
return self.hint & (int(not board.turn) + 1) > 0
def setup(self, notifyNewGameNodeSignal : Optional[QtCore.pyqtSignal] = None,
materialLabel : Optional[QtWidgets.QLabel] = None,
squareLabel : Optional[QtWidgets.QLabel] = None,
turnFrame : Optional[QtWidgets.QFrame] = None,
hintLabel : Optional[QtWidgets.QLabel] = None,
flipped : bool = False,
gameNode : Optional[chess.pgn.GameNode]= None) -> None:
self.notifyNewGameNodeSignal = notifyNewGameNodeSignal
self.materialLabel = materialLabel
self.squareLabel = squareLabel
self.turnFrame = turnFrame
self.hintLabel = hintLabel
if gameNode is not None:
self.gameNode = gameNode
self.boardElementGroup = None
self.boardPieces = list()
self.flipped = flipped
board = self.gameNode.board()
self.showMaterial(board)
self.showTurn(board)
self.pressedPiece = None
def boardRect(self) -> QtCore.QRectF:
return QtCore.QRectF(0, 0, 8 * self.pieceSize, 8 * self.pieceSize)
def setDrawOptions(self, enable : bool) -> None:
self.drawOptions = enable
def setWarnOfDanger(self, enable : bool) -> None:
if enable != self.warnOfDanger:
self.warnOfDanger = enable
if enable:
self.draw_warnOfDanger()
else:
self.remove_warnOfDanger()
def fen(self):
return self.gameNode.board().fen()
def setGameNode(self, gameNode : bool) -> None:
if gameNode is None:
return
self.gameNode = gameNode
self.draw_board()
board = self.gameNode.board()
self.showMaterial(board)
self.isGameOver = False
self.showTurn(board)
if self.needHint() or self.score:
self.requestHint.emit(self.fen())
self.draw_warnOfDanger()
# -------------------------------------------------------
def nextMove(self) -> None:
newGameNode = self.gameNode.next()
if newGameNode is None:
return self.gameNode
self.gameNode = newGameNode
self.draw_board()
board = self.gameNode.board()
self.showTurn(board)
if self.needHint() or self.score:
self.requestHint.emit(self.fen())
self.showMaterial(board)
self.showTurn(board)
self.draw_warnOfDanger()
return newGameNode
def previousMove(self) -> None:
newGameNode = self.gameNode.parent
if newGameNode is None:
return self.gameNode
self.gameNode = newGameNode
self.draw_board()
board = self.gameNode.board()
self.showTurn(board)
if self.needHint() or self.score:
self.requestHint.emit(self.fen())
self.showMaterial(board)
self.showTurn(board)
self.draw_warnOfDanger()
return newGameNode
# -------------------------------------------------------
def showTurn(self, board : chess.Board) -> None:
if self.turnFrame is None:
return
self.gameIsOver = board.is_game_over()
game = self.gameNode.game()
border = ' border-color: black; border-style: solid; border-width: 1px;'
if self.gameIsOver:
game.headers['Result'] = board.result()
if board.is_checkmate():
self.turnFrame.setStyleSheet('background-color: red;' + border)
else:
self.turnFrame.setStyleSheet('background-color: yellow;' + border)
elif game.headers['Result'] != '*' and self.gameNode.is_mainline() and self.gameNode.is_end():
if game.headers['Result'] == '1/2-1/2':
self.turnFrame.setStyleSheet('background-color: yellow;' + border)
else:
self.turnFrame.setStyleSheet('background-color: red;' + border)
elif board.turn:
self.turnFrame.setStyleSheet('background-color: white;' + border)
else:
self.turnFrame.setStyleSheet('background-color: black;')
def showMaterial(self, board : chess.Board) -> None:
if self.materialLabel is None:
return
pieceMap = board.piece_map()
whiteCountList = 7 * [0]
blackCountList = 7 * [0]
for piece in list(pieceMap.values()):
if piece.color == chess.WHITE:
whiteCountList[piece.piece_type] += 1
else:
blackCountList[piece.piece_type] += 1
piece_text =''
for piece_type in range(5, 0,-1):
delta = whiteCountList[piece_type] - blackCountList[piece_type]
if delta == 0:
continue
if delta > 0:
piece_text += delta * Game.encodePiece(piece_type, chess.WHITE)
else:
piece_text += abs(delta) * Game.encodePiece(piece_type, chess.BLACK)
self.materialLabel.setText(piece_text)
# -------------------------------------------------------
def draw_board(self, flipped : Optional[bool] = None) -> None:
self.clear()
elementWidth = self.pieceSize
for row in range(8):
for col in range(8):
rect = QtWidgets.QGraphicsRectItem( row * elementWidth, col * elementWidth, elementWidth, elementWidth)
if row % 2 == col % 2:
rect.setBrush( self.whiteSquareBrush )
else:
rect.setBrush( self.blackSquareBrush )
rect.setCacheMode(QtWidgets.QGraphicsItem.CacheMode.NoCache)
rect.setZValue(0)
self.addItem(rect)
if flipped is not None:
self.flipped = flipped
self.draw_pieces()
def draw_pieces(self) -> None:
symbolWidth = self.pieceSize
for row in range(8):
for col in range(8):
if self.flipped:
chessSquare = 63 - chess.square(col, row)
else:
chessSquare = chess.square(col, row)
piece = self.gameNode.board().piece_at(chessSquare)
if piece is not None:
# print('draw_pieces: square = {}, name = {}'.format(chessSquare, chess.square_name(chessSquare)))
# print('draw_pieces: piece = {}, scenePos = {}'.format(piece.symbol(), self.getScenePos(chessSquare)))
bPiece = Piece(piece.symbol(), size = symbolWidth)
bPiece.setPos(self.getScenePos(chessSquare))
# bPiece.setScale(symbolWidth/bPiece.boundingRect().width())
self.addItem(bPiece)
self.update()
def draw_drawOptions(self) -> None:
if len(self.legal_targets) == 0 or not self.drawOptions:
return
elementSize = QtCore.QSizeF(self.pieceSize, self.pieceSize)
board = self.gameNode.board()
self.drawOptionsGroup = len(self.legal_targets)*[None]
for n, chessSquare in enumerate(self.legal_targets):
self.drawOptionsGroup[n] = QtWidgets.QGraphicsRectItem(
QtCore.QRectF(self.getScenePos(chessSquare), elementSize))
self.drawOptionsGroup[n].setCacheMode(QtWidgets.QGraphicsItem.CacheMode.NoCache)
if board.is_attacked_by(not board.turn, chessSquare):
self.drawOptionsGroup[n].setBrush(self.badSquareBrush)
else:
self.drawOptionsGroup[n].setBrush(self.goodSquareBrush)
self.drawOptionsGroup[n].setZValue(0.8)
self.addItem(self.drawOptionsGroup[n])
self.update()
def remove_drawOptions(self) -> None:
try:
for rect in self.drawOptionsGroup:
self.removeItem(rect)
self.update()
except:
pass
self.drawOptionsGroup = list()
def draw_warnOfDanger(self) -> None:
if not self.warnOfDanger:
return
elementSize = QtCore.QSizeF(self.pieceSize, self.pieceSize)
square2ScoreDict = warnOfDanger.warnOfDanger(self.gameNode)
if square2ScoreDict is None or len(square2ScoreDict) == 0:
return
self.warnOfDangerGroup = len(square2ScoreDict)*[None]
for n, chessSquare in enumerate(square2ScoreDict):
score = square2ScoreDict[chessSquare]
self.warnOfDangerGroup[n] = QtWidgets.QGraphicsRectItem(
QtCore.QRectF(self.getScenePos(chessSquare), elementSize))
self.warnOfDangerGroup[n].setCacheMode(QtWidgets.QGraphicsItem.CacheMode.NoCache)
if score > 0:
self.warnOfDangerGroup[n].setBrush(self.badSquareBrush)
elif score == 0:
self.warnOfDangerGroup[n].setBrush(self.intermediateSquareBrush)
else:
self.warnOfDangerGroup[n].setBrush(self.goodSquareBrush)
self.warnOfDangerGroup[n].setZValue(0.4)
self.addItem(self.warnOfDangerGroup[n])
self.update()
def remove_warnOfDanger(self) -> None:
try:
for rect in self.warnOfDangerGroup:
self.removeItem(rect)
except:
pass
self.warnOfDangerGroup = list()
def getScenePos(self, chessSquare : int, center : bool = False) -> QtCore.QPointF:
if chessSquare < 0 or chessSquare > 63:
return None
if center:
delta = self.pieceSize / 2
else:
delta = 0
if self.flipped:
row = chess.square_rank(chessSquare)
col = 7 - chess.square_file(chessSquare)
else:
row = 7 - chess.square_rank(chessSquare)
col = chess.square_file(chessSquare)
return QtCore.QPointF(col * self.pieceSize + delta, row * self.pieceSize + delta)
# -------------------------------------------------------
def getChessSquareAt(self, scenePos : QtCore.QPointF) -> int:
iPos = scenePos/self.pieceSize
if self.flipped:
id = chess.square(7 - int(iPos.x()), int(iPos.y()))
else:
id = chess.square(int(iPos.x()), 7 - int(iPos.y()))
if id < 0 or id > 63:
return None
return id
# -------------------------------------------------------
def setHint(self, enableHint : int = 0, enableScore : bool = False,
engine : Optional[chessengine.ChessEngine] = None) -> None:
self.engine = engine
if self.engine is not None:
self.hint = enableHint
else:
self.hint = 0
self.score = (self.engine is not None and enableScore)
if self.needHint() or self.score:
self.hintFen = None
self.engine.bestMoveScoreSignal.connect(self.bestMoveScoreAvailable)
self.requestHint.emit(self.fen())
else:
self.hintLabel.setText('-/-')
def setFlipped(self, enable : bool) -> None:
self.flipped = enable
self.setGameNode(self.gameNode)
def hintRequested(self, fen : str) -> None:
if not (self.needHint() or self.score):
return
self.timer.stop()
self.timer.start(self.hintDelay+1)
def flushHint(self) -> None:
fen = self.fen()
if self.hintFen != fen and self.engine is not None and self.engine.uciNewGame(fen):
self.engine.startPlay()
self.hintFen = fen
@QtCore.pyqtSlot(chess.Move, str)
def bestMoveScoreAvailable(self, move, score):
if self.hintLabel is not None:
board = self.gameNode.board()
if self.hint & (int(not board.turn) + 1) > 0:
try:
moveString = board.lan(move)
except:
moveString = '?{}'.format(move.uci())
else:
moveString = '-'
if self.score:
self.hintLabel.setText('{}/{}'.format(moveString, score))
else:
self.hintLabel.setText('{}/-'.format(moveString))
# -------------------------------------------------------
[docs] def mouseDoubleClickEvent(self, mouseEvent):
self.mousePressed = False
# print('==> mouseDoubleClickEvent')
[docs] def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.Type.GraphicsSceneMouseMove:
square = self.getChessSquareAt(event.scenePos())
if square is not None:
self.squareLabel.setText(chess.square_name(square))
else:
self.squareLabel.setText('')
elif event.type() == QtCore.QEvent.Type.GraphicsSceneLeave:
self.squareLabel.setText('')
return QtWidgets.QGraphicsScene.eventFilter(self, source, event)
[docs] def mousePressEvent(self, qGraphicsSceneMouseEvent : QtWidgets.QGraphicsSceneMouseEvent) -> None:
self.mousePressed = True
self.pressedPiece = None
self.remove_warnOfDanger()
self.pressedSquareId = self.getChessSquareAt(qGraphicsSceneMouseEvent.scenePos())
if self.pressedSquareId is not None:
self.pressedPiece = self.itemAt(self.getScenePos(self.pressedSquareId), QtGui.QTransform())
# print('==> mousePressEvent: scene = {} => square = {}'.format(qGraphicsSceneMouseEvent.scenePos(), chess.square_name(self.pressedSquareId)))
if isinstance(self.pressedPiece,QtWidgets.QGraphicsRectItem):
self.pressedPiece = None # empty field hitten
board = self.gameNode.board()
if not self.gameIsOver:
self.pressedSquareId = self.getChessSquareAt(qGraphicsSceneMouseEvent.scenePos())
if self.pressedPiece is not None:
self.pressedPiece = self.itemAt(self.getScenePos(self.pressedSquareId), QtGui.QTransform())
self.legal_targets = list()
for move in list(board.legal_moves):
if move.from_square == self.pressedSquareId:
self.legal_targets.append(move.to_square)
self.attackedPieceDict = dict()
for pieceID in board.attacks(self.pressedSquareId):
actPiece = self.itemAt(self.getScenePos(pieceID), QtGui.QTransform())
if not isinstance(actPiece,QtWidgets.QGraphicsRectItem):
self.attackedPieceDict[pieceID] = actPiece
self.draw_drawOptions()
QtWidgets.QGraphicsScene.mousePressEvent(self, qGraphicsSceneMouseEvent)
[docs] def mouseReleaseEvent(self, qGraphicsSceneMouseEvent : QtWidgets.QGraphicsSceneMouseEvent) -> None:
# print('==> mouseReleaseEvent: mousePressed = {}, scene = {}'.format(self.mousePressed, qGraphicsSceneMouseEvent.scenePos()))
QtWidgets.QGraphicsScene.mouseReleaseEvent(self, qGraphicsSceneMouseEvent)
if self.pressedPiece is None or not self.mousePressed or self.gameIsOver:
if self.pressedPiece is not None:
self.pressedPiece.setPos(self.getScenePos(self.pressedSquareId))
return
self.remove_drawOptions()
releasedSquareId = self.getChessSquareAt(qGraphicsSceneMouseEvent.scenePos())
if releasedSquareId in self.legal_targets:
if releasedSquareId in self.attackedPieceDict:
self.removeItem(self.attackedPieceDict[releasedSquareId])
else:
releasedSquareId = self.pressedSquareId
# print('==> mouseReleaseEvent: square = {}'.format(chess.square_name(releasedSquareId)))
if releasedSquareId != self.pressedSquareId:
oldBoard = self.gameNode.board()
if self.pressedPiece.llPiece.piece_type == chess.PAWN and \
((self.pressedPiece.llPiece.color == chess.WHITE and releasedSquareId > chess.H7) \
or (self.pressedPiece.llPiece.color == chess.BLACK and releasedSquareId < chess.A2)):
self.promotePawn.move(qGraphicsSceneMouseEvent.screenPos())
promotedPieceType = self.promotePawn.exec()
move = chess.Move(self.pressedSquareId, releasedSquareId, promotion = promotedPieceType)
self.removeItem(self.pressedPiece)
promotedPiece = chess.Piece(promotedPieceType, self.pressedPiece.llPiece.color)
pPiece = Piece(promotedPiece.symbol(), self.pieceSize)
pPiece.setPos(self.getScenePos(releasedSquareId))
self.addItem(pPiece)
self.update()
else:
move = chess.Move(self.pressedSquareId, releasedSquareId)
if oldBoard.is_castling(move):
isWhite = (self.pressedPiece.llPiece.color == chess.WHITE)
if (isWhite and self.pressedSquareId != chess.E1) \
or ((not isWhite) and self.pressedSquareId != chess.E8):
raise ValueError('UIE: Unexpected castling move')
if releasedSquareId > self.pressedSquareId:
if isWhite:
rookPos = self.getScenePos(chess.H1)
rookTargetPos = self.getScenePos(chess.F1)
else:
rookPos = self.getScenePos(chess.H8)
rookTargetPos = self.getScenePos(chess.F8)
else:
if isWhite:
rookPos = self.getScenePos(chess.A1)
rookTargetPos = self.getScenePos(chess.D1)
else:
rookPos = self.getScenePos(chess.A8)
rookTargetPos = self.getScenePos(chess.D8)
rookPiece = self.itemAt(rookPos, QtGui.QTransform())
if isinstance(rookPiece,QtWidgets.QGraphicsRectItem):
raise ValueError('UIE: QGraphicsRectItem found')
rookPiece.setPos(self.getScenePos(releasedSquareId))
rookPiece.setPos(rookTargetPos)
elif oldBoard.is_en_passant(move):
pawnSquareID = chess.square(chess.square_file(move.to_square), chess.square_rank(move.from_square))
pawnItem = self.itemAt(self.getScenePos(pawnSquareID), QtGui.QTransform())
self.removeItem(pawnItem)
print('en passant move detected')
self.pressedPiece.setPos(self.getScenePos(releasedSquareId))
self.gameNode = self.gameNode.add_variation(move)
board = self.gameNode.board()
# showStatus(board)
self.showMaterial(board)
self.showTurn(board)
if self.notifyNewGameNodeSignal is not None:
self.notifyNewGameNodeSignal.emit(self.gameNode)
if self.needHint() or self.score:
self.requestHint.emit(self.fen())
else:
self.pressedPiece.setPos(self.getScenePos(releasedSquareId))
self.pressedPiece = None
self.draw_warnOfDanger()