Ejemplo n.º 1
0
class MainWindow(QWidget):
    """
        Main UI Window
    """
    def __init__(self, parent=None):
        """
        Initialize the chess board.
        """
        super().__init__(parent)
        ## NN param set
        self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        print('Processing device: ',self.device)
        self.path = "best_policy.model"
        self.learning_rate   = 0.0001
        self.mcts_iteration = 100
        #self.Chess_read     = CHESS_READ()
        ##
        self.setWindowTitle("GrandmasterFLEX")
        self.resize(1280, 720)
        self.svgWidget = QSvgWidget(parent=self)
        self.svgWidget.setGeometry(10, 10, 700, 700)
        self.boardSize = min(self.svgWidget.width(), self.svgWidget.height())
        self.margin = 0.05 * self.boardSize 
        self.squareSize = (self.boardSize - 2*self.margin)/8
        self.board = chess.Board()
        self.lastmove = None
        self.pieceToMove = [None, None]
        self.drawBoard()
        self.enginePath = "./stockfish.exe"
        self.time = 0.1

        self.pbar = QProgressBar(self)
        self.pbarlabel = QLabel('Training Progress: ')
        self.maxtimelabel = QLabel("Max number of examples from ./Training Games")
        self.engineLabel = QLabel("Selfplay games#")
        self.engineButton = QPushButton("Find move")
        self.moveButton = QPushButton("Make move")
        self.undoButton = QPushButton("Undo move")
        self.testButton = QPushButton("Selfplay")
        self.gendataButton = QPushButton("Generate Dataset")
        self.trainButton = QPushButton("Train AI")
        self.newgameButton = QPushButton("New Game")
        self.undoButton.setMaximumWidth(175)
        self.pathField = QLineEdit()
        self.pathField1 = QLabel("0")
        self.examples = QLineEdit()
        self.engineResult = QLineEdit()
        self.pathField.setText("5")
        self.examples.setText('10000000')
        self.pbar.setValue(0)

        self.main_layout = QHBoxLayout()
        self.tool_layout = QGridLayout()
        ### widget design
        ##QT top row
        self.tool_layout.addWidget(self.engineLabel, 0, 0)
        self.tool_layout.addWidget(self.pathField, 0, 1)
        self.tool_layout.addWidget(self.pathField1, 0, 2) 
        self.tool_layout.addWidget(self.testButton, 0, 3)
        #second row
        self.tool_layout.addWidget(self.maxtimelabel, 1, 0)
        self.tool_layout.addWidget(self.examples, 1, 1)
        self.tool_layout.addWidget(self.gendataButton, 1, 2)
        self.tool_layout.addWidget(self.trainButton, 1, 3)
        #third row
        self.tool_layout.addWidget(self.pbarlabel, 2, 0)
        self.tool_layout.addWidget(self.pbar, 2, 1)
        #4th row
        self.tool_layout.addWidget(self.engineButton, 3, 0)
        self.tool_layout.addWidget(self.moveButton, 3, 1)
        self.tool_layout.addWidget(self.engineResult, 3, 2)
        self.tool_layout.addWidget(self.undoButton, 3, 3)
        self.tool_layout.addWidget(self.newgameButton, 3, 4)
        
        ###
        self.main_layout.addWidget(self.svgWidget, 55)
        self.main_layout.addLayout(self.tool_layout, 45)        
        self.setLayout(self.main_layout)

        self.engineButton.clicked.connect(self.find_move)
        self.moveButton.clicked.connect(self.make_move)
        self.undoButton.clicked.connect(self.undo_move)
        self.testButton.clicked.connect(self.selfplay)
        self.gendataButton.clicked.connect(self.gendata)
        self.trainButton.clicked.connect(self.trainnet)
        self.newgameButton.clicked.connect(self.newgame)
        
        #self.NN         = NEURAL_NETWORK(self.learning_rate, self.path, self.device)
        #self.mcts_tree  = MCTS(self.mcts_iteration, self.NN, self.Chess_read, self.device)
    def updarepbar(epoch1):
        self.pbar.setValue(epoch1)

    def gendata(self):
        numexamples = int(self.examples.text())
        gendata.get_dataset(numexamples)
        print(colored('Model saved','green'))

    def trainnet(self):
        with open("train.py") as f:
            code = compile(f.read(), "train.py", 'exec')
            exec(code)

    def selfplay(self):
        x = self.pathField.text()
        if x == '':
            print('no games')
            return
        else:
            self.itr = 1
            while self.itr <= int(x):
                while not self.board.is_game_over():
                    self.pathField1.setText('#games played: '+ str(self.itr))
                    go = self.make_move()
                    if go =='gameover':
                        self.post()
                        self.itr += 1
                        return
                print("GAME OVER: game: ",str(self.itr))
                self.newgame()

                
    def newgame(self):
        moves = []
        x1 = np.array([0])
        y1 = np.array([0])
        viz.line(x1,y1,update='replace',opts=layoutb,name='GrandmasterFlex - BLACK',win='GrandmasterFlex3')
        viz.line(x1,y1,update='replace',opts=layoutw,name='GrandmasterFlex - WHITE',win='GrandmasterFlex2')
        self.board.reset()
        s.board.reset()
        with open('si.pickle', 'wb') as p:
            pickle.dump(s, p)
        i = 0
        with open('rnd.pickle','wb') as rnd:
            pickle.dump(i,rnd)
        with open('g.pickle','wb')as g:
            moves = []
            pickle.dump(moves, g)

    @Slot(QWidget)
    def mousePressEvent(self, event):
        """
        Handles the left mouse click and enables moving the chess pieces by first clicking on the chess
        piece and then on the target square. 
        """
        if not self.board.is_game_over():
            if event.x() <= self.boardSize and event.y() <= self.boardSize:
                if self.margin<event.x()<self.boardSize-self.margin and self.margin<event.y()<self.boardSize-self.margin:
                    if event.buttons()==Qt.LeftButton:
                        file = int((event.x() - self.margin) / self.squareSize)
                        rank = 7 - int((event.y() - self.margin) / self.squareSize)
                        square = chess.square(file, rank)
                        piece = self.board.piece_at(square)
                        coordinates = "{}{}".format(chr(file + 97), str(rank + 1))
                        if self.pieceToMove[0] is not None:
                            move = chess.Move.from_uci("{}{}".format(self.pieceToMove[1], coordinates))
                            if move in self.board.legal_moves:
                                self.board.push(move)
                                s.board.push(move)
                            self.lastmove = str(self.pieceToMove[1]) + str(coordinates)
                            print('Last Move: ',self.lastmove)
                            piece = None
                            coordinates = None
                            with open('rnd.pickle','rb') as rnd:
                                i = pickle.load(rnd)
                                i = 1 + i
                            with open('rnd.pickle','wb') as rnd:
                                pickle.dump(i,rnd)
                            print(colored("move: " + str(i),'yellow'))
                        self.pieceToMove = [piece, coordinates]
                        self.drawBoard()
                        go = self.make_move()
                        if go == 'gameover':
                            print(colored(Style.BRIGHT + "********************* GAME IS OVER *********************",'red'))
                            self.post()
    
    def drawBoard(self):
        """
        Draw a chess board for the starting position and then redraw it for every move.
        """
        self.svgBoard = self.board._repr_svg_().encode("UTF-8")
        self.svgDrawBoard = self.svgWidget.load(self.svgBoard)  
        return self.svgDrawBoard


    def find_move(self,lastmove):
        """
        Calculate the best move according to Stockfish
        """
        #spinner = Halo(text='SEARCHING MINDSTATE',text_color='cyan', spinner='simpleDotsScrolling',color='cyan')
        #spinner.start()
        with open('si.pickle', 'rb') as f:
            s = pickle.load(f)
        try:
            times = float(self.engineTime.text())
        except:
            times = float(1)
        self.time = times
        #engine = chess.engine.SimpleEngine.popen_uci(self.enginePath)
        #result = engine.play(self.board, chess.engine.Limit(time=self.time))
        print(self.board,'\n',self.lastmove)
        #move, prob = self.mcts_tree.play(self.board, self.lastmove)
        move,s,prob = computer_move(s, v)
        self.engineResult.setText(str(move))
        #engine.quit()
        #spinner.stop()
        return move,s, prob
        


    def make_move(self):
        """
        Finds and plays the best move
        """
        try:
            with open('rnd.pickle','rb') as rnd:
                i = pickle.load(rnd)
                i = 1 + i
        except:
            i = 0
        with open('rnd.pickle','wb') as rnd:
            pickle.dump(i,rnd)
        try:
            move,s,prob = self.find_move(self.lastmove)
            print(colored('move: ' + str(i),'yellow'))
            if (i % 2) == 0:
                prob1 = np.array([float(prob)])
                i1 = np.array([(i/2)])
                #viz.line(prob1,i1,update='append',opts=layoutb,name='GrandmasterFlex - BLACK',win='GrandmasterFlex3')
                plotter.plot('Round', 'Prob', 'Win Probability - Black' , i1, prob)
            else:
                prob1 = np.array([float(prob)])
                i1 = np.array([(i/2)])
                #viz.line(prob1,i1,update='append',opts=layoutw,name='GrandmasterFlex - WHITE',win='GrandmasterFlex2')
                plotter.plot('Round', 'Prob', 'Win Probability - White' , i1, prob)
            #print(move)
            nf3 = chess.Move.from_uci(move)
            #print('uci eq: ',nf3)
            #x = input('waiting')
            with open('g.pickle','rb')as g:
                    moves = pickle.load(g)
                    moves.append(move)
            with open('g.pickle','wb')as g:
                pickle.dump(moves, g)
                print(colored(moves,'cyan'))

            self.board.push(nf3)
            s.board.push(nf3)
            self.drawBoard()
            time.sleep(0.2)
            QApplication.processEvents()
            self.lastmove = move
            with open('si.pickle', 'wb') as p:
                pickle.dump(s, p)
        except:
            print(colored(Style.BRIGHT + "********************* GAME IS OVER *********************",'red'))
            #self.post()
            return 'gameover'
        

    def undo_move(self):
        """
        Undo the last move played on the board
        """
        self.board.pop()
        s = self
        self.drawBoard()

    def post(self):
        game = chess.pgn.Game()
        game.headers["Event"] = "GMFLEX"
        game.headers["Site"] = "local"
        game.headers["Date"] = datetime.now()
        game.headers["White"] = "White"
        game.headers["Black"] = "Black"
        with open('g.pickle','rb')as g:
            moves = pickle.load(g)
            i = 0
            for move in moves:
                i += 1
                if i == 1:
                    print(move)
                    node = game.add_variation(chess.Move.from_uci(move))
                else:
                    node = node.add_variation(chess.Move.from_uci(move))
        with open('si.pickle', 'rb') as f:
            si = pickle.load(f)
            b = si.board
            # game over values
            if b.result() == "1-0":
                game.headers["Result"] = "1-0"
                winner = "WHITE"
            elif b.result() == "0-1":
                game.headers["Result"] = "0-1"
                winner = "BLACK"
            else: 
                winner = "BLACK"
            win = open('winner.txt', 'a')
            stamp = str(datetime.now()).replace(":","_")
            log = open('TrainingGames/'+ stamp +".pgn", 'w')
            print(game, file=log, end="\n\n")
            try:
                sgame = "Final Board:\n" + str(game)
            except:
                print(colored(Style.BRIGHT + "Save Game Fail",'red'))
            win.write(winner + ":\n" + sgame)
            if winner == "BLACK":
                res1 = 0
                res2 = 1
            else:
                res1 = 1
                res2 = 0
        with open('w.pickle','rb')as w:
                wins = pickle.load(w)
        win1 = pd.DataFrame({'W':[res1],'B':[res2],'Winner':[winner]})
        pd.DataFrame.append(wins,win1)
        with open('w.pickle','wb')as w:
            pickle.dump(wins,w)
        with open('rnd.pickle','wb') as rnd:
            pickle.dump(i,rnd)
        with open('g.pickle','wb')as g:
            moves = []
            pickle.dump(moves, g)
    def update(self):
        """Update the gui with the current value."""
                  
        self.drawBoard()
Ejemplo n.º 2
0
class MainWindow(QWidget):
    """
        Main UI Window
    """
    def __init__(self, parent=None):
        """
        Initialize the chess board.
        """
        super().__init__(parent)
        self.setWindowTitle("PyChess")
        self.resize(1280, 720)
        self.svgWidget = QSvgWidget(parent=self)
        self.svgWidget.setGeometry(10, 10, 700, 700)
        self.boardSize = min(self.svgWidget.width(), self.svgWidget.height())
        self.margin = 0.05 * self.boardSize
        self.squareSize = (self.boardSize - 2 * self.margin) / 8
        self.board = chess.Board()
        self.pieceToMove = [None, None]
        self.drawBoard()
        self.enginePath = "Use double \ instead of \ when on Windows system."
        self.time = 0.1

        self.maxtimelabel = QLabel("Max. time per move(in s):")
        self.engineLabel = QLabel("Enter path to engine:")
        self.engineButton = QPushButton("Find move")
        self.moveButton = QPushButton("Make move")
        self.undoButton = QPushButton("Undo move")
        self.undoButton.setMaximumWidth(175)
        self.pathField = QLineEdit()
        self.engineTime = QLineEdit()
        self.engineResult = QLineEdit()
        self.pathField.setText(
            "Use double \ instead of \ when on Windows system.")

        self.main_layout = QHBoxLayout()
        self.tool_layout = QGridLayout()

        self.tool_layout.addWidget(self.engineLabel, 0, 0)
        self.tool_layout.addWidget(self.pathField, 0, 1)
        self.tool_layout.addWidget(self.maxtimelabel, 1, 0)
        self.tool_layout.addWidget(self.engineTime, 1, 1)
        self.tool_layout.addWidget(self.engineButton, 2, 0)
        self.tool_layout.addWidget(self.engineResult, 2, 1)
        self.tool_layout.addWidget(self.moveButton, 3, 0)
        self.tool_layout.addWidget(self.undoButton, 3, 1)

        self.main_layout.addWidget(self.svgWidget, 55)
        self.main_layout.addLayout(self.tool_layout, 45)
        self.setLayout(self.main_layout)

        self.engineButton.clicked.connect(self.find_move)
        self.moveButton.clicked.connect(self.make_move)
        self.undoButton.clicked.connect(self.undo_move)

    @Slot(QWidget)
    def mousePressEvent(self, event):
        """
        Handles the left mouse click and enables moving the chess pieces by first clicking on the chess
        piece and then on the target square. 
        """
        if event.x() <= self.boardSize and event.y() <= self.boardSize:
            if self.margin < event.x(
            ) < self.boardSize - self.margin and self.margin < event.y(
            ) < self.boardSize - self.margin:
                if event.buttons() == Qt.LeftButton:
                    file = int((event.x() - self.margin) / self.squareSize)
                    rank = 7 - int((event.y() - self.margin) / self.squareSize)
                    square = chess.square(file, rank)
                    piece = self.board.piece_at(square)
                    coordinates = "{}{}".format(chr(file + 97), str(rank + 1))
                    if self.pieceToMove[0] is not None:
                        move = chess.Move.from_uci("{}{}".format(
                            self.pieceToMove[1], coordinates))
                        if move in self.board.legal_moves:
                            self.board.push(move)
                        piece = None
                        coordinates = None
                    self.pieceToMove = [piece, coordinates]
                    self.drawBoard()

    def drawBoard(self):
        """
        Draw a chess board for the starting position and then redraw it for every move.
        """
        self.svgBoard = self.board._repr_svg_().encode("UTF-8")
        self.svgDrawBoard = self.svgWidget.load(self.svgBoard)
        return self.svgDrawBoard

    def find_move(self):
        """
        Calculate the best move according to Stockfish
        """
        self.enginePath = self.pathField.text()
        self.time = float(self.engineTime.text())
        engine = chess.engine.SimpleEngine.popen_uci(self.enginePath)
        result = engine.play(self.board, chess.engine.Limit(time=self.time))
        self.engineResult.setText(str(result.move))
        engine.quit()
        return result.move

    def make_move(self):
        """
        Finds and plays the best move
        """
        move = self.find_move()
        self.board.push(move)
        self.drawBoard()

    def undo_move(self):
        """
        Undo the last move played on the board
        """
        self.board.pop()
        self.drawBoard()