# 用Python实现命令行版2048游戏:从逻辑到代码


背景介绍

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吧!


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注