def __init__(self, *_): super().__init__() self.squareSize = QSize(50, 50) self.board = Board(14, 14) self.pieces = {} self.highlights = [] self.playerHighlights = { 'r': self.PlayerHighlight(12, 1, QColor('#bf3b43')), 'b': self.PlayerHighlight(1, 1, QColor('#4185bf')), 'y': self.PlayerHighlight(1, 12, QColor('#c09526')), 'g': self.PlayerHighlight(12, 12, QColor('#4e9161')) } # Player labels self.redName = None self.redNameEdit = None self.redRating = '?' self.blueName = None self.blueNameEdit = None self.blueRating = '?' self.yellowName = None self.yellowNameEdit = None self.yellowRating = '?' self.greenName = None self.greenNameEdit = None self.greenRating = '?' self.createPlayerLabels() # Drag-drop self.setAcceptDrops(True) self.dragStart = None self.clickedSquare = None self.maskedSquare = None self.mouseButton = None self.currentPlayer = None # Board orientation self.orientation = deque(['r', 'b', 'y', 'g']) # Arrows and square highlight self.arrowStart = None self.keyModifier = None self.arrowColor = None self.squareColor = None # Coordinate help self.coordinate = None self.setMouseTracking(True)
def __init__(self): super().__init__() self.variant = '?' self.board = Board(14, 14) self.result = self.NoResult self.currentPlayer = self.NoPlayer self.moveNumber = 0 self.currentMove = self.Node('root', [], None) self.currentMove.fen4 = self.startFen4 self.redName = self.NoPlayer self.blueName = self.NoPlayer self.yellowName = self.NoPlayer self.greenName = self.NoPlayer self.redRating = '?' self.blueRating = '?' self.yellowRating = '?' self.greenRating = '?' self.chesscomMoveText = '' self.moveText = '' self.moveDict = dict() self.inverseMoveDict = dict() self.index = 0 # Used by getMoveText() method self.fenMoveNumber = 1
def guiTest(chessBoard): app = QApplication(sys.argv) board = Board(chessBoard) sys.exit(app.exec_())
class Algorithm(QObject): """The Algorithm is the underlying logic responsible for changing the current state of the board.""" boardChanged = pyqtSignal(Board) gameOver = pyqtSignal(str) currentPlayerChanged = pyqtSignal(str) fen4Generated = pyqtSignal(str) pgn4Generated = pyqtSignal(str) moveTextChanged = pyqtSignal(str) selectMove = pyqtSignal(tuple) removeMoveSelection = pyqtSignal() removeHighlight = pyqtSignal(QColor) addHighlight = pyqtSignal(int, int, int, int, QColor) playerNamesChanged = pyqtSignal(str, str, str, str) playerRatingChanged = pyqtSignal(str, str, str, str) cannotReadPgn4 = pyqtSignal() NoResult, Team1Wins, Team2Wins, Draw = ['*', '1-0', '0-1', '1/2-1/2'] # Results NoPlayer, Red, Blue, Yellow, Green = ['?', 'r', 'b', 'y', 'g'] # Players playerQueue = deque([Red, Blue, Yellow, Green]) startFen4 = '3yRyNyByKyQyByNyR3/3yPyPyPyPyPyPyPyP3/14/bRbP10gPgR/bNbP10gPgN/bBbP10gPgB/bKbP10gPgQ/' \ 'bQbP10gPgK/bBbP10gPgB/bNbP10gPgN/bRbP10gPgR/14/3rPrPrPrPrPrPrPrP3/3rRrNrBrQrKrBrNrR3 ' \ 'r rKrQbKbQyKyQgKgQ - 0 1' # chess.com: [player to move] - [dead 1/0] - [kingside castle 1/0] - [queenside castle 1/0] - [points] - [ply] - chesscomStartFen4 = 'R-0,0,0,0-1,1,1,1-1,1,1,1-0,0,0,0-0-3,yR,yN,yB,yK,yQ,yB,yN,yR,3/3,yP,yP,yP,yP,yP,yP,yP,yP,3/' \ '14/bR,bP,10,gP,gR/bN,bP,10,gP,gN/bB,bP,10,gP,gB/bK,bP,10,gP,gQ/bQ,bP,10,gP,gK/bB,bP,10,gP,gB/'\ 'bN,bP,10,gP,gN/bR,bP,10,gP,gR/14/3,rP,rP,rP,rP,rP,rP,rP,rP,3/3,rR,rN,rB,rQ,rK,rB,rN,rR,3' def __init__(self): super().__init__() self.variant = '?' self.board = Board(14, 14) self.result = self.NoResult self.currentPlayer = self.NoPlayer self.moveNumber = 0 self.currentMove = self.Node('root', [], None) self.currentMove.fen4 = self.startFen4 self.redName = self.NoPlayer self.blueName = self.NoPlayer self.yellowName = self.NoPlayer self.greenName = self.NoPlayer self.redRating = '?' self.blueRating = '?' self.yellowRating = '?' self.greenRating = '?' self.chesscomMoveText = '' self.moveText = '' self.moveDict = dict() self.inverseMoveDict = dict() self.index = 0 # Used by getMoveText() method self.fenMoveNumber = 1 class Node: """Generic node class. Basic element of a tree.""" def __init__(self, name, children, parent): self.name = name self.children = children self.parent = parent self.fen4 = None self.comment = None def add(self, node): """Adds node to children.""" self.children.append(node) def pop(self): """Removes last child from node.""" self.children.pop() def getRoot(self): """Backtracks tree and returns root node.""" if self.parent is None: return self return self.parent.getRoot() def pathFromRoot(self, actions=None): """Returns a list of nextMove() actions to reach the current node from the root.""" if not actions: actions = [] if self.parent is None: return actions else: var = self.parent.children.index(self) actions.insert(0, 'nextMove(' + str(var) + ')') return self.parent.pathFromRoot(actions) def getMoveNumber(self): """Returns the move number in the format (ply, variation, move). NOTE: does NOT support subvariations.""" varNum = [int(a.strip('nextMove()')) for a in self.pathFromRoot()] ply, var, move = (0, 0, 0) plyCount = True i = 0 while i < len(varNum): if varNum[i] != 0: var = varNum[i] plyCount = False else: if plyCount: ply += 1 else: move += 1 i += 1 return str(ply + 1) + '-' + str(var) + '-' + str( move + 1) if var != 0 else str(ply) def updatePlayerNames(self, red, blue, yellow, green): """Sets player names to names entered in the player name labels.""" self.redName = red if not (red == 'Player Name' or red == '') else '?' self.blueName = blue if not (blue == 'Player Name' or blue == '') else '?' self.yellowName = yellow if not (yellow == 'Player Name' or yellow == '') else '?' self.greenName = green if not (green == 'Player Name' or green == '') else '?' self.getPgn4() # Update PGN4 def updatePlayerRating(self, red, blue, yellow, green): """Sets player rating to rating entered in the player name labels.""" self.redRating = red self.blueRating = blue self.yellowRating = yellow self.greenRating = green def setResult(self, value): """Updates game result, if changed.""" if self.result == value: return if self.result == self.NoResult: self.result = value self.gameOver.emit(self.result) else: self.result = value self.getPgn4() # Update PGN4 def setCurrentPlayer(self, value): """Updates current player, if changed.""" if self.currentPlayer == value: return self.currentPlayer = value self.setPlayerQueue(self.currentPlayer) self.currentPlayerChanged.emit(self.currentPlayer) def setPlayerQueue(self, currentPlayer): """Rotates player queue such that the current player is the first in the queue.""" while self.playerQueue[0] != currentPlayer: self.playerQueue.rotate(-1) def setBoard(self, board): """Updates board, if changed.""" if self.board == board: return self.board = board self.boardChanged.emit(self.board) def setupBoard(self): """Initializes board.""" self.setBoard(Board(14, 14)) def newGame(self): """Initializes board and sets starting position.""" if SETTINGS.value('chesscom'): fen4 = self.chesscomStartFen4 else: fen4 = self.startFen4 self.setBoardState(fen4) self.fen4Generated.emit(fen4) def getFen4(self, emitSignal=True): """Gets FEN4 from current board state.""" fen4 = self.board.getFen4() # Append character for current player fen4 += self.currentPlayer + ' ' fen4 += self.board.castlingAvailability() + ' ' fen4 += '- ' # En passant target square, n/a fen4 += str(self.moveNumber) + ' ' # Number of quarter-moves fen4 += str(self.moveNumber // 4 + 1) # Number of full moves, starting from 1 if SETTINGS.value('chesscom'): chesscomPrefix = self.currentPlayer.upper() + '-0,0,0,0' + \ self.toChesscomCastling(self.board.castlingAvailability()) + '-0,0,0,0-' + \ str(self.moveNumber) + '-' fen4 = chesscomPrefix + self.board.getChesscomFen4() if emitSignal: self.fen4Generated.emit(fen4) return fen4 def toChesscomCastling(self, castling): """Converts castling availability string to chess.com compatible format.""" s = '-' s += '1,' if 'rK' in castling else '0,' s += '1,' if 'bK' in castling else '0,' s += '1,' if 'yK' in castling else '0,' s += '1' if 'gK' in castling else '0' s += '-' s += '1,' if 'rQ' in castling else '0,' s += '1,' if 'bQ' in castling else '0,' s += '1,' if 'yQ' in castling else '0,' s += '1' if 'gQ' in castling else '0' return s def setCastlingAvailability(self, fen4): """Sets castling availability according to FEN4.""" castling = fen4.split(' ')[2] RED, BLUE, YELLOW, GREEN = range(4) QUEENSIDE, KINGSIDE = (0, 1) self.board.castle[RED][KINGSIDE] = ( 1 << self.square(10, 0)) if 'rK' in castling else 0 self.board.castle[RED][QUEENSIDE] = ( 1 << self.square(3, 0)) if 'rQ' in castling else 0 self.board.castle[BLUE][KINGSIDE] = ( 1 << self.square(0, 10)) if 'bK' in castling else 0 self.board.castle[BLUE][QUEENSIDE] = ( 1 << self.square(0, 3)) if 'bQ' in castling else 0 self.board.castle[YELLOW][KINGSIDE] = ( 1 << self.square(3, 13)) if 'yK' in castling else 0 self.board.castle[YELLOW][QUEENSIDE] = ( 1 << self.square(10, 13)) if 'yQ' in castling else 0 self.board.castle[GREEN][KINGSIDE] = ( 1 << self.square(13, 3)) if 'gK' in castling else 0 self.board.castle[GREEN][QUEENSIDE] = ( 1 << self.square(13, 10)) if 'gQ' in castling else 0 def setBoardState(self, fen4): """Sets board according to FEN4.""" if not fen4: return if self.getFen4(False) == fen4: # Do not emit fen4Generated signal return self.setupBoard() self.board.parseFen4(fen4) self.setResult(self.NoResult) if SETTINGS.value('chesscom'): self.setCurrentPlayer(fen4[0].lower()) self.moveNumber = 0 self.fenMoveNumber = 1 else: self.setCurrentPlayer(fen4.split(' ')[1]) self.moveNumber = int(fen4.split(' ')[-2]) self.fenMoveNumber = int(fen4.split(' ')[-2]) + 1 self.currentMove = self.Node('root', [], None) self.currentMove.fen4 = fen4 self.chesscomMoveText = '' self.moveText = '' self.moveDict.clear() self.getPgn4() # Update PGN4 def toChesscomMove(self, moveString): """Converts move string to chess.com move notation.""" moveString = moveString.split() if moveString[0][1] == 'P': moveString.pop(0) if len(moveString) == 3: piece = moveString[1][1] if piece != 'P': moveString[1] = 'x' + piece else: moveString[1] = 'x' else: moveString.insert(1, '-') elif len(moveString) == 4: # Castling move shortCastle = [ 'rK h1 rR k1', 'bK a8 bR a11', 'yK g14 yR d14', 'gK n7 gR n4' ] longCastle = [ 'rK h1 rR d1', 'bK a8 bR a4', 'yK g14 yR k14', 'gK n7 gR n11' ] if ' '.join(moveString) in shortCastle: moveString = 'O-O' elif ' '.join(moveString) in longCastle: moveString = 'O-O-O' else: moveString[0] = moveString[0][1] piece = moveString[2][1] if piece != 'P': moveString[2] = 'x' + piece else: moveString[2] = 'x' else: if moveString != 'O-O' and moveString != 'O-O-O': moveString[0] = moveString[0][1] moveString.insert(2, '-') moveString = ''.join(moveString) return moveString def fromChesscomMove(self, move, player): """Returns fromFile, fromRank, toFile, toRank from chess.com move.""" if move == 'O-O': if player == self.Red: fromFile, fromRank, toFile, toRank = (7, 0, 10, 0) elif player == self.Blue: fromFile, fromRank, toFile, toRank = (0, 7, 0, 10) elif player == self.Yellow: fromFile, fromRank, toFile, toRank = (6, 13, 3, 13) elif player == self.Green: fromFile, fromRank, toFile, toRank = (13, 6, 13, 3) else: fromFile, fromRank, toFile, toRank = [None] * 4 elif move == 'O-O-O': if player == self.Red: fromFile, fromRank, toFile, toRank = (7, 0, 3, 0) elif player == self.Blue: fromFile, fromRank, toFile, toRank = (0, 7, 0, 3) elif player == self.Yellow: fromFile, fromRank, toFile, toRank = (6, 13, 10, 13) elif player == self.Green: fromFile, fromRank, toFile, toRank = (13, 6, 13, 10) else: fromFile, fromRank, toFile, toRank = [None] * 4 else: for c in reversed(move): if c.isupper(): move = move.replace(c, '') move = move.replace('x', '') move = move.replace('-', '') move = move.replace('+', '') move = move.replace('#', '') prev = '' i = 0 for char in move: if (not char.isdigit()) and prev.isdigit(): move = [move[:i], move[i:]] break prev = char i += 1 fromFile = ord(move[0][0]) - 97 fromRank = int(move[0][1:]) - 1 toFile = ord(move[1][0]) - 97 toRank = int(move[1][1:]) - 1 return fromFile, fromRank, toFile, toRank def toAlgebraic(self, moveString): """Converts move string to algebraic notation.""" moveString = moveString.split() if moveString[0][1] == 'P': moveString.pop(0) if len(moveString) == 3: moveString[1] = 'x' elif len(moveString) == 4: # Castling move shortCastle = [ 'rK h1 rR k1', 'bK a8 bR a11', 'yK g14 yR d14', 'gK n7 gR n4' ] longCastle = [ 'rK h1 rR d1', 'bK a8 bR a4', 'yK g14 yR k14', 'gK n7 gR n11' ] if ' '.join(moveString) in shortCastle: moveString = 'O-O' elif ' '.join(moveString) in longCastle: moveString = 'O-O-O' else: moveString[0] = moveString[0][1] moveString[2] = 'x' else: if moveString != 'O-O' and moveString != 'O-O-O': moveString[0] = moveString[0][1] moveString = ''.join(moveString) return moveString def fromAlgebraic(self, move, player): """Returns fromFile, fromRank, toFile, toRank from algebraic move.""" if move == 'O-O': if player == self.Red: fromFile, fromRank, toFile, toRank = (7, 0, 10, 0) elif player == self.Blue: fromFile, fromRank, toFile, toRank = (0, 7, 0, 10) elif player == self.Yellow: fromFile, fromRank, toFile, toRank = (6, 13, 3, 13) elif player == self.Green: fromFile, fromRank, toFile, toRank = (13, 6, 13, 3) else: fromFile, fromRank, toFile, toRank = [None] * 4 elif move == 'O-O-O': if player == self.Red: fromFile, fromRank, toFile, toRank = (7, 0, 3, 0) elif player == self.Blue: fromFile, fromRank, toFile, toRank = (0, 7, 0, 3) elif player == self.Yellow: fromFile, fromRank, toFile, toRank = (6, 13, 10, 13) elif player == self.Green: fromFile, fromRank, toFile, toRank = (13, 6, 13, 10) else: fromFile, fromRank, toFile, toRank = [None] * 4 else: if move[0].isupper(): move = move[1:] move = move.replace('x', '') prev = '' i = 0 for char in move: if (not char.isdigit()) and prev.isdigit(): move = [move[:i], move[i:]] break prev = char i += 1 fromFile = ord(move[0][0]) - 97 fromRank = int(move[0][1:]) - 1 toFile = ord(move[1][0]) - 97 toRank = int(move[1][1:]) - 1 return fromFile, fromRank, toFile, toRank def strMove(self, fromFile, fromRank, toFile, toRank): """Returns move in string form, separated by spaces, i.e. '<piece> <from> <captured piece> <to>'.""" piece: str = self.board.getData(fromFile, fromRank) captured: str = self.board.getData(toFile, toRank) char = (piece + ' ' + chr(97 + fromFile) + str(fromRank + 1) + ' ' + captured * (captured != ' ') + ' ' + chr(97 + toFile) + str(toRank + 1)) # chr(97) = 'a' return char def prevMove(self): """Sets board state to previous move.""" if self.currentMove.name == 'root': return moveString = self.currentMove.name moveString = moveString.split() piece = moveString[0] fromFile = ord(moveString[1][0]) - 97 # chr(97) = 'a' fromRank = int(moveString[1][1:]) - 1 if len(moveString) == 4: captured = moveString[2] toFile = ord(moveString[3][0]) - 97 toRank = int(moveString[3][1:]) - 1 else: captured = ' ' toFile = ord(moveString[2][0]) - 97 toRank = int(moveString[2][1:]) - 1 self.board.undoMove(fromFile, fromRank, toFile, toRank, piece, captured) self.currentMove = self.currentMove.parent self.moveNumber -= 1 self.playerQueue.rotate(1) self.setCurrentPlayer(self.playerQueue[0]) # Signal View to remove last move highlight if self.currentPlayer == self.Red: color = QColor('#33bf3b43') elif self.currentPlayer == self.Blue: color = QColor('#334185bf') elif self.currentPlayer == self.Yellow: color = QColor('#33c09526') elif self.currentPlayer == self.Green: color = QColor('#334e9161') else: color = QColor('#00000000') self.removeHighlight.emit(color) if not self.currentMove.name == 'root': key = self.inverseMoveDict[self.currentMove] self.selectMove.emit(key) else: self.removeMoveSelection.emit() self.getFen4() # Update FEN4 self.getPgn4() # Update PGN4 def nextMove(self, var=0): """Sets board state to next move. Follows main variation by default (var=0).""" if not self.currentMove.children: return moveString = self.currentMove.children[var].name moveString = moveString.split() fromFile = ord(moveString[1][0]) - 97 # chr(97) = 'a' fromRank = int(moveString[1][1:]) - 1 if len(moveString) == 4: toFile = ord(moveString[3][0]) - 97 toRank = int(moveString[3][1:]) - 1 else: toFile = ord(moveString[2][0]) - 97 toRank = int(moveString[2][1:]) - 1 self.board.makeMove(fromFile, fromRank, toFile, toRank) self.currentMove = self.currentMove.children[var] self.moveNumber += 1 # Signal View to add move highlight and remove highlights of next player if self.currentPlayer == self.Red: color = QColor('#33bf3b43') elif self.currentPlayer == self.Blue: color = QColor('#334185bf') elif self.currentPlayer == self.Yellow: color = QColor('#33c09526') elif self.currentPlayer == self.Green: color = QColor('#334e9161') else: color = QColor('#00000000') self.addHighlight.emit(fromFile, fromRank, toFile, toRank, color) self.playerQueue.rotate(-1) self.setCurrentPlayer(self.playerQueue[0]) if self.currentPlayer == self.Red: color = QColor('#33bf3b43') elif self.currentPlayer == self.Blue: color = QColor('#334185bf') elif self.currentPlayer == self.Yellow: color = QColor('#33c09526') elif self.currentPlayer == self.Green: color = QColor('#334e9161') else: color = QColor('#00000000') self.removeHighlight.emit(color) key = self.inverseMoveDict[self.currentMove] self.selectMove.emit(key) self.getFen4() # Update FEN4 self.getPgn4() # Update PGN4 def firstMove(self): """Sets board state to first move.""" while self.currentMove.name != 'root': self.prevMove() def lastMove(self): """Sets board state to last move.""" self.firstMove() while self.currentMove.children: self.nextMove() def makeMove(self, fromFile, fromRank, toFile, toRank): """This method must be implemented to define the proper logic corresponding to the game type (Teams or FFA).""" return False def getPgn4(self): """Generates PGN4 from current game.""" pgn4 = '' # Tags: "?" if data unknown, "-" if not applicable pgn4 += '[Variant "' + self.variant + '"]\n' pgn4 += '[Site "www.chess.com/4-player-chess"]\n' pgn4 += '[Date "' + datetime.utcnow().strftime( '%a %b %d %Y %H:%M:%S (UTC)') + '"]\n' # pgn4 += '[Event "-"]\n' # pgn4 += '[Round "-"]\n' pgn4 += '[Red "' + self.redName + '"]\n' if not self.redName == '?' else '' pgn4 += '[RedElo "' + self.redRating + '"]\n' if not self.redRating == '?' else '' pgn4 += '[Blue "' + self.blueName + '"]\n' if not self.blueName == '?' else '' pgn4 += '[BlueElo "' + self.blueRating + '"]\n' if not self.blueRating == '?' else '' pgn4 += '[Yellow "' + self.yellowName + '"]\n' if not self.yellowName == '?' else '' pgn4 += '[YellowElo "' + self.yellowRating + '"]\n' if not self.yellowRating == '?' else '' pgn4 += '[Green "' + self.greenName + '"]\n' if not self.greenName == '?' else '' pgn4 += '[GreenElo "' + self.greenRating + '"]\n' if not self.greenRating == '?' else '' # pgn4 += '[Result "' + self.result + '"]\n' # 1-0 (r & y win), 0-1 (b & g win), 1/2-1/2 (draw), * (no result) # pgn4 += '[Mode "ICS"]\n' # ICS = Internet Chess Server, OTB = Over-The-Board pgn4 += '[TimeControl "G/1 d15"]\n' # 1-minute game with 15 seconds delay per move pgn4 += '[PlyCount "' + str( self.moveNumber) + '"]\n' # Total number of quarter-moves startFen4 = self.currentMove.getRoot().fen4 if SETTINGS.value('chesscom'): if startFen4 != self.chesscomStartFen4: pgn4 += '[SetUp "1"]\n' pgn4 += '[StartFen4 "' + startFen4 + '"]\n' else: if startFen4 != self.startFen4: pgn4 += '[SetUp "1"]\n' pgn4 += '[StartFen4 "' + startFen4 + '"]\n' pgn4 += '[CurrentMove "' + self.currentMove.getMoveNumber() + '"]\n' pgn4 += '[CurrentPosition "' + self.getFen4() + '"]\n\n' # Movetext if SETTINGS.value('chesscom'): pgn4 = pgn4[:-1] # remove newline pgn4 += self.chesscomMoveText else: pgn4 += self.moveText # Append result pgn4 += self.result self.pgn4Generated.emit(pgn4) def updateMoveText(self): """Updates movetext and dictionary.""" self.chesscomMoveText = '' self.moveText = '' self.moveDict.clear() self.index = 0 self.getMoveText(self.currentMove.getRoot(), self.fenMoveNumber) self.inverseMoveDict = { value: key for key, value in self.moveDict.items() } self.moveTextChanged.emit(self.moveText) if self.currentMove.name != 'root': key = self.inverseMoveDict[self.currentMove] self.selectMove.emit(key) def getMoveText(self, node, move=1, var=0): """Traverses move tree to generate movetext and updates move dictionary to keep track of the nodes associated with the movetext.""" if node.children: main = node.children[0] if len(node.children) > 1: variations = node.children[1:] else: variations = None else: main = None variations = None # If different FEN4 starting position used, insert move number if needed if node.name == 'root' and move != 1 and (move - 1) % 4: token = str((move - 1) // 4 + 1) + '.' self.chesscomMoveText += token self.moveText += token + ' ' self.moveDict[(self.index, token)] = None self.index += 1 token = '.' * ((move - 1) % 4) if token: self.moveText += token self.moveDict[(self.index, token)] = None self.index += 1 if (move - 1) % 4: self.chesscomMoveText += ' ' self.moveText += ' ' # Main move has variations if main and variations: if not (move - 1) % 4: token = str(move // 4 + 1) + '.' self.chesscomMoveText += '\n' + token + ' ' self.moveText += token + ' ' self.moveDict[(self.index, token)] = None self.index += 1 else: self.chesscomMoveText += '.. ' # Add main move to movetext before expanding variations, but do not expand main move yet chesscomToken = self.toChesscomMove(main.name) self.chesscomMoveText += chesscomToken + ' ' token = self.toAlgebraic(main.name) self.moveText += token + ' ' self.moveDict[(self.index, token)] = main self.index += 1 if main.comment: self.chesscomMoveText += '{ ' + main.comment + ' } ' self.moveText += '{ ' + main.comment + ' } ' # Expand variations for variation in variations: if self.moveText[-2] == ')': self.index += 1 token = '(' self.chesscomMoveText += token + ' ' self.moveText += token + ' ' self.moveDict[(self.index, token)] = None self.index += 1 token = str(move // 4 + 1) self.chesscomMoveText += token self.moveText += token + ' ' self.moveDict[(self.index, token)] = None self.index += 1 token = '.' * ((move - 1) % 4) if token: self.moveText += token self.moveDict[(self.index, token)] = None self.index += 1 if (move - 1) % 4: self.chesscomMoveText += '.. ' self.moveText += ' ' else: self.chesscomMoveText += '. ' chesscomToken = self.toChesscomMove(variation.name) self.chesscomMoveText += chesscomToken + ' ' token = self.toAlgebraic(variation.name) self.moveText += token + ' ' self.moveDict[(self.index, token)] = variation self.index += 1 if variation.comment: self.chesscomMoveText += '{ ' + variation.comment + ' } ' self.moveText += '{ ' + variation.comment + ' } ' self.getMoveText(variation, move + 1, var + 1) # Expand main move self.index += 1 self.getMoveText(main, move + 1, var) # Main move has no variations elif main and not variations: if not (move - 1) % 4: token = str(move // 4 + 1) + '.' self.chesscomMoveText += '\n' + token + ' ' self.moveText += token + ' ' self.moveDict[(self.index, token)] = None self.index += 1 else: self.chesscomMoveText += '.. ' chesscomToken = self.toChesscomMove(main.name) self.chesscomMoveText += chesscomToken + ' ' token = self.toAlgebraic(main.name) self.moveText += token + ' ' self.moveDict[(self.index, token)] = main self.index += 1 if main.comment: self.chesscomMoveText += '{ ' + main.comment + ' } ' self.moveText += '{ ' + main.comment + ' } ' self.getMoveText(main, move + 1, var) # Node is leaf node (i.e. end of variation or main line) else: if var != 0: token = ')' self.chesscomMoveText += token + ' ' self.moveText += token + ' ' self.moveDict[(self.index, token)] = None def split_(self, movetext): """Splits movetext into tokens.""" x = split('\s+(?={)|(?<=})\s+', movetext ) # regex: one or more spaces followed by { or preceded by } movetext = [] for y in x: if y: if y[0] != '{': for z in y.split(): movetext.append(z) else: movetext.append(y) return movetext def parseChesscomPgn4(self, pgn4): """Parses chess.com PGN4 and sets game state accordingly.""" startPosition = None currentMove = None lines = pgn4.split('\n') movetext = '' for line in lines: if line == '': continue elif line[0] == '[' and line[-1] == ']': tag = line.strip('[]').split('"')[:-1] tag[0] = tag[0].strip() if tag[0] == 'Variant' and tag[1] == 'FFA': self.cannotReadPgn4.emit() return False elif tag[0] == 'Red': self.redName = tag[1] elif tag[0] == 'RedElo': self.redRating = tag[1] elif tag[0] == 'Blue': self.blueName = tag[1] elif tag[0] == 'BlueElo': self.blueRating = tag[1] elif tag[0] == 'Yellow': self.yellowName = tag[1] elif tag[0] == 'YellowElo': self.yellowRating = tag[1] elif tag[0] == 'Green': self.greenName = tag[1] elif tag[0] == 'GreenElo': self.greenRating = tag[1] elif tag[0] == 'Result': self.result = tag[1] elif tag[0] == 'StartFen4': startPosition = tag[1] elif tag[0] == 'CurrentMove': currentMove = tag[1] else: # Irrelevant tags pass else: if not currentMove: self.cannotReadPgn4.emit() return False movetext += line + ' ' # Generate game from movetext self.newGame() tokens = self.split_(movetext) for token in tokens: if token[0] == '(' and len(token) > 1: index = tokens.index(token) tokens.insert(index + 1, token[1:]) tokens[index] = token[0] roots = [] prev = None i = 0 for token in tokens: try: next_ = tokens[i + 1] except IndexError: next_ = None if (token[0].isdigit() and token[-1] == '.') or token in '..RT#': pass elif token[0] == '{': # Comment self.currentMove.comment = token[1:-1].strip() elif token == '(': # Next move is variation if not prev == ')': self.prevMove() roots.append(self.currentMove) else: roots.append(self.currentMove) elif token == ')': # End of variation root = roots.pop() while self.currentMove.name != root.name: self.prevMove() if next_ != '(': # Continue with previous line self.nextMove() else: fromFile, fromRank, toFile, toRank = self.fromChesscomMove( token, self.currentPlayer) self.makeMove(fromFile, fromRank, toFile, toRank) prev = token i += 1 # Set game position to CurrentMove ("ply-variation-move") self.firstMove() currentMove = [int(c) for c in currentMove.split('-')] if len(currentMove) == 1: ply = currentMove[0] for _ in range(ply): self.nextMove() else: ply, variation, move = currentMove for _ in range(ply - 1): self.nextMove() self.nextMove(variation) for _ in range(move - 1): self.nextMove() # Emit signal to update player names and rating self.playerNamesChanged.emit(self.redName, self.blueName, self.yellowName, self.greenName) self.playerRatingChanged.emit(self.redRating, self.blueRating, self.yellowRating, self.greenRating) return True def parsePgn4(self, pgn4): """Parses PGN4 and sets game state accordingly.""" currentPosition = None lines = pgn4.split('\n') for line in lines: if line == '': continue elif line[0] == '[' and line[-1] == ']': tag = line.strip('[]').split('"')[:-1] tag[0] = tag[0].strip() if tag[0] == 'Variant' and tag[1] == 'FFA': self.cannotReadPgn4.emit() return False elif tag[0] == 'Red': self.redName = tag[1] elif tag[0] == 'Blue': self.blueName = tag[1] elif tag[0] == 'Yellow': self.yellowName = tag[1] elif tag[0] == 'Green': self.greenName = tag[1] elif tag[0] == 'Result': self.result = tag[1] elif tag[0] == 'CurrentPosition': currentPosition = tag[1] else: # Irrelevant tags pass else: if not currentPosition: self.cannotReadPgn4.emit() return False # Generate game from movetext self.newGame() line = line.replace(' *', '') line = line.replace(' 1-0', '') line = line.replace(' 0-1', '') line = line.replace(' 1/2-1/2', '') if line == '*': # No movetext to process break roots = [] tokens = self.split_(line) prev = None i = 0 for token in tokens: try: next_ = tokens[i + 1] except IndexError: next_ = None if token[0].isdigit() or token[0] == '.': pass elif token[0] == '{': # Comment self.currentMove.comment = token[1:-1].strip() elif token == '(': # Next move is variation if not prev == ')': self.prevMove() roots.append(self.currentMove) else: roots.append(self.currentMove) elif token == ')': # End of variation root = roots.pop() while self.currentMove.name != root.name: self.prevMove() if next_ != '(': # Continue with previous line self.nextMove() else: fromFile, fromRank, toFile, toRank = self.fromAlgebraic( token, self.currentPlayer) self.makeMove(fromFile, fromRank, toFile, toRank) prev = token i += 1 # Set game position to FEN4 self.firstMove() node = None for node in self.traverse(self.currentMove, self.currentMove.children): if node.fen4 == currentPosition: break if node: actions = node.pathFromRoot() for action in actions: exec('self.' + action) # Emit signal to update player names self.playerNamesChanged.emit(self.redName, self.blueName, self.yellowName, self.greenName) return True def traverse(self, tree, children): """Traverses nodes of tree in breadth-first order.""" yield tree last = tree for node in self.traverse(tree, children): for child in node.children: yield child last = child if last == node: return
def setupBoard(self): """Initializes board.""" self.setBoard(Board(14, 14))
import sys from PyQt5.QtWidgets import QApplication from gui.board import Board if __name__ == '__main__': app = QApplication(sys.argv) window = Board() sys.exit(app.exec_())
def main(): """Main function of the game. This function initializes the game and enters the PyGame main loop. """ # Inits PyGame module pygame.init() # Loads Sugar standard cursor a, b, c, d = pygame.cursors.load_xbm("gui/standardcursor.xbm", "gui/standardcursor_mask.xbm") pygame.mouse.set_cursor(a, b, c, d) internal_size = ( 1200, 825 ) # The game is designed to work in this size (xo display size) target_size = ( 900, 619 ) # The game will be sown in this size, useful for testing in regular PCs with less resolution than xo flags = 0 if olpcgames.ACTIVITY: # Running as Activity target_size = olpcgames.ACTIVITY.game_size #logic.Mesh.init_mesh(log) # Mesh isn't ready in this version else: pass # Uncomment this if want to execute fullscreen on regular PCs # flags = pygame.FULLSCREEN real_screen = pygame.display.set_mode(target_size, flags) # The scale factor beetween internal and target if internal_size == target_size: scale = None internal_screen = real_screen # The game works directly on the real screen else: # Running on regular PC, the screen its scaled to te target_size internal_screen = pygame.Surface(internal_size) scale = (internal_size[0] / float(target_size[0]), internal_size[1] / float(target_size[1])) # Creates a new logic game, player names aren't used without mesh game = GameState("Jugador1", "Jugador2") board = Board(internal_screen, game) board.paint_board_elements() pygame.display.update() # This clock is used to keep the game at the desired FPS. clock = pygame.time.Clock() # Main loop update = True # The first time the screen need to be updated running = True while running: # Waits for events, if none the game pauses: # http://wiki.laptop.org/go/Game_development_HOWTO#Reducing_CPU_Load milliseconds = clock.tick( MAX_FPS) # waits if the game is running faster than MAX_FPS events = olpcgames.pausescreen.get_events( SLEEP_TIMEOUT ) # Event-management loop with support for pausing after X seconds (20 here) if events: for event in events: if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: running = False if event.type == pygame.MOUSEBUTTONDOWN: if scale: x = event.pos[0] * scale[ 0] # Multiplies the real coordinates by the scale factor y = event.pos[1] * scale[ 1] # to get the internal coordinates else: (x, y) = event.pos update = board.processXY(x, y) if event.type == pygame.USEREVENT: if event.code == olpcgames.FILE_READ_REQUEST: game = _read_file(event.filename) log.debug("Loaded:" + game.serialization()) board = Board(internal_screen, game) update = True elif event.code == olpcgames.FILE_WRITE_REQUEST: _save_file(event.filename, game) if event.type > pygame.USEREVENT and event.type <= pygame.USEREVENT + 10: log.debug("New user event") board.user_event(event) update = True if update == True: board.paint_board_elements() if scale: pygame.transform.scale(internal_screen, target_size, real_screen) update = False pygame.display.flip() # Una vez que sale del loop manda la senal de quit para que cierre la ventana pygame.quit()
def __init__(self, win): self.win = win self.board = Board() self.is_moving_anim = False self.board.prep_anim() self.top_player = True
class Engine: def __init__(self, win): self.win = win self.board = Board() self.is_moving_anim = False self.board.prep_anim() self.top_player = True def update(self): self.board.move_marbles() self.board.draw_board(self.win) self.board.draw_text(self.win, self.top_player) pygame.display.update() if self.board.animation_finished(): self.is_moving_anim = False def move(self, pos=(-1, -1), pit_number=-1): if self.is_moving_anim == True: return False self.is_moving_anim = True # Find pit clicked by mouse if pit_number == -1: pit = self.board.get_pit(pos, self.top_player) else: pit = self.board.get_pit_by_number(pit_number, self.top_player) if pit == None: return False # Move the marbles last_pit = self.move_marbles(pit) # Check take (zbicie) self.check_take(last_pit) # Change move if the last pit was not a player's basket if not (last_pit.is_basket and last_pit.top_player == self.top_player): self.top_player = not self.top_player # Moves marbles and returns last pit def move_marbles(self, pit): marbles = pit.get_marbles() pit.remove_marbles() for i in range(len(marbles)): pit = pit.next_pit() if pit.is_basket and pit.top_player != self.top_player: pit = pit.next_pit() pit.add_marble(marbles[i]) return pit def check_take(self, pit): cond = (pit.top_player == self.top_player and pit.get_marbles_count() == 1 and not pit.is_basket and pit.opposite_pit().get_marbles_count() != 0) if cond: self.board.get_basket(self.top_player).add_marble( pit.get_marbles()[0]) pit.remove_marbles() opposite_pit = pit.opposite_pit() opposite_marbles = opposite_pit.get_marbles() opposite_pit.remove_marbles() for m in opposite_marbles: self.board.get_basket(self.top_player).add_marble(m) def game_over(self): return self.board.check_game_over(self.top_player) def update_baskets_gameover(self): self.board.update_baskets_gameover(self.top_player) def print_game_over(self): self.board.move_marbles() self.board.draw_board(self.win) self.board.draw_game_over(self.win) pygame.display.update() def gamestate(self): return self.board.generate_gamestate(self.top_player)
def _setup_board(self): return Board(self.root, self.players)
class View(QWidget): """The View is responsible for rendering the current state of the board and signalling user interaction to the underlying logic.""" clicked = pyqtSignal(QPoint) squareSizeChanged = pyqtSignal(QSize) playerNameEdited = pyqtSignal(str, str, str, str) playerRatingEdited = pyqtSignal(str, str, str, str) pieceMoved = pyqtSignal(QPoint, QPoint) dragStarted = pyqtSignal(QPoint) def __init__(self, *_): super().__init__() self.squareSize = QSize(50, 50) self.board = Board(14, 14) self.pieces = {} self.highlights = [] self.playerHighlights = { 'r': self.PlayerHighlight(12, 1, QColor('#bf3b43')), 'b': self.PlayerHighlight(1, 1, QColor('#4185bf')), 'y': self.PlayerHighlight(1, 12, QColor('#c09526')), 'g': self.PlayerHighlight(12, 12, QColor('#4e9161')) } # Player labels self.redName = None self.redNameEdit = None self.redRating = '?' self.blueName = None self.blueNameEdit = None self.blueRating = '?' self.yellowName = None self.yellowNameEdit = None self.yellowRating = '?' self.greenName = None self.greenNameEdit = None self.greenRating = '?' self.createPlayerLabels() # Drag-drop self.setAcceptDrops(True) self.dragStart = None self.clickedSquare = None self.maskedSquare = None self.mouseButton = None self.currentPlayer = None # Board orientation self.orientation = deque(['r', 'b', 'y', 'g']) # Arrows and square highlight self.arrowStart = None self.keyModifier = None self.arrowColor = None self.squareColor = None # Coordinate help self.coordinate = None self.setMouseTracking(True) class SquareHighlight: """A square highlight.""" Type = 1 def __init__(self, file, rank, color): self.file = file self.rank = rank self.color = color class PlayerHighlight(SquareHighlight): """A player highlight. Same as square highlight, just renamed for convenience (unaltered subclass).""" pass class Arrow: """An arrow highlight, to show possible moves on the board.""" Type = 2 def __init__(self, origin, target, color): self.origin = origin self.target = target self.color = color class LegalMoveIndicator: """A legal move indicator.""" Type = 3 def __init__(self, square, capture=False): self.square = square self.capture = capture def rotateBoard(self, rotation): """Rotates board view (clockwise +, counterclockwise -).""" self.orientation.rotate(rotation) self.movePlayerLabels(self.orientation[0]) self.removeArrows() self.update() def autoRotate(self, rotation): """Automatically rotates board after move is made or undone.""" if SETTINGS.value('autorotate'): self.rotateBoard(rotation) def setCurrentPlayer(self, player): """Updates current player, if changed.""" if self.currentPlayer == player: return self.currentPlayer = player def setBoard(self, board): """Updates board, if changed. Disconnects signals from old board and connects them to new board.""" if self.board == board: return if self.board: try: self.board.disconnect() # If there are no signal-slot connections, TypeError is raised except TypeError: pass self.board = board if board: board.dataChanged.connect(self.update) board.boardReset.connect(self.update) board.boardReset.connect(self.resetHighlights) board.autoRotate.connect(self.autoRotate) self.updateGeometry() def setSquareSize(self, size): """Sets size of board squares and updates geometry accordingly.""" if self.squareSize == size: return self.squareSize = size self.squareSizeChanged.emit(size) self.updateGeometry() def sizeHint(self): """Implements sizeHint() method. Computes and returns size based on size of board squares.""" return QSize(self.squareSize.width() * self.board.files, self.squareSize.height() * self.board.ranks) def squareRect(self, file, rank, orientation=None): """Returns square of type QRect at position (file, rank).""" sqSize = self.squareSize if orientation == 'b': return QRect( QPoint((self.board.ranks - (rank + 1)) * sqSize.width(), (self.board.files - (file + 1)) * sqSize.height()), sqSize) elif orientation == 'y': return QRect( QPoint((self.board.files - (file + 1)) * sqSize.width(), rank * sqSize.height()), sqSize) elif orientation == 'g': return QRect(QPoint(rank * sqSize.width(), file * sqSize.height()), sqSize) else: # red by default return QRect( QPoint(file * sqSize.width(), (self.board.ranks - (rank + 1)) * sqSize.height()), sqSize) def squareCenter(self, square, orientation=None): """Returns center of square as QPoint.""" sqSize = self.squareSize file = square.x() rank = square.y() if orientation == 'b': return QPoint((self.board.ranks - (rank + 1)) * sqSize.width() + sqSize.width() / 2, (self.board.files - (file + 1)) * sqSize.height() + sqSize.height() / 2) elif orientation == 'y': return QPoint((self.board.files - (file + 1)) * sqSize.width() + sqSize.width() / 2, rank * sqSize.height() + sqSize.height() / 2) elif orientation == 'g': return QPoint(rank * sqSize.width() + sqSize.width() / 2, file * sqSize.height() + sqSize.height() / 2) else: # red by default return QPoint(file * sqSize.width() + sqSize.width() / 2, (self.board.ranks - (rank + 1)) * sqSize.height() + sqSize.height() / 2) def paintEvent(self, event): """Implements paintEvent() method. Draws squares and pieces on the board.""" painter = QPainter() painter.begin(self) # Draw squares for rank in range(self.board.ranks): for file in range(self.board.files): # Do not paint 3x3 sub-grids at the corners if not ((file < 3 and rank < 3) or (file < 3 and rank > 10) or (file > 10 and rank < 3) or (file > 10 and rank > 10)): self.drawSquare(painter, file, rank) # Draw square highlights self.drawSquareHighlights(painter) painter.fillRect(self.squareRect(12, 1, self.orientation[0]), QColor('#40bf3b43')) painter.fillRect(self.squareRect(1, 1, self.orientation[0]), QColor('#404185bf')) painter.fillRect(self.squareRect(1, 12, self.orientation[0]), QColor('#40c09526')) painter.fillRect(self.squareRect(12, 12, self.orientation[0]), QColor('#404e9161')) # Show or hide player names if SETTINGS.value('shownames'): self.showNames() else: self.hideNames() # Draw pieces for rank in range(self.board.ranks): for file in range(self.board.files): if not self.maskedSquare == QPoint( file, rank): # When dragging a piece, don't paint it self.drawPiece(painter, file, rank) # Draw coordinates if SETTINGS.value('showcoordinates'): for y in range(14): x = 0 if 2 < y < 11 else 3 square = self.squareRect(x, y) square.moveTopLeft(QPoint(square.x() + 1, square.y() + 1)) square = QRectF(square) # Only works with QRectF, so convert if self.orientation[0] == 'b': file = self.board.files - (y + 1) rank = self.board.ranks - (x + 1) elif self.orientation[0] == 'y': file = self.board.files - (x + 1) rank = y elif self.orientation[0] == 'g': file = y rank = x else: # red by default file = x rank = self.board.ranks - (y + 1) color = self.palette().color(QPalette.Light) if (file + rank) % 2 \ else self.palette().color(QPalette.Dark) font = QFont('Trebuchet MS', 10, QFont.Bold) painter.setPen(color) painter.setFont(font) if self.orientation[0] in 'ry': painter.drawText(square, str(self.board.ranks - rank)) else: painter.drawText(square, chr(self.board.files - (file + 1) + 97)) for x in range(14): y = 0 if 2 < x < 11 else 3 square = self.squareRect(x, y) square.moveTopLeft(QPoint(square.x() - 1, square.y() - 1)) square = QRectF(square) # Only works with QRectF, so convert if self.orientation[0] == 'b': file = self.board.files - (y + 1) rank = self.board.ranks - (x + 1) elif self.orientation[0] == 'y': file = self.board.files - (x + 1) rank = y elif self.orientation[0] == 'g': file = y rank = x else: # red by default file = x rank = self.board.ranks - (y + 1) color = self.palette().color(QPalette.Light) if (file + rank) % 2 \ else self.palette().color(QPalette.Dark) font = QFont('Trebuchet MS', 10, QFont.Bold) painter.setPen(color) painter.setFont(font) if self.orientation[0] in 'ry': painter.drawText(square, Qt.AlignBottom | Qt.AlignRight, chr(file + 97)) else: painter.drawText(square, Qt.AlignBottom | Qt.AlignRight, str(rank + 1)) # Draw arrows self.drawArrows(painter) # Draw legal moves if SETTINGS.value('showlegalmoves'): self.drawLegalMoves(painter) # Draw coordinate help if SETTINGS.value('coordinatehelp'): if self.coordinate: file = ord(self.coordinate[1][0]) - 97 rank = int(self.coordinate[1][1:]) - 1 if not ((file < 3 and rank < 3) or (file < 3 and rank > 10) or (file > 10 and rank < 3) or (file > 10 and rank > 10)): square = self.coordinate[0] square = self.squareRect(square.x(), square.y()) square.moveTopLeft(QPoint(square.x(), square.y())) square = QRectF( square) # Only works with QRectF, so convert # Draw twice (grey and white with offset) to get shade effect for contrast painter.setPen(QColor('#80404040')) painter.setFont(QFont('Trebuchet MS', 20, QFont.Bold)) painter.drawText(square, Qt.AlignCenter | Qt.AlignVCenter, self.coordinate[1]) square.moveTopLeft(QPoint(square.x() - 1, square.y() - 1)) painter.setPen(QColor('white')) painter.setFont(QFont('Trebuchet MS', 20, QFont.Bold)) painter.drawText(square, Qt.AlignCenter | Qt.AlignVCenter, self.coordinate[1]) painter.end() def drawSquare(self, painter, file, rank): """Draws dark or light square at position (file, rank) using painter.""" rect = self.squareRect(file, rank, self.orientation[0]) fillColor = self.palette().color( QPalette.Midlight) if (file + rank) % 2 else self.palette().color( QPalette.Mid) painter.fillRect(rect, fillColor) def setPiece(self, char, icon): """Sets piece icon corresponding to algebraic piece name.""" self.pieces[char] = icon self.update() def piece(self, char): """Returns piece icon corresponding to algebraic piece name.""" return self.pieces[char] def drawPiece(self, painter, file, rank): """Draws piece at square (file, rank) using painter.""" rect = self.squareRect(file, rank, self.orientation[0]) char = self.board.getData(file, rank) if char != ' ': icon = self.piece(char) if not icon.isNull(): icon.paint(painter, rect, Qt.AlignCenter) def squareAt(self, point, orientation=None): """Returns square (file, rank) of type QPoint that contains point.""" sqSize = self.squareSize x = point.x() // sqSize.width() y = point.y() // sqSize.height() if (x < 0) or (x > 13) or (y < 0) or (y > 13): return QPoint() elif orientation == 'b': return QPoint(self.board.files - (y + 1), self.board.ranks - (x + 1)) elif orientation == 'y': return QPoint(self.board.files - (x + 1), y) elif orientation == 'g': return QPoint(y, x) else: # red by default return QPoint(x, self.board.ranks - (y + 1)) def mouseReleaseEvent(self, event): """Implements mouseReleaseEvent() method. Emits signal with clicked square (QPoint) in case of a left-click. Adds arrows and square highlights in case of a right-click (drag).""" point = self.squareAt(event.pos(), self.orientation[0]) arrowEnd = self.squareAt(event.pos()) if self.mouseButton == Qt.RightButton: if self.keyModifier == Qt.Key_1: self.arrowColor = QColor('#ab272f') self.squareColor = QColor('#80ab272f') elif self.keyModifier == Qt.Key_2: self.arrowColor = QColor('#2d71ab') self.squareColor = QColor('#802d71ab') elif self.keyModifier == Qt.Key_3: self.arrowColor = QColor('#ac8112') self.squareColor = QColor('#80ac8112') elif self.keyModifier == Qt.Key_4: self.arrowColor = QColor('#3a7d4d') self.squareColor = QColor('#803a7d4d') elif self.keyModifier == Qt.Key_0: self.arrowColor = QColor('#ff8c00') self.squareColor = QColor('#80ff8c00') else: if SETTINGS.value('autocolor'): if self.orientation[0] == 'r': self.arrowColor = QColor('#ab272f') self.squareColor = QColor('#80ab272f') elif self.orientation[0] == 'b': self.arrowColor = QColor('#2d71ab') self.squareColor = QColor('#802d71ab') elif self.orientation[0] == 'y': self.arrowColor = QColor('#ac8112') self.squareColor = QColor('#80ac8112') elif self.orientation[0] == 'g': self.arrowColor = QColor('#3a7d4d') self.squareColor = QColor('#803a7d4d') else: self.arrowColor = QColor('#ff8c00') self.squareColor = QColor('#80ff8c00') origin = self.squareCenter(self.arrowStart) target = self.squareCenter(arrowEnd) if origin == target: sq = self.squareAt(origin) file = sq.x() rank = sq.y() color = self.squareColor square = self.SquareHighlight(file, rank, color) # If already exists, remove existing removed = 0 for highlight in reversed(self.highlights): if highlight.Type == self.SquareHighlight.Type and highlight.file == file and \ highlight.rank == rank and highlight.color == color: self.removeHighlight(highlight) removed += 1 if not removed: # Do not allow drawing outside board if not ((file < 3 and rank < 3) or (file < 3 and rank > 10) or (file > 10 and rank < 3) or (file > 10 and rank > 10)): self.addHighlight(square) else: color = self.arrowColor arrow = self.Arrow(origin, target, color) # If already exists, remove existing removed = 0 for highlight in reversed(self.highlights): if highlight.Type == self.Arrow.Type and highlight.origin == origin and \ highlight.target == target and highlight.color == color: self.removeHighlight(highlight) removed += 1 if not removed: # Do not allow drawing outside board fromSquare = self.squareAt(origin) toSquare = self.squareAt(target) fromFile = fromSquare.x() fromRank = fromSquare.y() toFile = toSquare.x() toRank = toSquare.y() if not ((fromFile < 3 and fromRank < 3) or (fromFile < 3 and fromRank > 10) or (fromFile > 10 and fromRank < 3) or (fromFile > 10 and fromRank > 10)) and not \ ((toFile < 3 and toRank < 3) or (toFile < 3 and toRank > 10) or (toFile > 10 and toRank < 3) or (toFile > 10 and toRank > 10)): self.addHighlight(arrow) return elif self.mouseButton == Qt.LeftButton: if point.isNull(): return self.clicked.emit(point) else: return def mousePressEvent(self, event): """Implements mousePressEvent() method. Records drag start position, clicked square and mouse button. Also records arrow start and removes arrows if left-click on empty square.""" self.dragStart = event.pos() self.clickedSquare = self.squareAt(event.pos(), self.orientation[0]) self.mouseButton = event.buttons() self.arrowStart = self.squareAt(event.pos()) # If empty square clicked with left mouse button, remove arrows if event.buttons() == Qt.LeftButton and \ self.board.getData(self.clickedSquare.x(), self.clickedSquare.y()) == ' ': if self.keyModifier == Qt.Key_1: self.removeArrows([QColor('#80ab272f'), QColor('#ab272f')]) elif self.keyModifier == Qt.Key_2: self.removeArrows([QColor('#802d71ab'), QColor('#2d71ab')]) elif self.keyModifier == Qt.Key_3: self.removeArrows([QColor('#80ac8112'), QColor('#ac8112')]) elif self.keyModifier == Qt.Key_4: self.removeArrows([QColor('#803a7d4d'), QColor('#3a7d4d')]) elif self.keyModifier == Qt.Key_0: self.removeArrows([QColor('#80ff8c00'), QColor('#ff8c00')]) else: self.removeArrows() def mouseMoveEvent(self, event): """Implements mouseMoveEvent() method. Executes drag action and gets coordinate of square under mouse.""" # Coordinate help square = self.squareAt(event.pos(), self.orientation[0]) text = chr(square.x() + 97) + str(square.y() + 1) square = self.squareAt(event.pos()) self.coordinate = (square, text) self.update() # Drag action if not event.buttons() == Qt.LeftButton: return if not self.clickedSquare or not self.dragStart: return if (event.pos() - self.dragStart).manhattanLength() < 5: return char = self.board.getData(self.clickedSquare.x(), self.clickedSquare.y()) if char[0] != self.currentPlayer: return if char != ' ': icon = self.piece(char) if icon.isNull(): return self.showLegalMoves() iconPosition = self.squareRect(self.clickedSquare.x(), self.clickedSquare.y(), self.orientation[0]).topLeft() offset = QPoint(event.pos() - iconPosition) # Pixmap shown under cursor while dragging dpr = 2 # device pixel ratio pixmap = icon.pixmap( QSize(self.squareSize.width() * dpr, self.squareSize.height() * dpr)) pixmap.setDevicePixelRatio(dpr) # Serialize drag-drop data into QByteArray data = QByteArray() dataStream = QDataStream(data, QIODevice.WriteOnly) dataStream << icon << offset # Custom MIME data mimeData = QMimeData() mimeData.setData('dragdrop', data) # Drag action drag = QDrag(self) drag.setMimeData(mimeData) drag.setPixmap(pixmap) drag.setHotSpot( QPoint(self.squareSize.width() / 2, self.squareSize.height() / 2)) self.maskedSquare = self.clickedSquare self.dragStarted.emit(self.clickedSquare) drag.exec_() self.maskedSquare = None def dragEnterEvent(self, event): """Implements dragEnterEvent() method.""" if event.mimeData().hasFormat('dragdrop'): if event.source() == self: event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def dragMoveEvent(self, event): """Implements dragMoveEvent() method.""" if event.mimeData().hasFormat('dragdrop'): if event.source() == self: event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def dragLeaveEvent(self, event): """Implements dragLeaveEvent() method.""" # Keep cursor on the board while dragging cursor = QCursor() position = cursor.pos() topLeft = self.mapToGlobal( self.geometry().topLeft()) - self.geometry().topLeft() bottomRight = self.mapToGlobal( self.geometry().bottomRight()) - self.geometry().topLeft() bound = lambda x, l, u: l if x < l else u if x > u else x x = bound(position.x(), topLeft.x() + 1, bottomRight.x() - 1) y = bound(position.y(), topLeft.y() + 1, bottomRight.y() - 1) if x != position.x() or y != position.y(): cursor.setPos(x, y) def dropEvent(self, event): """Implements dropEvent() method. Handles drop action.""" self.removeLegalMoveIndicators() if event.mimeData().hasFormat('dragdrop'): # Read data serialized from the QByteArray data = event.mimeData().data('dragdrop') dataStream = QDataStream(data, QIODevice.ReadOnly) icon = QIcon() offset = QPoint() dataStream >> icon >> offset # Send signal to make the move square = self.squareAt(event.pos(), self.orientation[0]) self.pieceMoved.emit(self.clickedSquare, square) if event.source() == self: event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def addHighlight(self, highlight): """Adds highlight to the list and redraws view.""" self.highlights.append(highlight) self.update() def removeHighlight(self, highlight): """Removes highlight from the list and redraws view.""" try: self.highlights.remove(highlight) self.update() except ValueError: pass def removeHighlightsOfColor(self, color): """Removes all highlights of color.""" for highlight in reversed( self.highlights ): # reversed list, because modifying while looping if not highlight.Type == self.LegalMoveIndicator.Type and highlight.color == color: self.removeHighlight(highlight) def removeArrows(self, colors=None): """Removes all arrows and highlighted squares drawn on the board.""" if colors: for color in colors: self.removeHighlightsOfColor(color) else: colors = [ QColor('#80ff8c00'), QColor('#80ab272f'), QColor('#802d71ab'), QColor('#80ac8112'), QColor('#803a7d4d') ] for highlight in reversed( self.highlights ): # reversed list, because modifying while looping if highlight.Type == self.Arrow.Type: self.removeHighlight(highlight) elif highlight.Type == self.SquareHighlight.Type and highlight.color in colors: self.removeHighlight(highlight) def drawSquareHighlights(self, painter): """Draws all recognized highlights stored in the list.""" for highlight in self.highlights: if highlight.Type == self.SquareHighlight.Type: colors = [ QColor('#80ff8c00'), QColor('#80ab272f'), QColor('#802d71ab'), QColor('#80ac8112'), QColor('#803a7d4d') ] if highlight.color in colors: rect = self.squareRect(highlight.file, highlight.rank) else: rect = self.squareRect(highlight.file, highlight.rank, self.orientation[0]) painter.fillRect(rect, highlight.color) def drawArrows(self, painter): """Draws arrows on the board.""" for highlight in self.highlights: if highlight.Type == self.Arrow.Type: lineWidth = 10 sqSize = self.squareSize painter.setPen( QPen(highlight.color, lineWidth, Qt.SolidLine, Qt.RoundCap)) origin = highlight.origin target = highlight.target dx = target.x() - origin.x() dy = target.y() - origin.y() # Knight jumps if dx == sqSize.width() and dy == -2 * sqSize.height(): corner = QPoint(origin.x(), origin.y() - 2 * sqSize.height()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == 2 * sqSize.width() and dy == -sqSize.height(): corner = QPoint(origin.x() + 2 * sqSize.width(), origin.y()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == 2 * sqSize.width() and dy == sqSize.height(): corner = QPoint(origin.x() + 2 * sqSize.width(), origin.y()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == sqSize.width() and dy == 2 * sqSize.height(): corner = QPoint(origin.x(), origin.y() + 2 * sqSize.height()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == -sqSize.width() and dy == 2 * sqSize.height(): corner = QPoint(origin.x(), origin.y() + 2 * sqSize.height()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == -2 * sqSize.width() and dy == sqSize.height(): corner = QPoint(origin.x() - 2 * sqSize.width(), origin.y()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == -2 * sqSize.width() and dy == -sqSize.height(): corner = QPoint(origin.x() - 2 * sqSize.width(), origin.y()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner elif dx == -sqSize.width() and dy == -2 * sqSize.height(): corner = QPoint(origin.x(), origin.y() - 2 * sqSize.height()) line = QLineF(origin, corner) painter.drawLine(line) origin = corner # Other moves (and second part of knight jump) line = QLineF(origin, target) angle = line.angle() tip = line.p2() line.setLength(line.length() - 2 * lineWidth) painter.drawLine(line) tipOffset = line.p2() leftBase = QLineF() leftBase.setP1(tipOffset) leftBase.setLength(lineWidth) leftBase.setAngle(angle - 90) left = leftBase.p2() rightBase = QLineF() rightBase.setP1(tipOffset) rightBase.setLength(lineWidth) rightBase.setAngle(angle + 90) right = rightBase.p2() arrowHead = QPolygonF([left, right, tip]) path = QPainterPath() path.addPolygon(arrowHead) painter.fillPath(path, QBrush(highlight.color)) def showLegalMoves(self): """Shows legal moves.""" if SETTINGS.value('showlegalmoves'): fromFile = self.clickedSquare.x() fromRank = self.clickedSquare.y() identifier = self.board.getData(fromFile, fromRank) if identifier != ' ' and identifier[0] == self.currentPlayer: color = ['r', 'b', 'y', 'g'].index(identifier[0]) piece = ['P', 'N', 'B', 'R', 'Q', 'K'].index(identifier[1]) + 4 self.addLegalMoveIndicators(piece, fromFile, fromRank, color) def addLegalMoveIndicators(self, piece, fromFile, fromRank, color): """Adds legal move indicators.""" origin = self.board.square(fromFile, fromRank) moves = self.board.getSquares( self.board.legalMoves(piece, origin, color) & self.board.emptyBB) captures = self.board.getSquares( self.board.legalMoves(piece, origin, color) & self.board.occupiedBB) for move in moves: legalMoveIndicator = self.LegalMoveIndicator( QPoint(move[0], move[1])) self.addHighlight(legalMoveIndicator) for capture in captures: legalMoveIndicator = self.LegalMoveIndicator( QPoint(capture[0], capture[1]), True) self.addHighlight(legalMoveIndicator) def removeLegalMoveIndicators(self): """Removes all legal move indicators.""" for highlight in reversed(self.highlights): if highlight.Type == self.LegalMoveIndicator.Type: self.removeHighlight(highlight) def drawLegalMoves(self, painter): """Draws legal move indicators.""" for highlight in reversed(self.highlights): if highlight.Type == self.LegalMoveIndicator.Type: center = self.squareCenter(highlight.square, self.orientation[0]) if highlight.capture: lineWidth = 4 rx = self.squareSize.width() / 2 - lineWidth / 2 ry = rx painter.setPen( QPen(QColor('#40000000'), lineWidth, Qt.SolidLine)) painter.drawEllipse(center, rx, ry) else: rx = self.squareSize.width() / 10 ry = rx painter.setBrush(QColor('#40000000')) painter.setPen(Qt.NoPen) painter.drawEllipse(center, rx, ry) def highlightPlayer(self, player): """Adds highlight for player to indicate turn. Removes highlights for other players if they exist.""" self.addHighlight(self.playerHighlights[player]) for otherPlayer in self.playerHighlights: if otherPlayer != player: try: self.removeHighlight(self.playerHighlights[otherPlayer]) except ValueError: pass def highlightChecks(self): """Adds red square highlight for kings in check.""" checkColor = QColor('#ccff0000') for highlight in reversed( self.highlights ): # reversed list, because modifying while looping if highlight.Type == self.SquareHighlight.Type and highlight.color == checkColor: self.removeHighlight(highlight) for color in range(4): inCheck, (file, rank) = self.board.kingInCheck(color) if inCheck: highlight = self.SquareHighlight(file, rank, checkColor) self.addHighlight(highlight) def resetHighlights(self): """Clears list of highlights and redraws view.""" self.highlights = [] self.update() class PlayerName(QPushButton): """Editable player name label.""" def __init__(self): super().__init__() self.setFixedSize(150, 50) self.setText('Player Name') self.setStyleSheet(""" QPushButton {border: none; font-weight: bold;} QPushButton[player='red'] {color: #bf3b43;} QPushButton[player='blue'] {color: #4185bf;} QPushButton[player='yellow'] {color: #c09526;} QPushButton[player='green'] {color: #4e9161;} """) class PlayerNameEdit(QLineEdit): """Player name edit field.""" focusOut = pyqtSignal() def __init__(self): super().__init__() self.setFixedSize(150, 50) self.setAlignment(Qt.AlignCenter) self.setFrame(False) self.setAttribute(Qt.WA_MacShowFocusRect, 0) self.installEventFilter(self) self.setStyleSheet(""" QLineEdit {font-weight: bold;} QLineEdit[player='red'] {color: #bf3b43;} QLineEdit[player='blue'] {color: #4185bf;} QLineEdit[player='yellow'] {color: #c09526;} QLineEdit[player='green'] {color: #4e9161;} """) def eventFilter(self, object_, event): """Handles focusOut event.""" if event.type() == QEvent.FocusOut: self.focusOut.emit() return False def createPlayerLabels(self): """Adds editable player name labels to board view.""" # Red player self.redName = self.PlayerName() self.redName.setProperty('player', 'red') self.redName.move(550, 650) self.redName.setParent(self) self.redName.show() self.redName.clicked.connect( lambda: self.editPlayerName(self.redNameEdit)) self.redNameEdit = self.PlayerNameEdit() self.redNameEdit.setProperty('player', 'red') self.redNameEdit.move(550, 650) self.redNameEdit.setParent(self) self.redNameEdit.show() self.redNameEdit.setHidden(True) self.redNameEdit.returnPressed.connect( lambda: self.setPlayerName(self.redName)) self.redNameEdit.focusOut.connect( lambda: self.setPlayerName(self.redName)) # Blue player self.blueName = self.PlayerName() self.blueName.setProperty('player', 'blue') self.blueName.move(0, 650) self.blueName.setParent(self) self.blueName.show() self.blueName.clicked.connect( lambda: self.editPlayerName(self.blueNameEdit)) self.blueNameEdit = self.PlayerNameEdit() self.blueNameEdit.setProperty('player', 'blue') self.blueNameEdit.move(0, 650) self.blueNameEdit.setParent(self) self.blueNameEdit.show() self.blueNameEdit.setHidden(True) self.blueNameEdit.returnPressed.connect( lambda: self.setPlayerName(self.blueName)) self.blueNameEdit.focusOut.connect( lambda: self.setPlayerName(self.blueName)) # Yellow player self.yellowName = self.PlayerName() self.yellowName.setProperty('player', 'yellow') self.yellowName.move(0, 0) self.yellowName.setParent(self) self.yellowName.show() self.yellowName.clicked.connect( lambda: self.editPlayerName(self.yellowNameEdit)) self.yellowNameEdit = self.PlayerNameEdit() self.yellowNameEdit.setProperty('player', 'yellow') self.yellowNameEdit.move(0, 0) self.yellowNameEdit.setParent(self) self.yellowNameEdit.show() self.yellowNameEdit.setHidden(True) self.yellowNameEdit.returnPressed.connect( lambda: self.setPlayerName(self.yellowName)) self.yellowNameEdit.focusOut.connect( lambda: self.setPlayerName(self.yellowName)) # Green player self.greenName = self.PlayerName() self.greenName.setProperty('player', 'green') self.greenName.move(550, 0) self.greenName.setParent(self) self.greenName.show() self.greenName.clicked.connect( lambda: self.editPlayerName(self.greenNameEdit)) self.greenNameEdit = self.PlayerNameEdit() self.greenNameEdit.setProperty('player', 'green') self.greenNameEdit.move(550, 0) self.greenNameEdit.setParent(self) self.greenNameEdit.show() self.greenNameEdit.setHidden(True) self.greenNameEdit.returnPressed.connect( lambda: self.setPlayerName(self.greenName)) self.greenNameEdit.focusOut.connect( lambda: self.setPlayerName(self.greenName)) def movePlayerLabels(self, orientation): """Moves player labels when board orientation is changed.""" if orientation == 'b': self.redName.move(550, 0) self.redNameEdit.move(550, 0) self.blueName.move(550, 650) self.blueNameEdit.move(550, 650) self.yellowName.move(0, 650) self.yellowNameEdit.move(0, 650) self.greenName.move(0, 0) self.greenNameEdit.move(0, 0) elif orientation == 'y': self.redName.move(0, 0) self.redNameEdit.move(0, 0) self.blueName.move(550, 0) self.blueNameEdit.move(550, 0) self.yellowName.move(550, 650) self.yellowNameEdit.move(550, 650) self.greenName.move(0, 650) self.greenNameEdit.move(0, 650) elif orientation == 'g': self.redName.move(0, 650) self.redNameEdit.move(0, 650) self.blueName.move(0, 0) self.blueNameEdit.move(0, 0) self.yellowName.move(550, 0) self.yellowNameEdit.move(550, 0) self.greenName.move(550, 650) self.greenNameEdit.move(550, 650) else: # red by default self.redName.move(550, 650) self.redNameEdit.move(550, 650) self.blueName.move(0, 650) self.blueNameEdit.move(0, 650) self.yellowName.move(0, 0) self.yellowNameEdit.move(0, 0) self.greenName.move(550, 0) self.greenNameEdit.move(550, 0) def hideNames(self): """Hides player name labels.""" self.redName.setHidden(True) self.blueName.setHidden(True) self.yellowName.setHidden(True) self.greenName.setHidden(True) def showNames(self): """Shows player name labels.""" self.redName.setHidden(False) self.blueName.setHidden(False) self.yellowName.setHidden(False) self.greenName.setHidden(False) def editPlayerName(self, nameEdit): """Activates player name edit field.""" name = self.sender() name.setHidden(True) nameEdit.setHidden(False) nameEdit.setFocus(True) def setPlayerName(self, name): """Updates player name label and deactivates player name edit field.""" nameEdit = self.sender() s = name.text().split('\n') if len(s) == 2: rating = s[-1] n = nameEdit.text().split(' ') if len(n) > 1: e = n[-1].strip('()') if e.isdigit(): rating = '(' + e + ')' name.setText(' '.join(n[:-1]) + '\n' + rating) else: name.setText(' '.join(n) + '\n' + rating) else: name.setText(' '.join(n) + '\n' + rating) else: rating = None n = nameEdit.text().split(' ') if len(n) > 1: e = n[-1].strip('()') if e.isdigit(): rating = '(' + e + ')' if rating: name.setText(' '.join(n[:-1]) + '\n' + rating) else: name.setText(' '.join(n)) nameEdit.setHidden(True) name.setHidden(False) red = self.redName.text().split('\n') blue = self.blueName.text().split('\n') yellow = self.yellowName.text().split('\n') green = self.greenName.text().split('\n') self.playerNameEdited.emit(red[0], blue[0], yellow[0], green[0]) redRating = red[-1].strip('()') if len(red) > 1 else self.redRating blueRating = blue[-1].strip('()') if len(blue) > 1 else self.blueRating yellowRating = yellow[-1].strip( '()') if len(yellow) > 1 else self.yellowRating greenRating = green[-1].strip( '()') if len(green) > 1 else self.greenRating self.playerRatingEdited.emit(redRating, blueRating, yellowRating, greenRating) def setPlayerNames(self, red, blue, yellow, green): """Sets player names to names obtained from PGN4 file.""" if red == '?': red = 'Player Name' if blue == '?': blue = 'Player Name' if yellow == '?': yellow = 'Player Name' if green == '?': green = 'Player Name' self.redName.setText(red) self.blueName.setText(blue) self.yellowName.setText(yellow) self.greenName.setText(green) self.setPlayerRating(self.redRating, self.blueRating, self.yellowRating, self.greenRating) def setPlayerRating(self, redRating, blueRating, yellowRating, greenRating): """Sets the player rating according to the PGN4 file.""" if redRating != '?': self.redName.setText(self.redName.text() + '\n(' + redRating + ')') if blueRating != '?': self.blueName.setText(self.blueName.text() + '\n(' + blueRating + ')') if yellowRating != '?': self.yellowName.setText(self.yellowName.text() + '\n(' + yellowRating + ')') if greenRating != '?': self.greenName.setText(self.greenName.text() + '\n(' + greenRating + ')')
def main(): """Main function of the game. This function initializes the game and enters the PyGame main loop. """ # Inits PyGame module pygame.init() # Loads Sugar standard cursor a, b, c, d = pygame.cursors.load_xbm("gui/standardcursor.xbm", "gui/standardcursor_mask.xbm") pygame.mouse.set_cursor(a, b, c, d) internal_size = (1200, 825) # The game is designed to work in this size (xo display size) target_size = (900, 619) # The game will be sown in this size, useful for testing in regular PCs with less resolution than xo flags = 0 if olpcgames.ACTIVITY: # Running as Activity target_size = olpcgames.ACTIVITY.game_size #logic.Mesh.init_mesh(log) # Mesh isn't ready in this version else: pass # Uncomment this if want to execute fullscreen on regular PCs # flags = pygame.FULLSCREEN real_screen = pygame.display.set_mode(target_size, flags) # The scale factor beetween internal and target if internal_size == target_size: scale = None internal_screen = real_screen # The game works directly on the real screen else: # Running on regular PC, the screen its scaled to te target_size internal_screen = pygame.Surface(internal_size) scale = (internal_size[0] / float(target_size[0]), internal_size[1] / float(target_size[1]) ) # Creates a new logic game, player names aren't used without mesh game = GameState("Jugador1", "Jugador2") board = Board(internal_screen, game) board.paint_board_elements() pygame.display.update() # This clock is used to keep the game at the desired FPS. clock = pygame.time.Clock() # Main loop update = True # The first time the screen need to be updated running = True while running: # Waits for events, if none the game pauses: # http://wiki.laptop.org/go/Game_development_HOWTO#Reducing_CPU_Load milliseconds = clock.tick(MAX_FPS) # waits if the game is running faster than MAX_FPS events = olpcgames.pausescreen.get_events(SLEEP_TIMEOUT) # Event-management loop with support for pausing after X seconds (20 here) if events: for event in events: if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: running = False if event.type == pygame.MOUSEBUTTONDOWN: if scale: x = event.pos[0] * scale[0] # Multiplies the real coordinates by the scale factor y = event.pos[1] * scale[1] # to get the internal coordinates else: (x, y) = event.pos update = board.processXY(x, y) if event.type == pygame.USEREVENT: if event.code == olpcgames.FILE_READ_REQUEST: game = _read_file(event.filename) log.debug("Loaded:" + game.serialization()) board = Board(internal_screen, game) update = True elif event.code == olpcgames.FILE_WRITE_REQUEST: _save_file(event.filename, game) if event.type > pygame.USEREVENT and event.type <= pygame.USEREVENT + 10: log.debug("New user event") board.user_event(event) update = True if update == True: board.paint_board_elements() if scale: pygame.transform.scale(internal_screen, target_size, real_screen) update = False pygame.display.flip() # Una vez que sale del loop manda la senal de quit para que cierre la ventana pygame.quit()
board_image = pygame.transform.scale(board_image, (window_width, window_height)) screen.blit(board_image, [0, 0]) pygame.display.set_caption("Chessmachine") clock = pygame.time.Clock() gui_board = None def main(screen, draggable_pieces): for event in pygame.event.get(): for i in range(32): draggable_piece = draggable_pieces[i] if draggable_piece != None: gui_board.treat_draggable_piece(screen, draggable_piece, event) for draggable_piece in draggable_pieces: if draggable_piece != None: draggable_piece.update(screen, draggable_pieces, board_image) if __name__ == "__main__": os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() clock = pygame.time.Clock() gui_board = Board(screen, board_image, "Human", "Artificial") #gui_board.game.state.printBoard() state_board = gui_board.game.state.board while 1: main(screen, gui_board.pieces) pygame.display.update() clock.tick(60)