Python实现2048小游戏

2048小游戏也算是一款好玩的益智休闲小游戏,下面本博主用 python 语言将该游戏复现,感兴趣的小伙伴点击 关注 哦!

同时博主还用 java 语言复现了该游戏,可点击以下链接浏览博主的另一篇文章:JAVA实现2048小游戏 !


目录

一、效果

二、教程

1、文件结构

2、configs.py

3、main.py

4、Game2048.py

三、代码

1、configs.py

2、main.py

3、Game2048.py


一、效果

2048小游戏是一款比较流行的数字游戏,游戏规则如下:

每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。

    

ps: 博主就没有添加成功的图片了,实在是因为技术不行,试完了几次均没有凑成 2048 ...因此放上了凑成256成功的图片

二、教程

1、文件结构

2、configs.py

常用参数:

(1) 窗口设置

A. screen_width:游戏窗口的宽

B. screen_height:游戏窗口的高

(2) 方块设置

A. block_gap:方块与方块之间的间隙

B. block_size:方块的大小

C. block_arc:方块四角的弧度

3、main.py

(1) 调用Game2048类,创建2048游戏示例game

game = Game2048(screen_width, screen_height, block_gap, block_size, block_arc)

(2) 开始游戏

game.Form()

4、Game2048.py

(1) 导入包

import os
import sys
import numpy
import random
import pygame

(2) 类的创建

类名:Game2048

class Game2048(object):

(3) 类的初始化

A. 变量

a. screen_width: 窗口的宽 400

b. screen_height:窗口的高 500

c. block_gap: 方块间隙 10

d. block_size:方块大小 86

e. block_arc:方块的弧度

f. size:矩阵的大小 4 * 4

g. martix:初始化矩阵 4 * 4 

h. form:窗体

i. is_over:游戏是否结束

j. is_success:游戏是否成功

k. score:分数

l. isadd:是否添加数字

m. block_color:方块颜色

n. nums_color:数字颜色

o. title_font:窗口标题字体类型及大小

p. score_font:分数字体类型及大小

q. tips_font:说明字体类型及大小

r. font:数字字体类型及大小

B. 代码

def __init__(self, screen_width, screen_height, block_gap, block_size, block_arc):
    """ 窗口 """
    self.screen_width = screen_width  # 窗口的宽 400
    self.screen_height = screen_height  # 窗口的高 500
    self.block_gap = block_gap  # 方块间隙 10
    self.block_size = block_size  # 方块大小 86
    self.block_arc = block_arc  # 方块的弧度
    self.size = 4  # 矩阵 4 * 4
    self.martix = []  # 初始化矩阵 4 * 4 的 0 矩阵
    self.form = ''

    """ 其他 """
    self.is_over = False  # 游戏是否结束
    self.is_success = False  # 游戏是否成功
    self.score = 0  # 分数
    self.isadd = True  # 是否添加数字
    self.block_color = {  # 方块颜色
        0: (205, 193, 180),
        2: (238, 228, 218),
        4: (237, 224, 200),
        8: (242, 177, 121),
        16: (245, 149, 99),
        32: (246, 124, 95),
        64: (246, 94, 59),
        128: (237, 207, 114),
        256: (237, 204, 97),
        512: (237, 200, 80),
        1024: (237, 197, 63),
        2048: (237, 194, 46)
    }
    self.nums_color = {
        0: (205, 193, 180),
        2: (0, 0, 0),
        4: (0, 0, 0),
        8: (255, 255, 255),
        16: (255, 255, 255),
        32: (255, 255, 255),
        64: (255, 255, 255),
        128: (255, 255, 255),
        256: (255, 255, 255),
        512: (255, 255, 255),
        1024: (255, 255, 255),
        2048: (255, 255, 255)
    }

    """ 字体 """
    self.title_font = ''  # 窗口标题字体类型及大小: 2048
    self.score_font = ''  # 分数字体类型及大小
    self.tips_font = ''  # 说明字体类型及大小
    self.font = ''  # 数字字体

(4) 窗体的设置

  • init(): 初始化所有导入的 pygame 模块
  • display.set_caption(title): 设置窗口的标题
  • display.set_mode(): 初始化一个准备显示的窗口或屏幕
  • display.update(): 使绘制的显示到窗口上
def Form(self):
    pygame.init()  # 初始化所有导入的 pygame 模块
    pygame.display.set_caption("Game2048")  # 窗口标题
    os.environ['SDL_VIDEO_CENTERED'] = '1'  # 窗口居中显示
    self.form = pygame.display.set_mode([self.screen_width, self.screen_height], 0, 0)  # 窗口大小
    self.InitGame()  # 矩阵的初始化

    while True:
        self.Action()  # 用户行为: 按键/鼠标
        self.Paint()  # 表格绘制
        pygame.display.update()  # 使绘制的显示到窗口上

(5) 用户行为:按键/鼠标

  • pygame.event.get(): 获取所有消息并将其从队列中删除
  • pygame.QUIT: 窗口右上角的红 ×
  • sys.exit()函数是通过抛出异常的方式来终止进程的
  • pygame.KEYDOWN 按下键盘时
  • pygame.KEYUP 释放键盘时
  • K_ESCAPE: ESC
  • K_UP: ↑
  • K_DOWN: ↓
  • K_LEFT: ←
  • K_RIGHT: → 
def Action(self):
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            sys.exit() 
        elif event.type == pygame.KEYDOWN:

            """ 重新开始游戏 """
            if event.key == pygame.K_ESCAPE:
                self.InitGame()  # 游戏初始化

            """ ↑ """
            if event.key == pygame.K_UP and self.is_over == False:
                self.MoveUp()
      
            """ ↓ """
            if event.key == pygame.K_DOWN and self.is_over == False:
                self.MoveDown()

            """ ← """
            if event.key == pygame.K_LEFT and self.is_over == False:
                self.MoveLeft()
 
            """ → """
            if event.key == pygame.K_RIGHT and self.is_over == False:
                self.MoveRight()

(6) 游戏初始化

def InitGame(self):
    self.score = 0
    self.is_over = False
    self.is_success = False
    self.martix = numpy.zeros([self.size, self.size])

    # 随机生成两个数
    for i in range(2):
        self.isadd = True
        self.CreatNum()

(7) 随机在一个位置生成一个数字

  • 2, 4出现概率3:1
  • random.randint(m, n): 随机生成[m, n]
def CreatNum(self):
    list = self.GetEmpty()  # 获取空白方格下标
    if list and self.isadd:
        """ 随机生成的数字 """
        value = 4 if random.randint(0, 3) % 3 == 0 else 2

        """ 获取随机位置下标 """
        x, y = random.sample(list, 1)[0]

        """ 在随机位置上生成随机数字 """
        self.martix[x][y] = value

        self.isadd = False

(8) 获取空白方格

def GetEmpty(self):
    list = []
    for i in range(4):
        for j in range(4):
            if self.martix[i][j] == 0:
                list.append([i, j])
    return list

(9) 向上移动

def MoveUp(self):
    """ Move Up """
    """
    向上移动,只需考虑第二行到第四行
    共分为两种情况:
    1、当前数字上边无空格,即上边值不为 0
        a. 当前数字与上边数字相等,合并
        b. 当前数字与上边数字不相等,continue
    2、当前数字上边有空格,即上边值为 0, 上移
    """
    for j in range(4):
        index = 0
        for i in range(1, 4):
            if self.martix[i][j] > 0:
                if self.martix[i][j] == self.martix[index][j]:
                    # 当前数字 == 上边数字
                    """ 分数: 当前数字 + 上边数字
                        数值: 上边数字 = 上边数字 + 当前数字, 当前数字 = 0 """
                    self.score += self.martix[i][j] + self.martix[index][j]
                    self.martix[index][j] = self.martix[i][j] + self.martix[index][j]
                    self.martix[i][j] = 0
                    index += 1
                    self.isadd = True
                # 当前数字与上边数字不相等,continue 可以省略不写
                elif self.martix[index][j] == 0:
                    # 当前数字上边有0
                    """ 分数: 不变
                        数值: 上边数字 = 当前数字, 当前数字 = 0 """
                    self.martix[index][j] = self.martix[i][j]
                    self.martix[i][j] = 0
                    self.isadd = True
                else:
                    index += 1
                    if self.martix[index][j] == 0:
                        # index相当于慢指针,j相当于快指针
                        # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                        # 上边数字 = 0
                        """ 分数: 不变
                            数值: 上边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[index][j] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True

(10) 向下移动

def MoveDown(self):
    """ Move Down """
    """
    向下移动,只需考虑第一列到第三列
    共分为两种情况:
    1、当前数字下边无空格,即下边值不为 0
        a. 当前数字与下边数字相等,合并
        b. 当前数字与下边数字不相等,continue
    2、当前数字下边有空格,即下边值为 0, 下移
    """
    for j in range(4):
        index = 3
        for i in range(2, -1, -1):
            if self.martix[i][j] > 0:
                if self.martix[i][j] == self.martix[index][j]:
                    # 当前数字 == 下边数字
                    """ 分数: 当前数字 + 下边数字
                        数值: 下边数字 = 下边数字 + 当前数字, 当前数字 = 0 """
                    self.score += self.martix[i][j] + self.martix[index][j]
                    self.martix[index][j] = self.martix[i][j] + self.martix[index][j]
                    self.martix[i][j] = 0
                    index -= 1
                    self.isadd = True
                # 当前数字与下边数字不相等,continue 可以省略不写
                elif self.martix[index][j] == 0:
                    # 当前数字下边有0
                    """ 分数: 不变
                        数值: 下边数字 = 当前数字, 当前数字 = 0 """
                    self.martix[index][j] = self.martix[i][j]
                    self.martix[i][j] = 0
                    self.isadd = True
                else:
                    index -= 1
                    if self.martix[index][j] == 0:
                        # index相当于慢指针,j相当于快指针
                        # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                        # 下边数字 = 0
                        """ 分数: 不变
                            数值: 下边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[index][j] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True

(11) 向左移动

def MoveLeft(self):
    """
    Move Left
    """
    """
    向左移动,只需考虑第二列到第四列
    共分为两种情况:
    1、当前数字左边无空格,即左边值不为 0
        a. 当前数字与左边数字相等,合并
        b. 当前数字与左边数字不相等,continue
    2、当前数字左边有空格,即左边值为 0, 左移
    """
    for i in range(4):
        index = 0
        for j in range(1, 4):
            if self.martix[i][j] > 0:
                if self.martix[i][j] == self.martix[i][index]:
                    # 当前数字 == 左边数字
                    """ 分数: 当前数字 + 左边数字
                        数值: 左边数字 = 左边数字 + 当前数字, 当前数字 = 0 """
                    self.score += self.martix[i][j] == self.martix[i][index]
                    self.martix[i][index] = self.martix[i][j] + self.martix[i][index]
                    self.martix[i][j] = 0
                    index += 1
                    self.isadd = True
                # 当前数字与左边数字不相等,continue 可以省略不写
                elif self.martix[i][index] == 0:
                    # 当前数字左边有0
                    """ 分数: 不变
                        数值: 左边数字 = 当前数字, 当前数字 = 0 """
                    self.martix[i][index] = self.martix[i][j]
                    self.martix[i][j] = 0
                    self.isadd = True
                else:
                    index += 1
                    if self.martix[i][index] == 0:
                        # index相当于慢指针,j相当于快指针
                        # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                        # 左边数字 = 0
                        """ 分数: 不变
                            数值: 左边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[i][index] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True

(12) 向右移动

def MoveRight(self):
    """
    Move Right
    """
    """
    向右移动,只需考虑第一列到第三列
    共分为两种情况:
    1、当前数字右边无空格,即右边值不为 0
        a. 当前数字与右边数字相等,合并
        b. 当前数字与右边数字不相等,continue
    2、当前数字右边有空格,即右边值为 0, 右移
    """
    for i in range(4):
        index = 3
        for j in range(2, -1, -1):
            if self.martix[i][j] > 0:
                if self.martix[i][j] == self.martix[i][index]:
                    # 当前数字 == 右边数字
                    """ 分数: 当前数字 + 右边数字
                        数值: 右边数字 = 右边数字 + 当前数字, 当前数字 = 0 """
                    self.score += self.martix[i][j] + self.martix[i][index]
                    self.martix[i][index] = self.martix[i][j] + self.martix[i][index]
                    self.martix[i][j] = 0
                    index -= 1
                    self.isadd = True
                # 当前数字与左边数字不相等,continue 可以省略不写
                elif self.martix[i][index] == 0:
                    # 当前数字右边有0
                    """ 分数: 不变
                        数值: 右边数字 = 当前数字, 当前数字 = 0 """
                    self.martix[i][index] = self.martix[i][j]
                    self.martix[i][j] = 0
                    self.isadd = True
                else:
                    index -= 1
                    if self.martix[i][index] == 0:
                        # index相当于慢指针,j相当于快指针
                        # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                        # 右边数字 = 0
                        """ 分数: 不变
                            数值: 右边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[i][index] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True

(13) 判断游戏是否结束

def JudgeGameOver(self):
    # 当空白空格不为空时,即游戏未结束
    zerolist = self.GetEmpty()
    if zerolist:
        return False

    # 当空白方格为空时,判断是否存在可合并的方格
    for i in range(3):
        for j in range(3):
            if self.martix[i][j] == self.martix[i][j + 1]:
                return False
            if self.martix[i][j] == self.martix[i + 1][j]:
                return False

    # 若不满足以上两种情况,则游戏结束
    return True

(14)  判断游戏是否成功

def JudgeGameSuccess(self):
    # 检查是否有2048
    if self.martix.max() == 2048:
        return True
    return False

(15) 绘制表格

A. 游戏背景

  • fill(color): 填充某一种颜色
self.form.fill((220, 220, 220))

B. 初始化字体

pygame.font.init()

C. 添加标题

  • pygame.font.Font.render(): 在一个新 Surface 对象上绘制文本
self.title_font = pygame.font.SysFont('幼圆', 50, True)
title_text = self.title_font.render('2048', True, (0, 0, 0))
self.form.blit(title_text, (50, 10))

D. 添加分数:得分:0

pygame.draw.rect(self.form, (128, 128, 128), (250, 0, 120, 60))
self.score_font = pygame.font.SysFont('幼圆', 28, True)
score_text = self.score_font.render('得 分', True, (0, 0, 0))
self.form.blit(score_text, (275, 0))

digtial_score = self.score_font.render(str(int(self.score)), True, (255, 250, 250))
self.form.blit(digtial_score, (280, 30))

E. 添加游戏说明

self.tips_font = pygame.font.SysFont('simsunnsimsun', 20)
tips_text = self.tips_font.render('操作: ↑ ↓ ← →, 按esc键重新开始', True, (0, 0, 0))
self.form.blit(tips_text, (25, 70))

F. 绘制方格

for i in range(4):
    for j in range(4):
        # (x, y) 方块的初始位置
        x = j * self.block_size + (j + 1) * self.block_gap
        y = i * self.block_size + (i + 1) * self.block_gap
        # 绘制方块
        value = int(self.martix[i][j])
        pygame.draw.rect(self.form, self.block_color[value], (x + 5, y + 100, self.block_size, self.block_size),
                         border_radius=self.block_arc)

        # 数字字体即大小
        if value < 10:
            self.font = pygame.font.SysFont('simsunnsimsun', 46, True)  # 数字2、4、8
            value_text = self.font.render(str(value), True, self.nums_color[value])
            self.form.blit(value_text, (x + 35, y + 120))
        elif value < 100:
            self.font = pygame.font.SysFont('simsunnsimsun', 40, True)  # 数字16, 32, 64
            value_text = self.font.render(str(value), True, self.nums_color[value])
            self.form.blit(value_text, (x + 25, y + 120))
        elif value < 1000:
            self.font = pygame.font.SysFont('simsunnsimsun', 34, True)  # 数字128, 256, 512
            value_text = self.font.render(str(value), True, self.nums_color[value])
            self.form.blit(value_text, (x + 15, y + 120))
        else:
            self.font = pygame.font.SysFont('simsunnsimsun', 28, True)  # 数字1024, 2048
            value_text = self.font.render(str(value), True, self.nums_color[value])
            self.form.blit(value_text, (x + 5, y + 120))

# 新增数字
self.CreatNum()

G. 如果游戏结束

self.is_over = self.JudgeGameOver()
if self.is_over:
    over_font = pygame.font.SysFont("simsunnsimsun", 60, True)
    str_text = over_font.render('Game Over!', True, (255, 255, 255))
    self.form.blit(str_text, (30, 220))

H. 如果游戏成功

self.is_success = self.JudgeGameSuccess()
if self.is_success:
    success_font = pygame.font.SysFont("simsunnsimsun", 60, True)
    str_text = success_font.render('Successful!', True, (178, 34, 34))
    self.form.blit(str_text, (10, 220))

三、代码

1、configs.py

import argparse

def parse_args():

    parser = argparse.ArgumentParser(description='Game 2048')

    # Form
    """
    screen_width: Width of the form
    screen_height: Height of the form
    """
    parser.add_argument('--screen_width', default=400)
    parser.add_argument('--screen_height', default=500)

    # Block
    """
    block_gap: Gap between two blocks
    block_size: Size of a block
    block_arc: Arc of a block
    """
    parser.add_argument('--block_gap', default=10)
    parser.add_argument('--block_size', default=86)
    parser.add_argument('--block_arc', default=10)

    return parser.parse_args()

2、main.py

import configs
from Game2048 import Game2048

def main(args):
    """
    screen_width: Width of the form
    screen_height: Height of the form
    block_gap: Gap between two blocks
    block_size: Size of a block
    """
    screen_width = args.screen_width
    screen_height = args.screen_height
    block_gap = args.block_gap
    block_size = args.block_size
    block_arc = args.block_arc

    game = Game2048(screen_width, screen_height, block_gap, block_size, block_arc)
    game.Form()


if __name__ == '__main__':
    args = configs.parse_args()
    main(args)

3、Game2048.py

import os
import sys
import numpy
import random
import pygame

"""
Form(): 窗口的设置
Action(): 用户行为: 按键/鼠标
InitGame(): 游戏初始化
CreatNum(): 随机在一个位置生成一个数
GetEmpty(): 获取空白方格
MoveUp(): 向上移动
MoveDown(): 向下移动
MoveLeft(): 向左移动
MoveRight(): 向右移动
JudgeGameOver(): 判断游戏是否结束
JudgeGameSuccess(): 判断游戏是否成功
Paint(): 绘制表格
"""


class Game2048(object):
    # 初始化函数
    def __init__(self, screen_width, screen_height, block_gap, block_size, block_arc):
        """
        :param screen_width: Width of the form
        :param screen_height: Height of the form
        :param block_gap: Gap between two blocks
        :param block_size: Size of a block
        :param size: Dimension of matrix
        :param martix: Zero matrix
        :param is_over: Sign of the end of the game
        :param is_success: Sign of the success of the game
        :param form: The form
        :param score: score
        :param title_font: Title type and size of form
        :param score_font: Scores type and size
        :param tips_font: Tips type and type
        :param font: The numberes
        :param isadd: Add number or not
        """
        """ 窗口 """
        self.screen_width = screen_width  # 窗口的宽 400
        self.screen_height = screen_height  # 窗口的高 500
        self.block_gap = block_gap  # 方块间隙 10
        self.block_size = block_size  # 方块大小 86
        self.block_arc = block_arc  # 方块的弧度
        self.size = 4  # 矩阵 4 * 4
        self.martix = []  # 初始化矩阵 4 * 4 的 0 矩阵
        self.form = ''

        """ 其他 """
        self.is_over = False  # 游戏是否结束
        self.is_success = False  # 游戏是否成功
        self.score = 0  # 分数
        self.isadd = True  # 是否添加数字
        self.block_color = {  # 方块颜色
            0: (205, 193, 180),
            2: (238, 228, 218),
            4: (237, 224, 200),
            8: (242, 177, 121),
            16: (245, 149, 99),
            32: (246, 124, 95),
            64: (246, 94, 59),
            128: (237, 207, 114),
            256: (237, 204, 97),
            512: (237, 200, 80),
            1024: (237, 197, 63),
            2048: (237, 194, 46)
        }
        self.nums_color = {
            # 0: (0, 0, 0),
            0: (205, 193, 180),
            2: (0, 0, 0),
            4: (0, 0, 0),
            8: (255, 255, 255),
            16: (255, 255, 255),
            32: (255, 255, 255),
            64: (255, 255, 255),
            128: (255, 255, 255),
            256: (255, 255, 255),
            512: (255, 255, 255),
            1024: (255, 255, 255),
            2048: (255, 255, 255)
        }

        """ 字体 """
        self.title_font = ''  # 窗口标题字体类型及大小: 2048
        self.score_font = ''  # 分数字体类型及大小
        self.tips_font = ''  # 说明字体类型及大小
        self.font = ''  # 数字字体

    # 窗口的设置
    def Form(self):
        """
        init(): 初始化所有导入的 pygame 模块
        display.set_caption(title): 设置窗口的标题
        display.set_mode(): 初始化一个准备显示的窗口或屏幕
        display.update(): 使绘制的显示到窗口上
        """
        pygame.init()  # 初始化所有导入的 pygame 模块
        pygame.display.set_caption("Game2048")  # 窗口标题
        os.environ['SDL_VIDEO_CENTERED'] = '1'  # 窗口居中显示
        self.form = pygame.display.set_mode([self.screen_width, self.screen_height], 0, 0)  # 窗口大小
        self.InitGame()  # 矩阵的初始化

        while True:
            self.Action()  # 用户行为: 按键/鼠标
            self.Paint()  # 表格绘制
            pygame.display.update()  # 使绘制的显示到窗口上

    # 用户行为: 按键/鼠标
    def Action(self):
        for event in pygame.event.get():  # pygame.event.get(): 获取所有消息并将其从队列中删除
            if event.type == pygame.QUIT:  # pygame.QUIT: 窗口右上角的红 ×
                sys.exit()  # sys.exit()函数是通过抛出异常的方式来终止进程的
            elif event.type == pygame.KEYDOWN:
                """
                pygame.KEYDOWN 按下键盘时
                pygame.KEYUP 释放键盘时
                """
                """ 
                K_ESCAPE: ESC
                K_UP: ↑
                K_DOWN: ↓
                K_LEFT: ←
                K_RIGHT: →
                """

                """ 重新开始游戏 """
                if event.key == pygame.K_ESCAPE:
                    # print('ESC')
                    self.InitGame()  # 游戏初始化

                """ ↑ """
                if event.key == pygame.K_UP and self.is_over == False:
                    # print('UP')
                    self.MoveUp()
                    # self.CreatNum()

                """ ↓ """
                if event.key == pygame.K_DOWN and self.is_over == False:
                    # print('DOWN')
                    self.MoveDown()
                    # self.CreatNum()

                """ ← """
                if event.key == pygame.K_LEFT and self.is_over == False:
                    # print('LEFT')
                    self.MoveLeft()
                    # self.CreatNum()

                """ → """
                if event.key == pygame.K_RIGHT and self.is_over == False:
                    # print('RIGHT')
                    self.MoveRight()
                    # self.CreatNum()

    # 游戏初始化
    def InitGame(self):
        self.score = 0
        self.is_over = False
        self.is_success = False
        self.martix = numpy.zeros([self.size, self.size])

        # 随机生成两个数
        for i in range(2):
            self.isadd = True
            self.CreatNum()

    # 随机在一个位置生成一个数
    def CreatNum(self):

        list = self.GetEmpty()  # 获取空白方格下标
        if list and self.isadd:
            """ 随机生成的数字 """
            # 2, 4出现概率3:1
            # random.randint(m, n): 随机生成[m, n]
            value = 4 if random.randint(0, 3) % 3 == 0 else 2

            """ 获取随机位置下标 """
            x, y = random.sample(list, 1)[0]

            """ 在随机位置上生成随机数字 """
            self.martix[x][y] = value

            self.isadd = False

            # print('CreatNum: {}'.format(value), (x, y))
            # print(self.martix)

    # 获取空白方格
    def GetEmpty(self):
        list = []
        for i in range(4):
            for j in range(4):
                if self.martix[i][j] == 0:
                    list.append([i, j])
        return list

    # 向上移动
    def MoveUp(self):
        # print('up')
        """ Move Up """
        """
        向上移动,只需考虑第二行到第四行
        共分为两种情况:
        1、当前数字上边无空格,即上边值不为 0
            a. 当前数字与上边数字相等,合并
            b. 当前数字与上边数字不相等,continue
        2、当前数字上边有空格,即上边值为 0, 上移
        """
        for j in range(4):
            index = 0
            for i in range(1, 4):
                if self.martix[i][j] > 0:
                    if self.martix[i][j] == self.martix[index][j]:
                        # 当前数字 == 上边数字
                        """ 分数: 当前数字 + 上边数字
                            数值: 上边数字 = 上边数字 + 当前数字, 当前数字 = 0 """
                        self.score += self.martix[i][j] + self.martix[index][j]
                        self.martix[index][j] = self.martix[i][j] + self.martix[index][j]
                        self.martix[i][j] = 0
                        index += 1
                        self.isadd = True
                    # 当前数字与上边数字不相等,continue 可以省略不写
                    elif self.martix[index][j] == 0:
                        # 当前数字上边有0
                        """ 分数: 不变
                            数值: 上边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[index][j] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True
                    else:
                        index += 1
                        if self.martix[index][j] == 0:
                            # index相当于慢指针,j相当于快指针
                            # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                            # 上边数字 = 0
                            """ 分数: 不变
                                数值: 上边数字 = 当前数字, 当前数字 = 0 """
                            self.martix[index][j] = self.martix[i][j]
                            self.martix[i][j] = 0
                            self.isadd = True
        # print('up')
        # print(self.martix)

    # 向下移动
    def MoveDown(self):
        # print('down')
        """ Move Down """
        """
        向下移动,只需考虑第一列到第三列
        共分为两种情况:
        1、当前数字下边无空格,即下边值不为 0
            a. 当前数字与下边数字相等,合并
            b. 当前数字与下边数字不相等,continue
        2、当前数字下边有空格,即下边值为 0, 下移
        """
        for j in range(4):
            index = 3
            for i in range(2, -1, -1):
                if self.martix[i][j] > 0:
                    if self.martix[i][j] == self.martix[index][j]:
                        # 当前数字 == 下边数字
                        """ 分数: 当前数字 + 下边数字
                            数值: 下边数字 = 下边数字 + 当前数字, 当前数字 = 0 """
                        self.score += self.martix[i][j] + self.martix[index][j]
                        self.martix[index][j] = self.martix[i][j] + self.martix[index][j]
                        self.martix[i][j] = 0
                        index -= 1
                        self.isadd = True
                    # 当前数字与下边数字不相等,continue 可以省略不写
                    elif self.martix[index][j] == 0:
                        # 当前数字下边有0
                        """ 分数: 不变
                            数值: 下边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[index][j] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True
                    else:
                        index -= 1
                        if self.martix[index][j] == 0:
                            # index相当于慢指针,j相当于快指针
                            # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                            # 下边数字 = 0
                            """ 分数: 不变
                                数值: 下边数字 = 当前数字, 当前数字 = 0 """
                            self.martix[index][j] = self.martix[i][j]
                            self.martix[i][j] = 0
                            self.isadd = True

        # print('down')
        # print(self.martix)

    # 向左移动
    def MoveLeft(self):
        # print('left')
        """
        Move Left
        """
        """
        向左移动,只需考虑第二列到第四列
        共分为两种情况:
        1、当前数字左边无空格,即左边值不为 0
            a. 当前数字与左边数字相等,合并
            b. 当前数字与左边数字不相等,continue
        2、当前数字左边有空格,即左边值为 0, 左移
        """
        for i in range(4):
            index = 0
            for j in range(1, 4):
                if self.martix[i][j] > 0:
                    if self.martix[i][j] == self.martix[i][index]:
                        # 当前数字 == 左边数字
                        """ 分数: 当前数字 + 左边数字
                            数值: 左边数字 = 左边数字 + 当前数字, 当前数字 = 0 """
                        self.score += self.martix[i][j] == self.martix[i][index]
                        self.martix[i][index] = self.martix[i][j] + self.martix[i][index]
                        self.martix[i][j] = 0
                        index += 1
                        self.isadd = True
                    # 当前数字与左边数字不相等,continue 可以省略不写
                    elif self.martix[i][index] == 0:
                        # 当前数字左边有0
                        """ 分数: 不变
                            数值: 左边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[i][index] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True
                    else:
                        index += 1
                        if self.martix[i][index] == 0:
                            # index相当于慢指针,j相当于快指针
                            # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                            # 左边数字 = 0
                            """ 分数: 不变
                                数值: 左边数字 = 当前数字, 当前数字 = 0 """
                            self.martix[i][index] = self.martix[i][j]
                            self.martix[i][j] = 0
                            self.isadd = True
        # print('left')
        # print(self.martix)

    # 向右移动
    def MoveRight(self):
        # print('right')
        """
        Move Right
        """
        """
        向右移动,只需考虑第一列到第三列
        共分为两种情况:
        1、当前数字右边无空格,即右边值不为 0
            a. 当前数字与右边数字相等,合并
            b. 当前数字与右边数字不相等,continue
        2、当前数字右边有空格,即右边值为 0, 右移
        """
        for i in range(4):
            index = 3
            for j in range(2, -1, -1):
                if self.martix[i][j] > 0:
                    if self.martix[i][j] == self.martix[i][index]:
                        # 当前数字 == 右边数字
                        """ 分数: 当前数字 + 右边数字
                            数值: 右边数字 = 右边数字 + 当前数字, 当前数字 = 0 """
                        self.score += self.martix[i][j] + self.martix[i][index]
                        self.martix[i][index] = self.martix[i][j] + self.martix[i][index]
                        self.martix[i][j] = 0
                        index -= 1
                        self.isadd = True
                    # 当前数字与左边数字不相等,continue 可以省略不写
                    elif self.martix[i][index] == 0:
                        # 当前数字右边有0
                        """ 分数: 不变
                            数值: 右边数字 = 当前数字, 当前数字 = 0 """
                        self.martix[i][index] = self.martix[i][j]
                        self.martix[i][j] = 0
                        self.isadd = True
                    else:
                        index -= 1
                        if self.martix[i][index] == 0:
                            # index相当于慢指针,j相当于快指针
                            # 也就是说快指针和慢指针中间可能存在一个以上的空格,或者index和j并未相邻
                            # 右边数字 = 0
                            """ 分数: 不变
                                数值: 右边数字 = 当前数字, 当前数字 = 0 """
                            self.martix[i][index] = self.martix[i][j]
                            self.martix[i][j] = 0
                            self.isadd = True
        # print('right')
        # print(self.martix)

    # 判断游戏是否结束
    def JudgeGameOver(self):
        # 当空白空格不为空时,即游戏未结束
        zerolist = self.GetEmpty()
        if zerolist:
            return False

        # 当空白方格为空时,判断是否存在可合并的方格
        for i in range(3):
            for j in range(3):
                if self.martix[i][j] == self.martix[i][j + 1]:
                    return False
                if self.martix[i][j] == self.martix[i + 1][j]:
                    return False

        # 若不满足以上两种情况,则游戏结束
        return True

    # 判断游戏是否成功
    def JudgeGameSuccess(self):
        # 检查是否有2048
        if self.martix.max() == 2048:
            return True
        return False

    # 绘制表格
    def Paint(self):
        """ 游戏背景 """
        # fill(color): 填充某一种颜色
        self.form.fill((220, 220, 220))

        """ 字体设置 """
        # 初始化字体
        pygame.font.init()
        # 添加标题
        # f = pygame.font.get_fonts()  #: 获取字体样式
        # pygame.font.Font.render(): 在一个新 Surface 对象上绘制文本
        self.title_font = pygame.font.SysFont('幼圆', 50, True)
        title_text = self.title_font.render('2048', True, (0, 0, 0))
        self.form.blit(title_text, (50, 10))

        # 添加分数: 得分: 0
        pygame.draw.rect(self.form, (128, 128, 128), (250, 0, 120, 60))
        self.score_font = pygame.font.SysFont('幼圆', 28, True)
        score_text = self.score_font.render('得 分', True, (0, 0, 0))
        self.form.blit(score_text, (275, 0))

        digtial_score = self.score_font.render(str(int(self.score)), True, (255, 250, 250))
        self.form.blit(digtial_score, (280, 30))

        # 添加游戏说明
        self.tips_font = pygame.font.SysFont('simsunnsimsun', 20)
        tips_text = self.tips_font.render('操作: ↑ ↓ ← →, 按esc键重新开始', True, (0, 0, 0))
        self.form.blit(tips_text, (25, 70))

        """ 绘制方格 """
        for i in range(4):
            for j in range(4):
                # (x, y) 方块的初始位置
                x = j * self.block_size + (j + 1) * self.block_gap
                y = i * self.block_size + (i + 1) * self.block_gap
                # 绘制方块
                value = int(self.martix[i][j])
                # print(value)
                pygame.draw.rect(self.form, self.block_color[value], (x + 5, y + 100, self.block_size, self.block_size),
                                 border_radius=self.block_arc)

                # 数字字体即大小
                if value < 10:
                    self.font = pygame.font.SysFont('simsunnsimsun', 46, True)  # 数字2、4、8
                    value_text = self.font.render(str(value), True, self.nums_color[value])
                    self.form.blit(value_text, (x + 35, y + 120))
                elif value < 100:
                    self.font = pygame.font.SysFont('simsunnsimsun', 40, True)  # 数字16, 32, 64
                    value_text = self.font.render(str(value), True, self.nums_color[value])
                    self.form.blit(value_text, (x + 25, y + 120))
                elif value < 1000:
                    self.font = pygame.font.SysFont('simsunnsimsun', 34, True)  # 数字128, 256, 512
                    value_text = self.font.render(str(value), True, self.nums_color[value])
                    self.form.blit(value_text, (x + 15, y + 120))
                else:
                    self.font = pygame.font.SysFont('simsunnsimsun', 28, True)  # 数字1024, 2048
                    value_text = self.font.render(str(value), True, self.nums_color[value])
                    self.form.blit(value_text, (x + 5, y + 120))

        # 新增数字
        self.CreatNum()

        """ 如果游戏结束 """
        self.is_over = self.JudgeGameOver()
        if self.is_over:
            over_font = pygame.font.SysFont("simsunnsimsun", 60, True)
            str_text = over_font.render('Game Over!', True, (255, 255, 255))
            self.form.blit(str_text, (30, 220))

        """ 如果游戏成功 """
        self.is_success = self.JudgeGameSuccess()
        if self.is_success:
            success_font = pygame.font.SysFont("simsunnsimsun", 60, True)
            str_text = success_font.render('Successful!', True, (178, 34, 34))
            self.form.blit(str_text, (10, 220))

猜你喜欢

转载自blog.csdn.net/weixin_45666660/article/details/113768010