Java开发者的Python进修指南:2048小游戏编程解析

最近我写的源码解析文章有点多了,想换个口味。今天决定练习一下Python,尝试实现一款当时风靡一时的2048小游戏。

游戏规则:《2048》是一款数字合并游戏,玩家通过上下左右滑动来控制所有方块的移动,当相同数字的方块移动时会合并成一个方块,数值相加。游戏的终极目标是合成一个数值为2048的方块。

在Python编程语言中,为了表示2048游戏的棋盘,可以采用二维列表的数据结构。在这个二维列表中,每个方块都会被一个数字所代表,其中0表示空格。

我们写一段简单的代码,不需过多的UI框架,直接在控制台运行即可。让我们来使用一下colorama。colorama是一个Python模块,专门用于在控制台和命令行中输出彩色文字,能够在各种操作系统上使用。

游戏逻辑

在这里简要介绍游戏逻辑,以便更好地理解业务代码。

  1. 初始化游戏棋盘,随机生成一个数字2。
  2. 检查游戏是否结束,即棋盘是否填满且不能再移动。
  3. 实现上下左右滑动操作,合并相同数字的方块。
  4. 判断是否达到2048,游戏胜利。
  5. 根据用户输入的方向操作,更新棋盘状态。

在这里我将详细解释实现的逻辑。这里只涉及数字向左移动,无论用户是向上、向右还是向下移动,都会被转换为向左移动。接下来我将演示如何根据向左移动的业务逻辑来实现向上移动。

再仔细审视一下向右移动的逻辑,同样的思路也可以应用到向右移动,即直接使用::-1来实现。完成了向左移动的合并逻辑后,再使用::-1来恢复原始顺序即可。

解决了上一个问题后,我们会进一步深入探讨如何在向左移动时优化合并相同数字的操作。这个过程也相对简单,简单来说,就是对列表进行递归处理:如果前两个元素相等,则将它们合并,并继续处理剩余部分;如果前两个元素不相等,则保留第一个元素并继续处理剩余部分。直至列表长度小于2时停止递归,最终返回处理完的结果列表。

主程序流程

根据上述基本逻辑,我们将简单实现主程序流程。考虑到需要持续监听用户的键盘操作,因此我们的主程序必须以一个while循环来实现。但是如何处理用户想要强制退出的情况呢?不能让用户关机,因此我们需要设定一个退出键来实现用户主动退出的功能。

  1. 初始化游戏棋盘。
  2. 进入游戏循环,直到游戏结束或者胜利。
  3. 在每轮循环中,接受用户输入的方向(W/A/S/D键)。
  4. 判断是否退出游戏(Q键)
  5. 根据用户输入的方向更新棋盘状态(全部转化为左)。
  6. 判断游戏是否结束或者胜利。
python 复制代码
from random import choice
from os import system
from readchar import readchar, readkey
from colorama import init
from termcolor import colored

N = 4
FGS = ['white', 'green', 'yellow', 'blue', 'cyan', 'magenta', 'red']
TERM = (10, 80)
OFFSET = (TERM[0] // 2 - 2, TERM[1] // 2 - 10)

pos          = lambda y, x: '\x1b[%d;%dH' % (y, x)
color        = lambda i: colored('%4d' % i, FGS[len('{:b}'.format(i)) % len(FGS)] if i else 'grey')
formatted    = lambda m: '\n'.join(pos(y, OFFSET[1]) + ' '.join(color(i) for i in l) for l, y in zip(m, range(OFFSET[0], OFFSET[0] + 4))) ## 正方形格式化打印出二维数组
combine      = lambda l: ([l[0] * 2] + combine(l[2:]) if l[0] == l[1] else [l[0]] + combine(l[1:])) if len(l) >= 2 else l ## 如果列表的前两个元素相等,就将它们合并并递归地继续处理剩余部分;如果前两个元素不相等,则保留第一个元素并继续处理剩余部分。直到列表长度小于2时停止递归,返回结果列表。
expand       = lambda l: [l[i] if i < len(l) else 0 for i in range(N)] ## 函数的作用是扩展列表 l 的长度至 N,如果 l 的长度小于 N,则在末尾添加足够多的 0 使其达到长度 N。
merge_left   = lambda l: expand(combine(list(filter(bool, list(l))))) 
merge_right  = lambda l: merge_left(l[::-1])[::-1]  ## 先倒置,按照左合并一样,再倒置回来
left         = lambda m: list(map(merge_left, m))
right        = lambda m: list(map(merge_right, m))
up           = lambda m: list(map(list, zip(*left(zip(*m)))))  ## 先反转列表,然后左移再反转
down         = lambda m: list(map(list, zip(*right(zip(*m))))) ## 先反转列表,然后右移再反转
add_num_impl = lambda m, p: m[p[0]].__setitem__(p[1], 2)  # 这里写死的2,其实可以选择一个(2和4)随机值增加游戏体验
add_num      = lambda m: add_num_impl(m, choice([(x, y) for x in range(N) for y in range(N) if not m[x][y]])) ## 随机选择一个符合要求的二维坐标地址
win          = lambda m: 2048 in sum(m, []) ## 只要存在2048即赢
gameover     = lambda m: all(m == t(m) for t in trans.values()) ## 如果所有变换都一样则结束游戏
draw         = lambda m: system("CLS") or print(formatted(m)) ## 打印数组,这里注意下,如果CLS找不到命令可切换clear,目的是清空控制台

trans = {'a': left, 'd': right, 'w': up, 's': down}
m = [[0] * N for _ in range(N)] ## 初始化一个N x N的二维列表,并且每个元素值都是0
init() ## 命令行输出彩色文字
add_num(m)
draw(m)
while True:
    while True:
        move = readkey()
        if move in list(trans.keys()) + ['q']:
            break
    if move == 'q': ## 键盘'Q'是游戏退出
        break
    n = trans[move](m)
    if n != m:
        add_num(n)
    m = n
    draw(m)
    if win(m):
        print('\n' + colored('(^_^) You Win!'.center(TERM[1]), 'yellow'))
        break
    elif gameover(m):
        print('\n' + colored('(>﹏<) Game Over!'.center(TERM[1]), 'red'))
        break

总结

最终,我们成功实现了经典游戏2048。现在,可以直接运行代码。本游戏利用二维列表数据结构来表示游戏棋盘,并在控制台中利用colorama模块实现了彩色文字输出。游戏的逻辑包括初始化棋盘、检查游戏是否结束、执行滑动操作、检查胜利条件等。通过简单的代码,我们实现了主程序流程,监听用户操作并更新棋盘状态,使得游戏具有交互逻辑。其中,最具挑战性的部分在于方向转换、合并和扩展数组。其他操作则相对基础。

相关推荐
懂点Tech2 小时前
ctfshow misc28:GIF 高度修改解题与脚本实现
开发语言·windows·python
comedate2 小时前
SMLib 的 Examples 导读:PyAPI / SM_API / SMLib 三组示例怎么读
python·cad·smlib·examples·sm_api
云和数据.ChenGuang2 小时前
Python 重写(Override)深度解析:从 MRO 到 super() 的完整机制
java·开发语言·人工智能·python·langchain·1024程序员节
摇滚侠3 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 12
java·数据库·笔记
川石课堂软件测试3 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
万化冥合4 小时前
PyBox屏幕键盘如何辅助演示键盘操作?
python·计算机外设
车软学堂4 小时前
从测试转开发,到底要补什么
网络·人工智能·python·功能测试·单片机·车载系统·自动化
天空依然蔚蓝4 小时前
分享一个自动检测网站在线状态的python程序
python·运维开发·1024程序员节
岁月宁静4 小时前
一个 AI 项目从本地到上线,要经过哪些步骤?全流程讲清楚
python·docker·agent
Cosolar5 小时前
不收费、不加水印、数据归你:我做了个开源的在线简历工具
后端·面试·前端框架