游戏中的算法与计算思维 03:用洗牌理解随机与循环

课程首页 · 全部知识课程 · 返回专题主页

本系列第 3/8 课,建议 45–60 分钟(估算)。先完成上一课。

下载本课完成工程 .aia

这课解决什么

Fisher–Yates 从末尾向前,把当前位置与 1..i 随机位置交换。它改变位置,不改变牌的数量和内容;随机过程允许两次开局偶然相同,不能用“必须不同”验收。

先预测,再运行

洗牌后某种词出现三次,是随机现象还是程序错误?

先记下自己的答案,运行起始工程与完成工程比较;答案见文末。

开始实战

以上一课完成工程为起点,先导入并运行,再另存为本课作业。

完成工程可以查看答案;独立作业请保留自己的修改。

新增或调整的组件

实例名 组件 本课配置
标签_标题 标签 Width=Fill parent;FontSize=24;TextColor=#183153;Text=记忆翻牌 · 第 3课

逐步搭建

  1. 先生成完整成对牌组,再从 length(牌) 到 2 倒序循环。
  2. 每轮 random(1,i),暂存牌[i],完成两项交换。
  3. 别从固定 1..牌数随机,否则分布与本算法不同;别覆盖第一项后再读它交换。
  4. 多次新局,逐次检查长度和每类计数;使用固定随机序列追踪一次。

记忆翻牌游戏第3课运行状态布局预览

图来自本课最终工程执行积木后的状态,为 HTML 近似预览;不是手机截图。

核心积木与数据流

下面是本课完成工程中的核心代码,包含所需全局变量和过程。可在块图中追踪数值,再回到工程对照完整事件;合并到已有工程时,同名事件合并处理。

global 牌 = []
global 翻面 = []
global 第一 = 0
global 第二 = 0
global 锁定 = false
global 已配对 = 0
global 步数 = 0
global 秒数 = 0
global 对数 = 4
global 宽 = 70
global 高 = 100
global 题材提示 = ""
global 词 = list("历史","数学","编程","科学","艺术","运动")

procedure 绘制() {
宽 = 画布1.Width / 4
高 = 画布1.Height / ceil(length(牌) / 4)
画布1.Clear()
for i = 1 to length(牌) {
var 列 = (i - 1) % 4
var 行 = floor((i - 1) / 4)
画布1.PaintColor = choose(翻面[i] = 2, -14575216, choose(翻面[i] = 1,-24576,-14268949))
画布1.DrawShape(list(list(列 * 宽 + 2,行 * 高 + 2),list((列 + 1) * 宽 - 2,行 * 高 + 2),list((列 + 1) * 宽 - 2,(行 + 1) * 高 - 2),list(列 * 宽 + 2,(行 + 1) * 高 - 2)),true)
画布1.PaintColor = -1
画布1.DrawText(choose(翻面[i] = 0,"?",牌[i]),(列 + 0.5) * 宽,(行 + 0.5) * 高)
}
}

procedure 新局() {
题材提示 = ""
牌 = []
翻面 = []
第一 = 0
第二 = 0
已配对 = 0
锁定 = false
步数 = 0
秒数 = 0
for i = 1 to 对数 { listadd(牌,词[i]) listadd(牌,词[i]) listadd(翻面,0) listadd(翻面,0) }
for i = length(牌) to 2 step -1 {
var j = random(1,i)
var 临时 = 牌[i]
牌[i] = 牌[j]
牌[j] = 临时
}
标签_状态.Text = choose(题材提示 = "","新局:点击卡片",题材提示)
绘制()
}

中途检查与排错

本课以下控制与数据流已执行最终归档中的真实积木检查。请在伴侣或安装的 APK 中按相同场景操作,记录实际结果;自动检查通过不代表手机已实测。

  1. 开局8张卡片。
  2. 边界不越界。
  3. 洗牌/初始化保留每种两张。

排查时先确定出错的是输入、状态、数据读取还是显示;用标签暂时显示关键值,每次只改变一个条件。

界面图是积木执行后的画布近似预览;计时器、绘制与系统控件在设备上的实际表现仍需运行检查。

两个理解题与独立改造

  1. 洗牌后某种词出现三次,是随机现象还是程序错误?
  2. random(1,i) 中的 i 每轮为什么变小?

独立改造: 画出 [甲,甲,乙,乙] 的两轮交换过程,暂存变量不可省略。

先完成自己的工程,再对照答案。检查成功路径,也检查空数据、重复操作和取消;写出你改动的规则。

查看预测与练习参考答案

预测: 是错误。合法洗牌只交换,必须保持每种词两张。

追踪: 已处理尾部不再被后续交换打乱,每步只从尚未固定位置选择。

改造思路: 若先写牌[i]=牌[j],原牌[i]已丢失;临时变量保存它,第二次赋值才能恢复交换双方。

完成与下一步

保存自己的工程并导出 .aia;给文件命名以区分本课作业和参考源码。请用自己的话解释本课知识,并展示一次失败输入的处理。

上一课 · 下一课:第一张、第二张与匹配状态

文档反馈