python GUI编程(3)2048

作者: Lykit01 | 来源:发表于2019-04-17 13:35 被阅读4次

    这次我们用tkinter函数式编程来实现小游戏2048,下面是我的源码,还可以再优化:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import tkinter as tk
    import tkinter.messagebox as mb
    import random,copy
    
    root=tk.Tk()
    root.title('2048')
    root.geometry('360x330')
    color_dict={0:'white'}
    score_dict={}
    scorevar=tk.StringVar()
    board=[[0,0,0,0] for i in range(4)]
    col=['grey','pink','yellow','brown','red','violet','crimson','fuchsia']*100
    for num in range(1,100):
        color_dict[2**num]=col[num-1]
        score_dict[2**num]=num-1
    #gui
    def display(board):
        for i in range(4):
            for j in range(4):
                lb=tk.Label(root,text='' if board[i][j]==0 else board[i][j],bg=color_dict[board[i][j]],width=7,height=3)
                lb.place(x=(55+5)*(j+1),y=(55+5)*(i+1),anchor='nw')
    
    #移动与计算
    def available_dot(arr):
        res=[]
        for i in range(len(arr)):
            for j in range(len(arr[0])):
                if arr[i][j]==0:
                    res.append([i,j])
        return res
    
    def spown_dot(board,num):
        sample=random.sample(available_dot(board),num)
        for i in range(num):
            x, y = sample[i]
            board[x][y] = 2
    
    def to_text(board):
        text = ''
        for i in range(len(board)):
            for j in range(len(board[0])):
                text += str(board[i][j]) + ' '
            text += '\n'
        return text
    
    def can_move(board):
        for i in range(1,len(board)-1):
            for j in range(1,len(board[0])-1):
                if board[i][j]==board[i-1][j] or board[i][j]==board[i+1][j] or board[i][j]==board[i][j-1] or board[i][j]==board[i][j+1]:
                    return True
        if board[0][0]==board[0][1] or board[0][0]==board[1][0]:
            return True
        if board[3][0]==board[3][1] or board[3][0]==board[2][0]:
            return True
        if board[0][3]==board[1][3] or board[0][3]==board[0][2]:
            return True
        if board[3][3]==board[3][2] or board[3][3]==board[2][3]:
            return True
        if board[1][0]==board[2][0] or board[0][1]==board[0][2] or board[3][1]==board[3][2] or board[3][1]==board[3][2]:
            return True
        return False
    
    def left_arrow(event):
        last_board=copy.deepcopy(board)
        for i in range(4):
            tmp=[]
            for j in range(4):
                if board[i][j]!=0:
                    tmp.append(board[i][j])
            for k in range(len(tmp)-1):
                if tmp[k]!=0 and tmp[k]==tmp[k+1]:
                    tmp[k]*=2
                    get_score(tmp[k])
                    tmp=tmp[:k+1]+tmp[k+2:]+[0]
            tmp+=[0]*(4-len(tmp))
            board[i]=tmp
        if last_board!=board:
            spown_dot(board,1)
            #var.set(to_text(board))
            display(board)
        elif not available_dot(board):#动不了时游戏结束
            if not can_move(board):
                mb.showinfo(title='游戏结束',message='得分:%s'%scorevar.get())
                restart()
    
    def right_arrow(event):
        last_board=copy.deepcopy(board)
        for i in range(4):
            tmp=[]
            for j in range(4):
                if board[i][j]!=0:
                    tmp.append(board[i][j])
            for k in range(len(tmp)-1,0,-1):
                if tmp[k]!=0 and tmp[k]==tmp[k-1]:
                    tmp[k]*=2
                    get_score(tmp[k])
                    tmp=[0]+tmp[:k-1]+tmp[k:]
            tmp=[0]*(4-len(tmp))+tmp
            board[i]=tmp
        if last_board!=board:
            spown_dot(board,1)
            #var.set(to_text(board))
            display(board)
        elif not available_dot(board):#动不了时游戏结束
            if not can_move(board):
                mb.showinfo(title='游戏结束',message='得分:%s'%scorevar.get())
                restart()
    
    def up_arrow(event):
        last_board=copy.deepcopy(board)
        for j in range(4):
            tmp=[]
            for i in range(4):
                if board[i][j]!=0:
                    tmp.append(board[i][j])
            for k in range(len(tmp)-1):
                if tmp[k]!=0 and tmp[k]==tmp[k+1]:
                    tmp[k]*=2
                    get_score(tmp[k])
                    tmp=tmp[:k+1]+tmp[k+2:]+[0]
            tmp += [0] * (4 - len(tmp))
            for i in range(4):
                board[i][j]=tmp[i]
        if last_board!=board:
            spown_dot(board,1)
            #var.set(to_text(board))
            display(board)
        elif not available_dot(board):#动不了时游戏结束
            if not can_move(board):
                mb.showinfo(title='游戏结束',message='得分:%s'%scorevar.get())
                restart()
    
    def down_arrow(event):
        last_board=copy.deepcopy(board)
        for j in range(4):
            tmp=[]
            for i in range(4):
                if board[i][j]!=0:
                    tmp.append(board[i][j])
            for k in range(len(tmp)-1,0,-1):
                if tmp[k]!=0 and tmp[k]==tmp[k-1]:
                    tmp[k]*=2
                    get_score(tmp[k])
                    tmp=[0]+tmp[:k-1]+tmp[k:]
            tmp = [0] * (4 - len(tmp))+tmp
            for i in range(4):
                board[i][j]=tmp[i]
        if last_board!=board:
            spown_dot(board,1)
            #var.set(to_text(board))
            display(board)
        elif not available_dot(board):#动不了时游戏结束
            if not can_move(board):
                mb.showinfo(title='游戏结束',message='得分:%s'%scorevar.get())
                restart()
    
    def get_score(num):
        now_score=int(scorevar.get())
        now_score+=score_dict[num]
        scorevar.set(str(now_score))
    
    def restart():#重新开始
        global board
        board=[[0,0,0,0] for i in range(4)]
        spown_dot(board,2)
        display(board)
        scorevar.set(0)
    
    #initiate
    board=[[0,0,0,0] for i in range(4)]
    spown_dot(board,2)
    display(board)
    scorevar.set(0)
    
    #debug
    #var=tk.StringVar()
    #var.set(to_text(board))
    #board_lb=tk.Label(root,textvariable=var,bg='darkcyan',fg='white',width=8,height=5)
    board_lb=tk.Label(root)
    board_lb.place(x=300,y=200,anchor='nw')
    board_lb.focus_set()#只有当组件获得焦点的时候才能接收键盘事件
    board_lb.bind('<Left>',left_arrow)
    board_lb.bind('<Right>',right_arrow)
    board_lb.bind('<Up>',up_arrow)
    board_lb.bind('<Down>',down_arrow)
    
    score_nt=tk.Label(root,text='得分',width=5,height=2)
    score_nt.place(x=100,y=20,anchor='nw')
    score_lb=tk.Label(root,textvariable=scorevar,width=5,height=2)
    score_lb.place(x=140,y=20,anchor='nw')
    maker_lb=tk.Label(root,text='@Hue Zhang',width=10,height=2)
    maker_lb.place(x=180,y=320,anchor='center')
    
    restartbtn=tk.Button(root,text='重新开始',bg='lightgrey',width=6,height=1,command=restart)
    restartbtn.place(x=220,y=20,anchor='nw')
    
    root.mainloop()
    
    

    这种函数式编程中的global变量很难管理,很容易出错,我们换用一个高级的ui包PyQt5,下面用pyqt改写上面的程序,也增添了一些小功能。下面是pyqt5的教程:pyqt5的中文教程
    我的源码:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import sys
    from PyQt5.QtWidgets import (QMainWindow,QWidget,QPushButton,
        QApplication,QDesktopWidget,qApp,QAction,QLabel,QMessageBox,QToolTip)
    from PyQt5.QtGui import QIcon,QFont
    from PyQt5.QtCore import Qt
    import random,copy,math
    class Game(QMainWindow):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            #other property
            self.color_dict={}
            self.score_dict={}
            self.color_dict[0]='white'
            col = ['lightgrey','grey', 'pink', 'yellow', 'brown', 'red', 'violet', 'crimson', 'fuchsia'] * 100
            for num in range(1, 100):
                self.color_dict[2 ** num] = col[num - 1]
                self.score_dict[2 ** num] = num - 1
            self.first2048=False#第一次2048
    
            #main feature
            self.font = QFont('SansSerif', 10)
            QToolTip.setFont(self.font)
            self.setGeometry(300, 300, 500, 550)
            self.setWindowTitle("2048")
            self.setWindowIcon(QIcon('./2p.ico'))
            self.center()
            self.setToolTip('<b>Made by @Hue Zhang</b>')
            self.statusbar = self.statusBar()
            self.statusbar.showMessage('按WASD来移动')
    
            self.scorent=QLabel(self)
            self.scorent.resize(50, 50)
            self.scorent.move(80,10)
            self.scorent.setFont(self.font)
            self.scorent.setText('得分')
            self.scoreboard = QLabel(self)
            self.scoreboard.resize(100, 50)
            self.scoreboard.move(180, 10)
            self.scoreboard.setFont(self.font)
    
            restartbtn = QPushButton('重新开始', self)
            restartbtn.setToolTip('重新开始一局游戏')
            restartbtn.resize(restartbtn.sizeHint())
            restartbtn.move(280, 10)
            restartbtn.clicked.connect(self.restart)
    
            #self.wholetextboard=QLabel(self)#for debug
            #self.wholetextboard.resize(120,120)
            #self.wholetextboard.move(10000,10000)
            #self.wholetextboard.setFont(self.font)
            #初始化界面
            self.lbs_init()#label不能覆盖
            self.restart()
    
            self.show()
    
        def initBoard(self):
            self.wholeboard=[[0,0,0,0] for i in range(4)]
            self.spown_dot(2)
            #self.wholetextboard.setText(self.board_to_text(self.wholeboard))
            self.score=0
            self.scoreboard.setText('0')
    
        def restart(self):
            self.initBoard()
            self.lbs_update()
    
        def lbs_init(self):
            self.lbs = [[0, 0, 0, 0] for i in range(4)]
            for i in range(4):
                for j in range(4):
                    self.lbs[i][j] = QLabel(self)
                    self.lbs[i][j].setFont(self.font)
                    self.lbs[i][j].setAlignment(Qt.AlignCenter)#设置文字居中
                    self.lbs[i][j].resize(100, 100)
                    self.lbs[i][j].move(110 * j + 30, 110 *i+70)
    
        def lbs_update(self):
            for i in range(4):
                for j in range(4):
                    if not self.first2048 and self.wholeboard[i][j]==2048:
                        self.first2048=True
                        congrats = QMessageBox.about(self, '恭喜!', '你已经达成2048成就!')
                    col=self.color_dict[self.wholeboard[i][j]]
                    if self.wholeboard[i][j] == 0:
                        txt=''
                    else:
                        txt=str(self.wholeboard[i][j])
                    self.lbs[i][j].setText(txt)
                    self.lbs[i][j].setStyleSheet('background-color:%s'%col)
    
        def keyPressEvent(self,e):
            self.statusbar.showMessage('按WASD来移动')
            if e.key()==Qt.Key_Escape:
                self.close()
            elif e.key()==Qt.Key_W:
                self.toUp()
            elif e.key() == Qt.Key_S:
                self.toDown()
            elif e.key()==Qt.Key_A:#方向键暂时没找到方法获取焦点
                self.toLeft()
            elif e.key()==Qt.Key_D:
                self.toRight()
    
        def toLeft(self):
            self.last_board=copy.deepcopy(self.wholeboard)
            for i in range(4):
                tmp = []
                for j in range(4):
                    if self.wholeboard[i][j] != 0:
                        tmp.append(self.wholeboard[i][j])
                for k in range(len(tmp) - 1):
                    if tmp[k] != 0 and tmp[k] == tmp[k + 1]:
                        tmp[k] *= 2
                        self.get_score(tmp[k])
                        tmp = tmp[:k + 1] + tmp[k + 2:] + [0]
                tmp += [0] * (4 - len(tmp))
                self.wholeboard[i] = tmp
            self.check_board()
    
        def toRight(self):
            self.last_board=copy.deepcopy(self.wholeboard)
            for i in range(4):
                tmp = []
                for j in range(4):
                    if self.wholeboard[i][j] != 0:
                        tmp.append(self.wholeboard[i][j])
                for k in range(len(tmp) - 1, 0, -1):
                    if tmp[k] != 0 and tmp[k] == tmp[k - 1]:
                        tmp[k] *= 2
                        self.get_score(tmp[k])
                        tmp = [0] + tmp[:k - 1] + tmp[k:]
                tmp = [0] * (4 - len(tmp)) + tmp
                self.wholeboard[i] = tmp
            self.check_board()
    
        def toUp(self):
            self.last_board = copy.deepcopy(self.wholeboard)
            for j in range(4):
                tmp = []
                for i in range(4):
                    if self.wholeboard[i][j] != 0:
                        tmp.append(self.wholeboard[i][j])
                for k in range(len(tmp) - 1):
                    if tmp[k] != 0 and tmp[k] == tmp[k + 1]:
                        tmp[k] *= 2
                        self.get_score(tmp[k])
                        tmp = tmp[:k + 1] + tmp[k + 2:] + [0]
                tmp += [0] * (4 - len(tmp))
                for i in range(4):
                    self.wholeboard[i][j] = tmp[i]
            self.check_board()
    
        def toDown(self):
            self.last_board = copy.deepcopy(self.wholeboard)
            for j in range(len(self.wholeboard)):
                tmp = []
                for i in range(len(self.wholeboard[0])):
                    if self.wholeboard[i][j] != 0:
                        tmp.append(self.wholeboard[i][j])
                for k in range(len(tmp) - 1, 0, -1):
                    if tmp[k] != 0 and tmp[k] == tmp[k - 1]:
                        tmp[k] *= 2
                        self.get_score(tmp[k])
                        tmp = [0] + tmp[:k - 1] + tmp[k:]
                tmp = [0] * (4 - len(tmp)) + tmp
                for i in range(4):
                    self.wholeboard[i][j] = tmp[i]
            self.check_board()
    
        def check_board(self):
            if self.last_board != self.wholeboard:
                self.spown_dot(1)
                #self.wholetextboard.setText(self.board_to_text(self.wholeboard))
                self.lbs_update()
            elif not self.available_dot(self.wholeboard):  # 动不了时游戏结束
                if not self.can_move(self.wholeboard):
                    ggabout = QMessageBox.about(self, 'Game Over', '你已经无法移动了,得分:%s,点击OK重新开始。'%self.score)
                    self.restart()
            else:#无法向四个方向移动
                self.statusbar.showMessage('无法合并,请尝试其他方向')
    
        def board_to_text(self,board):
            text = ''
            for i in range(len(board)):
                for j in range(len(board[0])):
                    text += str(board[i][j]) + ' '
                text += '\n'
            return text
    
        def spown_dot(self,num):
            sample = random.sample(self.available_dot(self.wholeboard), num)
            for i in range(num):
                x, y = sample[i]
                self.wholeboard[x][y] = 2
    
        def available_dot(self,arr):
            res = []
            for i in range(len(arr)):
                for j in range(len(arr[0])):
                    if arr[i][j] == 0:
                        res.append([i, j])
            return res
    
        def can_move(self,board):
            for i in range(1, len(board) - 1):
                for j in range(1, len(board[0]) - 1):
                    if board[i][j] == board[i - 1][j] or board[i][j] == board[i + 1][j] or board[i][j] == board[i][j - 1] or \
                            board[i][j] == board[i][j + 1]:
                        return True
            if board[0][0] == board[0][1] or board[0][0] == board[1][0]:
                return True
            if board[3][0] == board[3][1] or board[3][0] == board[2][0]:
                return True
            if board[0][3] == board[1][3] or board[0][3] == board[0][2]:
                return True
            if board[3][3] == board[3][2] or board[3][3] == board[2][3]:
                return True
            if board[1][0] == board[2][0] or board[0][1] == board[0][2] or board[3][1] == board[3][2] or board[3][1] == \
                    board[3][2]:
                return True
            return False
    
        def get_score(self,score):
            self.score+=self.score_dict[score]
            self.scoreboard.setText(str(self.score))
    
        def center(self):
            qr=self.frameGeometry()
            cp=QDesktopWidget().availableGeometry().center()
            qr.moveCenter(cp)
            self.move(qr.topLeft())
    
        def closeEvent(self,event):
            reply=QMessageBox.question(self,'提示','确认要退出吗?',
                QMessageBox.Yes | QMessageBox.No,QMessageBox.No)
            if reply==QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()
    
    if __name__ == '__main__':
        app=QApplication(sys.argv)
        ex=Game()
        sys.exit(app.exec_())
    

    相关文章

      网友评论

        本文标题:python GUI编程(3)2048

        本文链接:https://www.haomeiwen.com/subject/hlzgwqtx.html