“好的开始是成功的一半” —— 理解项目整体设计再深入代码
2048 是一个理想的学习项目,原因如下:
| 特点 | 说明 | 学习价值 |
|---|---|---|
| 规则简单 | 4 个方向滑动,相同数字合并 | 逻辑清晰,易于理解 |
| 状态有限 | 4x4 网格,16 个位置 | 数据结构简单 |
| 算法适中 | 滑动 + 合并,有挑战性但不复杂 | 锻炼算法思维 |
| 可扩展 | 可添加动画、AI、多人模式 | 支持渐进式学习 |
| 可视化 | 界面直观,效果即时可见 | 学习成就感强 |
❌ 太简单:计算器、猜数字
→ 学不到架构设计
❌ 太复杂:3D 游戏、网络应用
→ 容易迷失在细节中
✅ 刚刚好:2048
→ 有挑战但可完成,能学到完整项目结构
初始状态:
┌────┬────┬────┬────┐
│ │ │ 2 │ │
├────┼────┼────┼────┤
│ │ │ │ │
├────┼────┼────┼────┤
│ │ 2 │ │ │
├────┼────┼────┼────┤
│ │ │ │ 4 │
└────┴────┴────┴────┘
向左滑动后:
┌────┬────┬────┬────┐
│ 2 │ │ │ │
├────┼────┼────┼────┤
│ │ │ │ │
├────┼────┼────┼────┤
│ 2 │ │ │ │
├────┼────┼────┼────┤
│ 4 │ │ │ │
└────┴────┴────┴────┘
(新方块随机生成)
优点:
✅ 语法简洁,适合初学者
✅ 丰富的生态系统
✅ 跨平台支持
✅ 类型注解支持(代码更清晰)
什么是 Textual?
→ 用 Python 构建终端用户界面的框架
→ 类似网页开发(HTML → Widgets, CSS → CSS, JS → Python)
为什么选 Textual?
✅ 现代化设计(比 curses 易用)
✅ 支持事件驱动
✅ 丰富的组件库
✅ 自动处理终端差异
什么是 uv?
→ 用 Rust 编写的超快 Python 包管理器
为什么选 uv?
✅ 速度极快(比 pip 快 10-100 倍)
✅ 自动管理虚拟环境
✅ 依赖锁定(确保一致性)
✅ 现代工作流
┌─────────────────────────────────────────┐
│ 用户界面层 │
│ Textual 8.0+ │
├─────────────────────────────────────────┤
│ 业务逻辑层 │
│ Python 3.14+ │
├─────────────────────────────────────────┤
│ 项目管理层 │
│ uv + pyproject.toml │
└─────────────────────────────────────────┘
什么是关注点分离(Separation of Concerns)?
把不同的功能分开,让每个部分只做一件事。
生活中的例子:
❌ 不好的设计:瑞士军刀式厨房
→ 切菜、炒菜、洗碗都在同一个台面上
→ 混乱、难以维护
✅ 好的设计:功能分区厨房
→ 切菜区、烹饪区、清洗区分开
→ 清晰、高效、易维护
┌─────────────────────────────────────────────────────────────┐
│ 表示层 (Presentation Layer) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ app.py - 应用入口,事件处理 │ │
│ │ ui.py - 界面组件,视觉渲染 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ ↑ │
│ (只调用,不修改) │
│ ↓ ↑ │
├─────────────────────────────────────────────────────────────┤
│ 业务层 (Business Layer) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ game.py - 游戏规则,移动逻辑,状态管理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ ↑ │
│ (只依赖接口) │
│ ↓ ↑ │
├─────────────────────────────────────────────────────────────┤
│ 数据层 (Data Layer) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ models.py - 数据结构,存储,序列化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ ↑ │
│ (纯数据,无逻辑) │
│ ↓ ↑ │
├─────────────────────────────────────────────────────────────┤
│ 支撑层 (Support Layer) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ config.py │ │ utils.py │ │
│ │ (配置常量) │ │ (工具函数) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
# ❌ 不分层:UI 和逻辑混在一起
def move_up():
# 移动逻辑
# UI 更新
# 动画播放
# ... 难以单独测试
# ✅ 分层:业务逻辑可独立测试
def test_move_up():
game = Game()
game.move("up") # 纯逻辑,不依赖 UI
assert game.score == 100
# 想改成 Web 界面?只需替换表示层!
# 业务层和数据层完全不用改
# Textual TUI
from textual.app import App
class GameApp(App): ...
# Web (Flask)
from flask import Flask
app = Flask(__name__)
@app.route("/")
def game_page(): ...
# 两者共用同一个 Game 类!
问题:分数计算错了
❌ 不分层:要在几百行代码里找
✅ 分层:直接去 game.py 的 move() 方法
问题:界面颜色要改
❌ 不分层:可能影响游戏逻辑
✅ 分层:只改 ui.py 的 CSS
| 模块 | 层级 | 职责 | 依赖其他模块 |
|---|---|---|---|
config.py |
支撑层 | 定义常量 | 无 |
utils.py |
支撑层 | 工具函数 | 无 |
models.py |
数据层 | 数据结构 | config |
game.py |
业务层 | 游戏逻辑 | models, config |
ui.py |
表示层 | 界面组件 | game, models |
app.py |
表示层 | 应用入口 | game, ui |
依赖规则:
每个类/函数只做一件事
# ❌ 不好:一个函数做太多事
def move_and_update_and_save():
# 移动逻辑
# UI 更新
# 保存到文件
# ✅ 好:每个函数职责单一
def move(direction): ...
def update_ui(): ...
def save_game(): ...
对扩展开放,对修改关闭
# ✅ 好设计:添加新方向不用改现有代码
DIRECTIONS = ["up", "down", "left", "right"]
def move(direction):
if direction not in DIRECTIONS:
raise ValueError(...)
# 处理移动
# 要添加"对角线"移动?
# → 扩展 DIRECTIONS 列表即可
把可能变化的值提取为常量
# ❌ 魔法数字
for i in range(4): # 4 是什么?
for j in range(4):
...
# ✅ 配置常量
GRID_SIZE = 4
for i in range(GRID_SIZE):
for j in range(GRID_SIZE):
...
1. 理解 2048 游戏规则(5 分钟)
→ 玩几局手机游戏
2. 理解分层设计(15 分钟)
→ 画出三层架构图
3. 认识技术栈(10 分钟)
→ 了解 Textual、uv 是什么
4. 运行项目(10 分钟)
→ 确保环境配置正确
# 任务 1:运行游戏
cd ~/Work/open_learn/python/game_2048
uv run game-2048
# 任务 2:修改配置
# 编辑 config.py,把 GRID_SIZE 改成 5
# 运行游戏,观察变化
# 任务 3:阅读代码
# 打开 game.py,找到 move() 函数
# 尝试理解它的调用链
A: Pygame 适合图形游戏,但 2048 是纯逻辑游戏。Textual 更轻量,且能学习终端 UI 开发(实用技能)。
A: 初期可能觉得多,但随着项目变大,分层的优势会越来越明显。这是专业开发的标配。
A: 可以,但建议先理解设计思想。磨刀不误砍柴工!
下一章: 第 2 章 项目结构与模块化
🐧 理解设计,再动手写代码!