一、本篇摘要

Day 11 我们学会了让 Python “记住昨天”——把数据存进文件。今天就用这个能力做一款经典的记忆翻牌游戏——关掉游戏,最高纪录依然在

本篇是串联复习大合集Day 6 列表画卡牌矩阵、Day 9 字典管 AI 图案主题包、Day 11 文件存排行榜。学完这一篇,孩子第一次感受到"多个知识点合作做一个真项目"的乐趣。

二、本节课学习目标

  1. 二维列表表示卡牌矩阵,理解"游戏地图"的编程本质。
  2. 字典管理 AI 生成的多套图案主题包(动物/水果/交通工具/emoji),可自由切换。
  3. 文件读写实现排行榜持久化,理解"游戏存档"的最小可行方案。
  4. 掌握 random.shuffle() 洗牌技巧,理解"程序随机性"是所有小游戏的灵魂。

三、专业名词通俗释义

专业名词 通俗解释
二维列表 列表里套列表,用来表示"行 × 列"的表格/地图
洗牌 打乱列表顺序的操作,Python 用 random.shuffle(list)
翻牌状态 每张卡有三种状态:未翻 / 已翻开 / 已配对
主题包 一组同类图案的集合,用字典 {主题名: [图案列表]} 组织
排行榜 记录玩家最好成绩的表格文件(CSV)

四、分模块双向对照

模块 1:卡牌矩阵——用二维列表画游戏地图

在这里插入图片描述

# 【Scratch积木】新建列表 [board],用一个大列表装 4 个小列表
# 【Scratch积木】每个小列表代表一行 4 张卡

board = [
    ["🐶", "🐱", "🐰", "🐼"],
    ["🐶", "🐱", "🐰", "🐼"],
    ["🦁", "🐸", "🐵", "🐷"],
    ["🦁", "🐸", "🐵", "🐷"],
]

# 访问某一张卡:board[行][列]
print(board[0][2])   # 🐰

核心易错说明:二维列表访问必须双方括号 board[row][col]rowcol 都从 0 开始数。

模块 2:AI 图案主题包——字典分类管理

# 【Scratch积木】新建字典 [themes],键是主题名,值是图案列表

themes = {
    "动物": ["🐶", "🐱", "🐰", "🐼", "🦁", "🐸", "🐵", "🐷"],
    "水果": ["🍎", "🍌", "🍇", "🍉", "🍓", "🍑", "🍒", "🥝"],
    "交通": ["🚗", "🚕", "🚙", "🚌", "🚑", "🚒", "🚚", "✈️"],
    "emoji": ["😀", "😎", "🥳", "🤖", "👻", "🎃", "🎁", "⭐"],
}

# 【Scratch积木】询问 "选择主题" 并等待,从字典中取出对应列表
theme_name = input("选择主题(动物/水果/交通/emoji):")
icons = themes.get(theme_name, themes["动物"])

核心易错说明.get(key, default)dict[key] 安全——键不存在时返回默认值而不是报错。

模块 3:洗牌——random.shuffle 实战在这里插入图片描述

import random

# 【Scratch积木】将列表 [cards] 打乱顺序

cards = ["🐶", "🐶", "🐱", "🐱", "🐰", "🐰", "🐼", "🐼"]
random.shuffle(cards)         # 原地打乱,不返回新列表
print(cards)                   # 每次运行结果都不同

核心易错说明random.shuffle()原地修改,不像 sorted() 返回新列表;x = random.shuffle(cards) 得到的是 None,是新手大坑。

模块 4:翻牌与配对逻辑

在这里插入图片描述

# 【Scratch积木】定义积木 flip(row, col) → 翻开某张卡
# 【Scratch积木】如果 两张卡相同 → 保持翻开,否则盖回

def flip_and_check(board, revealed, r1, c1, r2, c2):
    if board[r1][c1] == board[r2][c2]:
        revealed[r1][c1] = True
        revealed[r2][c2] = True
        return True     # 配对成功
    return False        # 配对失败

模块 5:排行榜持久化——CSV 读写(复习 Day 11)

在这里插入图片描述

import csv, os

RANK_FILE = "memory_rank.csv"

# 【Scratch积木】读取排行榜文件到列表
def load_rank():
    if not os.path.exists(RANK_FILE):
        return []
    with open(RANK_FILE, "r", encoding="utf-8") as f:
        reader = csv.reader(f)
        next(reader, None)
        return list(reader)

# 【Scratch积木】追加一条成绩
def save_rank(name, flips, theme):
    exists = os.path.exists(RANK_FILE)
    with open(RANK_FILE, "a", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        if not exists:
            writer.writerow(["玩家", "翻牌次数", "主题"])
        writer.writerow([name, flips, theme])

五、综合实战项目:4×4 记忆翻牌完整游戏

游戏规则:4×4 共 16 张卡(8 对图案),每回合输入两张卡坐标翻开。相同保持翻开,不同盖回。全部配对后记录翻牌次数入排行榜。

Scratch 积木流程

  1. 选择主题 → 从字典取图案 → random.shuffle 洗牌
  2. 展开成 4×4 二维列表 board
  3. 建立同尺寸的 revealed 状态矩阵(全 False)
  4. 重复执行直到 全部配对:
    • 打印当前牌面(配对的显示图案,未配对显示❓)
    • 询问两张卡坐标 → 翻开对比 → 更新 revealed
    • 翻牌次数 +1
  5. 记录成绩 → 显示排行榜
    在这里插入图片描述

Python 完整可运行源码

import random
import csv
import os

THEMES = {
    "动物": ["🐶", "🐱", "🐰", "🐼", "🦁", "🐸", "🐵", "🐷"],
    "水果": ["🍎", "🍌", "🍇", "🍉", "🍓", "🍑", "🍒", "🥝"],
    "交通": ["🚗", "🚕", "🚙", "🚌", "🚑", "🚒", "🚚", "✈️"],
    "emoji": ["😀", "😎", "🥳", "🤖", "👻", "🎃", "🎁", "⭐"],
}
RANK_FILE = "memory_rank.csv"


# 【Scratch积木】定义积木 build_board(theme) → 返回 4×4 洗牌后的二维列表
def build_board(theme):
    icons = THEMES[theme][:]
    cards = icons + icons                 # 每个图案配一对
    random.shuffle(cards)
    return [cards[i * 4:(i + 1) * 4] for i in range(4)]


# 【Scratch积木】定义积木 print_board(board, revealed)
def print_board(board, revealed):
    print("\n    0    1    2    3")
    for r in range(4):
        row_str = f"{r}  "
        for c in range(4):
            row_str += f"[{board[r][c] if revealed[r][c] else '❓'}]  "
        print(row_str)


# 【Scratch积木】定义积木 ask_coord(prompt) → 返回 (row, col)
def ask_coord(prompt):
    while True:
        raw = input(prompt).strip().split()
        if len(raw) == 2 and all(x.isdigit() for x in raw):
            r, c = int(raw[0]), int(raw[1])
            if 0 <= r < 4 and 0 <= c < 4:
                return r, c
        print("⚠️ 请输入两个 0-3 的数字,用空格分隔,例如:1 2")


# 【Scratch积木】定义积木 save_rank(name, flips, theme)
def save_rank(name, flips, theme):
    exists = os.path.exists(RANK_FILE)
    with open(RANK_FILE, "a", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        if not exists:
            writer.writerow(["玩家", "翻牌次数", "主题"])
        writer.writerow([name, flips, theme])


# 【Scratch积木】定义积木 show_rank()
def show_rank():
    if not os.path.exists(RANK_FILE):
        print("📭 暂无排行榜")
        return
    with open(RANK_FILE, "r", encoding="utf-8") as f:
        reader = csv.reader(f)
        next(reader, None)
        rows = [row for row in reader]
    # 【Scratch积木】按翻牌次数升序排序(次数越少越靠前)
    rows.sort(key=lambda x: int(x[1]))
    print("\n" + "=" * 30)
    print("       🏆 记忆翻牌排行榜")
    print("=" * 30)
    for i, (name, flips, theme) in enumerate(rows[:10], 1):
        print(f"  {i}. {name}  {flips} 次  [{theme}]")
    print("=" * 30)


# 【Scratch积木】主循环:一局游戏
def play_one_round():
    print("\n可选主题:", "、".join(THEMES.keys()))
    theme = input("选择图案主题:").strip()
    if theme not in THEMES:
        theme = "动物"
        print("默认使用「动物」主题")

    board = build_board(theme)
    revealed = [[False] * 4 for _ in range(4)]
    flips = 0
    pairs_found = 0

    while pairs_found < 8:
        print_board(board, revealed)
        print(f"🎯 已配对 {pairs_found}/8  |  翻牌 {flips} 次")

        r1, c1 = ask_coord("翻开第 1 张(行 列):")
        if revealed[r1][c1]:
            print("⚠️ 这张卡已经配对啦,换一张")
            continue

        r2, c2 = ask_coord("翻开第 2 张(行 列):")
        if (r2, c2) == (r1, c1) or revealed[r2][c2]:
            print("⚠️ 两张卡不能相同或已配对")
            continue

        # 【Scratch积木】临时翻开两张卡展示给玩家看
        print(f"翻开:[{board[r1][c1]}] 和 [{board[r2][c2]}]")
        flips += 1

        if board[r1][c1] == board[r2][c2]:
            print("🎉 配对成功!")
            revealed[r1][c1] = True
            revealed[r2][c2] = True
            pairs_found += 1
        else:
            print("❌ 不匹配,再想想")

    # 全部配对
    print_board(board, revealed)
    print(f"\n🏆 恭喜通关!共翻牌 {flips} 次")
    name = input("请输入你的昵称:").strip() or "匿名玩家"
    save_rank(name, flips, theme)
    show_rank()


# 【Scratch积木】游戏总入口
def main():
    print("=" * 40)
    print("  🎴 记忆翻牌游戏 · AI 主题包版")
    print("=" * 40)
    while True:
        play_one_round()
        again = input("\n再来一局?(y/n):")
        if again.lower() != "y":
            print("👋 下次见!")
            break


if __name__ == "__main__":
    main()

运行方式:保存为 day12_code.py → 命令行 python day12_code.py → 按提示输入两张卡的行列坐标。

💡 三大数据结构会师:卡牌矩阵是二维列表、主题包是字典、排行榜是文件——一款翻牌游戏把 Day 6/9/11 三个知识点全部串起来。这就是"综合项目"的味道——不再是学一个用一个,而是几个知识点合作解决一个真问题

六、高频易错点总结

1. 二维列表初始化陷阱

# ❌ 错误:所有行共享同一个引用
board = [[False] * 4] * 4
board[0][0] = True   # 结果所有行第 0 列都变 True

# ✅ 正确:每行独立创建
board = [[False] * 4 for _ in range(4)]

2. random.shuffle 返回值是 None

新手常写 cards = random.shuffle(cards),然后 cards 变成 None——shuffle 原地修改,不返回

3. 字典取值用 .get() 更安全

themes[key] 键不存在直接崩溃;themes.get(key, default) 优雅兜底。

4. CSV 排序前要转数字

rows.sort(key=lambda x: x[1])字符串排序,“10” 会排在 “2” 前面;必须 key=lambda x: int(x[1])

八、💡 学习提示

为鼓励大家动手练习、吃透编程逻辑,本篇不提供 Scratch 成品源码,请对照截图亲手搭建积木完成复刻!

配套 Python 代码可直接复制运行学习。

九、往期历史笔记

  1. 编程启蒙|Scratch 转 Python 系列第 1 天:变量、数字运算积木双向对照(AI 基础数值计算实战)

  2. 编程启蒙|Scratch 转 Python 系列第 2 天:分支判断 if 积木双向对照(AI 指令条件过滤实战)

  3. 编程启蒙|Scratch 转 Python 系列第 3 天:循环重复积木双向对照(AI 批量循环处理,已收录 AI Agent 技术社区)

  4. 编程启蒙|Scratch 转 Python 系列第 4 天:字符串文本积木双向对照(AI 提示词拼接、文本清洗实战)

  5. 编程启蒙|Scratch 转 Python 系列第 5 天:自定义积木 / 函数双向对照(AI 工具封装、重复指令简化实战)

  6. 编程启蒙|Scratch 转 Python 系列第 6 天:列表、数组积木双向对照(AI 底层语法 / AI 批量数据处理实战)

  7. 编程启蒙|Scratch 转 Python 系列第 7 天:猜数字大挑战·升级版实战(AI 出题 + 二分查找最优解 + 完整命令行游戏)

  8. 编程启蒙|Scratch 转 Python 系列第8天:节奏敲击机游戏实战(AI节奏谱生成实战)

  9. 编程启蒙|Scratch 转 Python 系列第9天:字典/哈希表积木双向对照(AI大模型参数配置表实战)

  10. 编程启蒙|Scratch 转 Python 系列第 10 天:问答闯关游戏实战(AI 题库管理 + 多关卡剧本)

  11. 编程启蒙|Scratch 转 Python 系列第 11 天:文件读写积木双向对照(AI 训练数据存取实战)

十、下一章预告

Scratch 转 Python 系列第 13 天:异常处理 try/except 积木双向对照(AI 接口调用容错实战)

当程序遇到"不听话"的输入或网络出错,如何优雅兜底?——try/except 会告诉你答案,这也是所有 AI API 调用的必备技能。

十一、原创声明

本文为「梅雅达编程笔记」原创启蒙教程,禁止私自搬运、二次转载,转发请标注来源。

想要系统学完整套 Scratch 转 Python 课程,欢迎订阅下方专栏持续追更。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐