背景介绍
2048是一款经典的数字合并游戏,玩家通过滑动数字方块(上下左右)使相同数字合并,最终目标是合成出“2048”。本文将带你用Python实现一个命令行交互的2048游戏,通过这个项目,你将练习二维数组操作、算法设计(移动/合并逻辑)、随机数生成和状态管理等核心技能。
思路分析
要实现命令行2048,需解决以下核心问题:
1. 数据结构:用4×4的二维列表(list[list[int]])存储棋盘状态,0表示空白格。
2. 移动合并:
– 紧凑:将行/列中的非零数字“挤到”一端(如左移时非零数字靠左,右移时靠右),去除中间的0。
– 合并:紧凑后,相邻相同数字合并为它们的和(如2+2=4),注意单次移动中每个数字只能合并一次。
– 方向处理:左右移动直接处理行,上下移动通过转置棋盘(行变列、列变行)转化为行处理。
3. 随机生成:每次有效移动后,在空白格中以90%概率生成2,以10%概率生成4。
4. 用户交互:解析方向指令(w上、s下、a左、d右)或退出指令(q)。
5. 胜负判断:
– 胜利:棋盘包含2048。
– 失败:棋盘无有效移动方向(四个方向移动后棋盘均无变化)且无2048。
代码实现
1. 初始化棋盘
随机在4×4网格中选择两个空白格,放入初始数字2:
import random
def init_board():
# 创建4×4全零棋盘
board = [[0 for _ in range(4)] for _ in range(4)]
# 随机选择两个空白格放2
empty_cells = [(i, j) for i in range(4) for j in range(4)]
for _ in range(2):
i, j = random.choice(empty_cells)
board[i][j] = 2
empty_cells.remove((i, j))
return board
2. 显示棋盘
用ASCII字符画表格,清晰展示棋盘状态(如┌───┬───┬───┬───┐等分隔符):
def print_board(board):
print('┌───┬───┬───┬───┐')
for row in board:
# 处理每行的显示:数字或空白(0)
row_str = '│'
for num in row:
if num == 0:
row_str += ' │' # 空白格
else:
row_str += f' {num} │' # 数字格
print(row_str)
# 除最后一行外,打印分隔符
if board.index(row) < 3:
print('├───┼───┼───┼───┤')
print('└───┴───┴───┴───┘')
3. 移动与合并逻辑
核心函数:process_row处理单行的紧凑和合并,move处理不同方向的移动(行/列)。
def process_row(row, direction):
# 步骤1:紧凑(去除0,保留非零数字)
compacted = [num for num in row if num != 0]
# 步骤2:合并(相邻相同数字合并,单次移动仅合并一次)
merged = []
i = 0
while i < len(compacted):
if i + 1 < len(compacted) and compacted[i] == compacted[i+1]:
merged.append(compacted[i] * 2) # 合并为和
i += 2 # 跳过下一个已合并的数字
else:
merged.append(compacted[i])
i += 1
# 步骤3:补零(根据方向补到4个元素)
if direction == 'left':
merged += [0] * (4 - len(merged)) # 左移补零在右
else: # 右移补零在左
merged = [0] * (4 - len(merged)) + merged
return merged
def move(board, direction):
new_board = [row.copy() for row in board] # 深拷贝避免修改原棋盘
if direction in ['a', 'd']: # 左右移动:直接处理行
for i in range(4):
row = new_board[i]
new_row = process_row(row, direction)
new_board[i] = new_row
else: # 上下移动:转置棋盘后处理行
# 转置(行变列,列变行)
transposed = list(zip(*new_board))
transposed = [list(row) for row in transposed]
for i in range(4):
col = transposed[i]
# 上移=列左移,下移=列右移
new_col = process_row(col, 'left' if direction == 'w' else 'right')
transposed[i] = new_col
# 转置回原棋盘
new_board = list(zip(*transposed))
new_board = [list(row) for row in new_board]
return new_board
4. 随机生成新数字
在空白格(值为0)中随机选一个,按90%概率生成2,10%概率生成4:
def add_random_tile(board):
# 收集所有空白格坐标
empty_cells = [(i, j) for i in range(4) for j in range(4) if board[i][j] == 0]
if not empty_cells:
return board # 无空白格(理论上不会发生,游戏早失败了)
# 随机选一个空白格
i, j = random.choice(empty_cells)
# 生成数字:90%概率2,10%概率4
board[i][j] = 2 if random.random() < 0.9 else 4
return board
5. 主循环:游戏流程控制
处理用户输入、移动棋盘、生成新数字、判断胜负:
def main():
board = init_board()
print_board(board)
while True:
# 处理用户输入
cmd = input("请输入方向(w:上, s:下, a:左, d:右)或q退出:").lower().strip()
if cmd == 'q':
print("游戏已退出!")
break
if cmd not in ['w', 's', 'a', 'd']:
print("无效输入,请重新输入!")
continue
# 尝试移动
new_board = move(board, cmd)
if new_board == board: # 移动无效(棋盘无变化)
print("无效移动,请尝试其他方向!")
continue
# 移动有效:生成新数字
add_random_tile(new_board)
board = new_board
print_board(board)
# 检查胜利
if 2048 in [num for row in board for num in row]:
print("恭喜你,达到了2048!游戏胜利!")
break
# 检查失败(无有效移动方向)
movable = False
for d in ['w', 's', 'a', 'd']:
test_board = move(board, d)
if test_board != board:
movable = True
break
if not movable:
print("无法移动,游戏结束!你没有达到2048。")
break
if __name__ == "__main__":
main()
代码解释与测试
- 移动逻辑:
process_row先“紧凑”(去除0)、再“合并”(相邻相同数字求和)、最后“补零”,确保数字按方向排列。move通过转置棋盘,将上下移动转化为行处理,简化代码。 - 随机生成:
add_random_tile在空白格中随机选位置,通过random.random()控制生成2(90%)或4(10%)的概率。 - 胜负判断:胜利条件是棋盘包含2048;失败条件是四个方向移动后棋盘均无变化(
movable=False)。
总结
通过这个项目,你掌握了:
– 二维数组的紧凑、合并、转置操作,解决方向移动问题。
– 随机数生成的概率控制(90%/10%)。
– 状态管理(胜利/失败判断)和用户交互逻辑。
这个项目适合Python初学者练习算法设计和二维数据处理,你也可以拓展功能(如记录最高分、美化界面、添加动画等)。
运行上述代码,你将得到一个功能完整的命令行2048游戏。尝试滑动数字,挑战合成2048吧!