小秩学数据分析数据蛙数据分析每周作业

python GUI编程(3)2048

2019-04-17  本文已影响4人  Lykit01

这次我们用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_())
上一篇 下一篇

猜你喜欢

热点阅读