使用Python 制作2048 游戏
在本文中,我们将通过 Python 代码和逻辑来设计一款您在智能手机上经常玩的 2048 游戏。如果您对游戏不熟悉,强烈建议您先玩一下游戏,以便了解游戏的基本功能。
如何玩2048:
1.有一个4*4的网格,可以填充任意数字。最初,两个随机单元格中填充有 2。休息单元是空的。
2.我们必须按四个键中的任意一个来上、下、左、右移动。当我们按下任意键时,单元格的元素会沿该方向移动,这样,如果该特定行(向左或向右移动的情况下)或列(向上和向下移动的情况下)包含任何两个相同的数字,它们就会得到加起来,该方向的极端单元用该数字填充自身,其余单元再次变空。
3.网格压缩后,任何随机的空单元格都会被 2 填充。
4.按照上述过程,我们必须将任意单元格中的元素相加,使其加倍,得到 2048。如果我们能够做到这一点,我们就赢了。
5.但是,如果在游戏过程中没有剩余的空单元格可以用新的 2 填充,则游戏结束。
在上面的过程中,您可以看到 2048 游戏图形用户界面的快照。但所有的逻辑都在主代码中。因此,为了单独理解其背后的逻辑,我们可以假设上面的网格是一个 4*4 矩阵(具有四行四列的列表)。您可以在下面看到上述游戏在没有 GUI 的情况下进行输入和输出的方法。
例子 :
代码语言:javascript复制命令如下:
'W' 或 'w' : 向上移动
'S' 或 's' : 下移
'A' 或 'a' :向左移动
'D' 或 'd' :向右移动
[0,0,0,0]
[0,0,0,0]
[0,0,0,0]
[0,0,2,0]
按命令:a
游戏尚未结束
[0,0,0,2]
[0,0,0,0]
[0,0,0,0]
[2, 0, 0, 0]
按命令:s
游戏尚未结束
[0,0,0,0]
[0,0,0,0]
[0,0,2,0]
[2, 0, 0, 2]
按命令:d
游戏尚未结束
[0,0,0,0]
[0,0,0,0]
[2, 0, 0, 2]
[0,0,0,4]
按命令:a
游戏尚未结束
[0,2,0,0]
[0,0,0,0]
[4,0,0,0]
[4,0,0,0]
按命令:s
游戏尚未结束
[0,0,0,0]
[0,0,0,0]
[0,0,0,0]
[8,2,0,2]
...
而这一系列的输入输出将会一直持续下去,直到我们输或赢!
编程方法:
- 我们将设计每个逻辑功能,例如我们正在执行向左滑动,然后我们将通过反转矩阵并执行向左滑动来将其用于向右滑动。
- 可以通过转置然后向左移动来完成向上移动。
- 向下移动可以通过右移转置来完成。
- 程序中的所有逻辑都在注释中详细解释了。强烈建议仔细阅读所有评论。
下面有两个 python 文件,一个是 2048.py,其中包含主要驱动程序代码,另一个是logic.py,其中包含所有使用的函数。应该在 2048.py
中导入logic.py才能使用这些函数。只需将这两个文件放在同一个文件夹中,然后运行 2048.py 即可完美运行。
logic.py:
代码语言:javascript复制# logic.py
# 导入到2048.py文件中
# 导入随机包
# 用于生成随机数的方法 numbers.
import random
# 初始化游戏/网格的函数在开始时
def start_game():
# 声明一个空列表 添加4个具有四个元素的列表,每个元素都为0。
mat =[]
for i in range(4):
mat.append([0] * 4)
# 为用户提供打印控制
print("Commands are as follows : ")
print("'W' or 'w' : Move Up")
print("'S' or 's' : Move Down")
print("'A' or 'a' : Move Left")
print("'D' or 'd' : Move Right")
# 调用函数添加 每一步后在网格中新增一个2
add_new_2(mat)
return mat
# 在任意空单元格中添加新的2的函数网格
def add_new_2(mat):
# 为行和列选择一个随机索引。
r = random.randint(0, 3)
c = random.randint(0, 3)
# 当循环遇到随机选择的单元格为空(或者包含零)时,循环将会终止。
while(mat[r] != 0):
r = random.randint(0, 3)
c = random.randint(0, 3)
# 我们将在那个空白的随机单元格中放置一个2。
mat[r] = 2
# 获取当前的函数
# 开始游戏
def get_current_state(mat):
# 如果任何单元格包含2048,我们就赢了
for i in range(4):
for j in range(4):
if(mat[i][j]== 2048):
return 'WON'
# 如果我们仍然有至少一个空单元格游戏还没有结束
for i in range(4):
for j in range(4):
if(mat[i][j]== 0):
return 'GAME NOT OVER'
# 或者如果现在没有空单元格但是,如果向左、向右、向上或向下移动后,任何两个单元格合并并创建一个空的单元格,则游戏还未结束
for i in range(3):
for j in range(3):
if(mat[i][j]== mat[i 1][j] or mat[i][j]== mat[i][j 1]):
return 'GAME NOT OVER'
for j in range(3):
if(mat[3][j]== mat[3][j 1]):
return 'GAME NOT OVER'
for i in range(3):
if(mat[i][3]== mat[i 1][3]):
return 'GAME NOT OVER'
# 否则我们就输掉了比赛
return 'LOST'
# 所有下面定义的函数 都是用于左交换初始状态的。
# 压缩网格的函数在每一步之前和之后合并单元格之后。
def compress(mat):
# 用于确定是否发生了任何更改的布尔变量
changed = False
# 空网格
new_mat = []
# 所有单元格为空
for i in range(4):
new_mat.append([0] * 4)
# 在这里,我们将移动条目每个单元格到它的极限左边逐行循环遍历行
for i in range(4):
pos = 0
# 循环遍历每一列在相应的行中
for j in range(4):
if(mat[i][j] != 0):
# 如果单元格非空,则将其数字移至该行中前一个空单元格,由pos变量表示。
new_mat[i][pos] = mat[i][j]
if(j != pos):
changed = True
pos = 1
# 返回新的压缩矩阵和标志变量。
return new_mat, changed
# 合并单元格的函数在压缩后的矩阵中
def merge(mat):
changed = False
for i in range(4):
for j in range(3):
# 如果当前单元格与同一行中的下一个单元格具有相同的值,并且它们都不为空,则
if(mat[i][j] == mat[i][j 1] and mat[i][j] != 0):
# 将当前单元格值加倍,并 清空下一个单元格
mat[i][j] = mat[i][j] * 2
mat[i][j 1] = 0
# 将布尔变量设置为True,表示合并后的新网格不同。
changed = True
return mat, changed
# 反转矩阵的函数表示反转每行的内容(即反转序列)
def reverse(mat):
new_mat =[]
for i in range(4):
new_mat.append([])
for j in range(4):
new_mat[i].append(mat[i][3 - j])
return new_mat
# 获取转置的函数矩阵的行和列
def transpose(mat):
new_mat = []
for i in range(4):
new_mat.append([])
for j in range(4):
new_mat[i].append(mat[j][i])
return new_mat
# 更新矩阵的函数
# if we move / swipe left
def move_left(grid):
# 首先压缩网格
new_grid, changed1 = compress(grid)
# 然后合并单元格。
new_grid, changed2 = merge(new_grid)
changed = changed1 or changed2
# 合并后再次压缩。
new_grid, temp = compress(new_grid)
# 返回新矩阵和已更改的 bool告知网格是相同或不同
return new_grid, changed
# 更新矩阵的函数
# if we move / swipe right
def move_right(grid):
# 要向右移动,我们只需倒转矩阵
new_grid = reverse(grid)
# 然后向左移动
new_grid, changed = move_left(new_grid)
# 然后再反转矩阵得到我们想要的结果
new_grid = reverse(new_grid)
return new_grid, changed
# 更新矩阵的函数
# if we move / swipe up
def move_up(grid):
# 要向上移动,我们只需矩阵的转置
new_grid = transpose(grid)
# 然后向左移动
new_grid, changed = move_left(new_grid)
# 再次进行转置就能得到理想的结果
new_grid = transpose(new_grid)
return new_grid, changed
# 更新矩阵的函数
# 如果我们向下移动/轻扫
def move_down(grid):
# 向下移动时,我们进行转置
new_grid = transpose(grid)
# 向右移动,然后再向右移动
new_grid, changed = move_right(new_grid)
# 采取转置会得到想要的结果。
new_grid = transpose(new_grid)
return new_grid, changed
# 此文件仅包含所有逻辑在主函数中调用的功能存在于其他文件中
2048.py
代码语言:javascript复制# 2048.py 完全代码
# 导入 logic.py 文件
# 使用的逻辑函数。
import logic
# 主代码
if __name__ == '__main__':
# 调用 start_game 函数
# 初始化矩阵
mat = logic.start_game()
while(True):
# 接收用户输入下一步
x = input("Press the command : ")
# 我们必须向上移动
if(x == 'W' or x == 'w'):
# 调用 move_up 函数
mat, flag = logic.move_up(mat)
# 获取当前状态并打印
status = logic.get_current_state(mat)
print(status)
# 如果游戏没有结束,则继续并添加一个新的2
if(status == 'GAME NOT OVER'):
logic.add_new_2(mat)
# 退出循环
else:
break
# 以上程序将按照 # 在每种类型的情况下移动下面
# 向下移动
elif(x == 'S' or x == 's'):
mat, flag = logic.move_down(mat)
status = logic.get_current_state(mat)
print(status)
if(status == 'GAME NOT OVER'):
logic.add_new_2(mat)
else:
break
# 向左移动
elif(x == 'A' or x == 'a'):
mat, flag = logic.move_left(mat)
status = logic.get_current_state(mat)
print(status)
if(status == 'GAME NOT OVER'):
logic.add_new_2(mat)
else:
break
# 向右移动
elif(x == 'D' or x == 'd'):
mat, flag = logic.move_right(mat)
status = logic.get_current_state(mat)
print(status)
if(status == 'GAME NOT OVER'):
logic.add_new_2(mat)
else:
break
else:
print("Invalid Key Pressed")
# 在每次移动后打印矩阵。
print(mat)
输出:
所有的代码中都有注释,大家可以研究研究,可以玩出自己的花样。
以下是 2048 游戏的界面