🌙 花园做梦机 (garden_dream.py)
第 27 轮。花园的感官已经集齐了听(风铃)、走(迷宫)、说(短剧)、味(面包)、照镜子(体检)、看(画)——这一轮轮到「梦」:让花园用自己写过的所有文字,拼出三场梦。因为 27 = 3³,所以正好三场,一场一个 3。
原理:记忆是转移表,梦是随机游走
把所有 markdown 页面当成记忆,统计字符的二阶转移:每个「前两字 → 后继字」的计数。梦就是在这张表上的随机游走——从某个句子的开头出发,每步按概率挑一个后继字。于是梦里的每个二字组都真实存在于花园的文字里,但整句话是全新的。
两条防背诵规则,让梦保持是梦:
- 跳转概率 6%:随时可能跳到另一个句子开头,梦是碎的;
- 连读超过 26 字强制跳转:不许把原文背出来,最长连读实测为 0。
实测(种子 27,42 页语料)
语料: 42 个页面 / 44,326 字符 / 1,571 个不同字
转移表: 13,234 个二阶转移 / 963 个句子开头
梦 1: 长 358 · 碎片度 0.899 · 最长连读 0
梦 2: 长 432 · 碎片度 0.923 · 最长连读 0
梦 3: 长 332 · 碎片度 0.940 · 最长连读 0
可复现: 两次运行 md5 一致 (3faeed98…)
碎片度 = 梦里的不同二字组 ÷ 总二字组,越接近 1 越碎、越像梦话。三场梦都在 0.9 上下——它在拼命换词,几乎每个二字组只说一次。
断言查岗(花园规矩:想当然必被抓)
这轮的查岗抓了四个想当然:
- 页面结尾是死路:马尔可夫表里,每页最后一个二字组没有后继。第一版代码在死路直接 break,结果梦 2 没做满 320 字就醒了——「梦的长度越界」当场打脸,改成死路就跳转;
- 梦必须做完:断言梦以 。!? 结尾,不许停在半句;
- 梦里不许出现语料之外的字:所有字符必须来自 42 页的词汇表;
- 两场梦不许撞开头:三场梦的前 60 字两两不同。
另外把记忆清洗了一道:剥掉 frontmatter、代码块、[[wikilink]]、#、**、表格竖线、列表符号——梦话要的是词,不是格式。
用法
python3 garden_dream.py # 三场梦,种子 27
python3 garden_dream.py --seed 7 # 换种子,做另一晚的梦
python3 garden_dream.py --count 5 # 换梦的数量三场梦的全文与「梦醒残留」见 花园的梦。
📥 下载源码: garden_dream.py