2048是一个休闲游戏。规则:每次控制所有方块向一个方向移动,若有两个数字相同,则合并(即得到和)。每次操作后,会在随机在一个空白的方格处随机生成一个2或者4。若玩家凑出2048的方块,则游戏胜利。如果16个格子(4*4)全部填满且无法合并,则游戏结束。

 

# -*- coding: utf-8 -*-
# @Time : 2020/12/15 16:02
# @Author : Zhenghui Lyu
# @File : myfunction.py
# @Software: PyCharm
import random
from tkinter import *
from tkinter import messagebox as msgbox

v = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]


def align(vlist, direction):
    """沿着direction方向对齐vlist中数字"""
    for i in range(vlist.count(0)):
        vlist.remove(0)  # 移除列表中0元素
    zeros = [0 for x in range(4 - len(vlist))]  # 空位补几个0数量
    if direction == 'left':  # 右侧补若干个0
        vlist.extend(zeros)
    else:
        vlist[:0] = zeros  # 左侧补若干个0


def addsame(vlist, direction):
    """查找相邻数字,相同则合并,原数字翻倍,原数字旁元素变0"""
    score = 0
    if direction == 'left':  # 左合并
        for i in [0, 1, 2]:
            if vlist[i] == vlist[i + 1] != 0:
                vlist[i] *= 2
                vlist[i + 1] = 0
                score += vlist[i]
                return {'bool': True, 'score': score}
    else:
        for i in [3, 2, 1]:  # 右合并
            if vlist[i] == vlist[i - 1] != 0:
                vlist[i] *= 2
                vlist[i - 1] = 0
                score += vlist[i]
                return {'bool': True, 'score': score}
    return {'bool': False, 'score': score}  # 无合并


def handle(vlist, direction):
    """处理一行数据,调用align对齐,调用addsame合并与算此次得分,"""
    increment = 0
    align(vlist, direction)
    result = addsame(vlist, direction)
    increment += result['score']
    align(vlist, direction)  # 游戏机制,对齐合并后,在对齐一次
    return increment


def isover():
    """判断游戏是否结束:1矩阵中无0(没有空白块),且没有相同元素可以合并"""
    N = 0  # 统计0的个数
    global v
    for q in v:  # v为矩阵
        N += q.count(0)
    if N != 0:
        return False
    else:
        for row in range(4):
            flag = islistover(v[row])
            if flag == False:
                return False
        for col in range(4):  # 判断列
            vlist = [v[row][col] for row in range(4)]  # 列复制到列表中处理
            flag = islistover(vlist)
            if flag == False:
                return False
    return True


def islistover(vlist):
    """判断列表是否还可以合并,若有相同元素还可以合并,则False"""
    for i in [0, 1, 2]:
        if vlist[i] == vlist[i + 1] and vlist[i + 1] != 0:
            return False
    return True


def addelement(N):
    """将随机数num,添加到随机k区域"""
    num = random.choice([2, 2, 2, 4])
    k = random.randrange(1, N + 1)
    n = 0
    for i in range(4):
        for j in range(4):
            if v[i][j] == 0:
                n += 1
                if n == k:
                    v[i][j] = num
                    break


def operation(v, op):  # v是矩阵,op是移动方向
    totalscore = 0
    gameover = False
    direction = 'left'
    print(op)
    if op == 'Left':
        direction = 'left'
        for row in range(4):
            totalscore += handle(v[row], direction)
    elif op == 'Right':
        direction = 'right'
        for row in range(4):
            totalscore += handle(v[row], direction)
    elif op == 'Up':
        direction = 'left'
        for col in range(4):
            vList = [v[row][col] for row in range(4)]
            totalscore += handle(vList, direction)
            for row in range(4):
                v[row][col] = vList[row]
    elif op == 'Down':
        direction = 'right'
        for col in range(4):
            vList = [v[row][col] for row in range(4)]
            totalscore += handle(vList, direction)
            for row in range(4):
                v[row][col] = vList[row]
    N = 0
    for q in v:
        N += q.count(0)
    if N != 0:
        addelement(N)
    if isover():
        gameover = True
    return {'游戏状态': gameover, '得分': totalscore}


def init(v):
    for i in range(4):
        v[i] = [random.choice([0, 0, 0, 2, 2, 4]) for x in v[i]]


def drawgameimage():
    global x, y
    for i in range(0, 4):
        for j in range(0, 4):
            m = v[i][j]
            n = 0
            while m > 1:
                n += 1
                m = m / 2
            img1 = imgs[n]
            cv.create_image((j * 120 + 70, i * 120 + 70), image=img1)
            cv.pack()


def callback(event):
    global score
    print('按下键:', event.char)
    KeyCode = event.keysym
    result = operation(v, KeyCode)
    drawgameimage()
    score += result['得分']
    root.title('得分:' + str(score))
    if result['游戏状态']:
        print('游戏结束,你是失败了')
        msgbox.showinfo('游戏结束', '你总得分是:' + str(score))
    else:
        if score >= 2048:
            print('游戏结束,你赢了!')
            msgbox.showinfo('游戏结束', '你赢了!!')


init(v)
score = 0
root = Tk()
root.title('2048')
imgs = [PhotoImage(file=x) for x in
        ["0.gif", "2.gif", "4.gif", "8.gif", "16.gif", "32.gif", "64.gif", "128.gif", "256.gif", "512.gif", "1024.gif",
         "2048.gif", "4096.gif"]]
cv = Canvas(root, bg='green', width=500, height=500)
drawgameimage()
cv.bind('<KeyPress>', callback)
cv.pack()
cv.focus_set()
root.mainloop()

 

注意图片要转换gif格式,tkinter只支持gif格式。