{
  "lead": "波函数坍缩（Wave Function Collapse，Maxim Gumin 2016）是一种程序化生成算法，名字借自量子力学：一开始每个格子都「同时是所有可能的图块」，每一步挑一个格子让它「坍缩」成确定的图块，再把这个决定带来的限制传播给周围的格子，直到整张地图都确定下来。规则只有一条：任意两个相邻的格子必须是允许相邻的组合。页面上模糊的颜色就是某个格子剩下的所有可能的平均色。",
  "formulas": [
    [
      "H = log Σw − (Σ w log w) / Σw",
      "香农熵：可能性越少、越集中的格子熵越小，最先坍缩"
    ],
    [
      "可能(邻居) ← 可能(邻居) ∩ ⋃<sub>p ∈ 可能(本格)</sub> 允许(p, 方向)",
      "约束传播：邻居只能保留与本格某个剩余可能兼容的图块，有变化就继续向外传"
    ]
  ],
  "terms": [
    [
      "熵最小优先",
      "每次挑选剩余可能最少的格子来决定，并按图块权重随机选一个。先处理最受约束的地方，就像解数独时先填只剩一个候选的格子，能大大减少走进死胡同的机会，也让地图像晶体一样从已确定的区域向外生长。"
    ],
    [
      "平铺模型",
      "直接给出图块和「谁能挨着谁」。管道图块看每条边上有没有管道；地形用的是角点图块：每块的四个角各有一个高度，相邻图块共享的两个角必须相同，同一块的四个角最多差一级，渲染时对四个角插值，所以海岸线是连续的。如果改成「每格一个高度、相邻最多差一级」，规则太弱，生成出来只是一片噪点。"
    ],
    [
      "重叠模型（从样例学习）",
      "不手写规则，而是给一张小样例图：把其中所有 3×3 的小块连同它们的 4 种旋转和镜像都收集起来当作「图块」，出现得越多权重越大；两个小块错开一格后重叠部分完全相同，才允许相邻。输出的每个像素取所在小块的左上角颜色，于是新图的任何局部都像样例里的某一处，整体却从未出现过。"
    ],
    [
      "矛盾与回溯",
      "传播可能把某个格子的可能性删光，这就是矛盾。求解器在每次坍缩前保存一份快照（最多 48 份），遇到矛盾就退回上一步，把刚才的选择排除掉再试；退无可退就换一个随机种子从头开始，重来 20 次仍失败才宣告无解。示例图块集设计得比较宽松，通常一次就成功。"
    ],
    [
      "无缝平铺",
      "勾选后，左右边缘和上下边缘也被当作相邻来检查，生成的地图可以像壁纸一样无缝拼接。"
    ]
  ],
  "flow": [
    [
      "js",
      "选择图块集和大小后调用 <code>wfc_new(图块集, 宽, 高, 种子, 是否平铺)</code>；右侧的图例来自 <code>wfc_preview()</code>。"
    ],
    [
      "rust",
      "每一帧 JS 调用 <code>wfc_step(n)</code>：Rust 坍缩 n 个格子，每次都做完整的约束传播、必要时回溯或重来，返回状态、已确定的格子数和回溯次数。每个格子的可能集合用位集存储，传播时按 64 位一组做与、或运算。"
    ],
    [
      "js",
      "<code>wfc_image()</code> 返回整张图：已确定的格子画图块，未确定的格子画剩余可能的加权平均色，JS 放大显示，保持像素锐利。"
    ]
  ],
  "perf": [
    "实测（桌面 Chromium，40×40 格）：管道 16 种图块约 13ms 生成完，地形 76 种约 40ms，迷宫 120 种约 90ms，湖泊 265 种约 350ms。图案越多，每个格子的位集越长，传播时要合并的集合也越多。页面默认每帧只确定 8 格，是为了能看清生长过程；「直接完成」一次跑到底。",
    "传播是这个算法的主要开销：一次坍缩可能引发连锁反应，一直波及很远的格子。更快的实现会为每个图案维护「还剩几个兼容邻居」的计数，这里为了代码清晰，直接对集合求并。"
  ],
  "src": [
    [
      "crates/graphics/wfc/src/solver.rs",
      ""
    ],
    [
      "crates/graphics/wfc/src/model.rs",
      ""
    ],
    [
      "crates/graphics/wfc/src/tilesets.rs",
      ""
    ],
    [
      "www/wfc/index.js",
      ""
    ]
  ]
}
