{
  "lead": "先用「递归回溯」算法生成一座完美迷宫（任意两点之间有且只有一条通路），再用 A* 或 Dijkstra 算法一步步搜索从起点到终点的最短路径。蓝色是待扩展的边界，棕色是已经扩展过的格子，橙色是最终找到的路径。",
  "formulas": [
    [
      "f(n) = g(n) + h(n)",
      "g：已走步数 · h：到终点的曼哈顿距离"
    ]
  ],
  "terms": [
    [
      "迷宫生成（递归回溯）",
      "迷宫以奇数坐标的格子为「房间」，房间之间隔着一格墙。从起点出发，随机挑一个没去过的相邻房间，打通中间的墙走过去；走进死胡同就沿栈回退，直到所有房间都被访问。这相当于在网格上随机生成一棵生成树，所以没有环路，每个房间都可达。"
    ],
    [
      "Dijkstra",
      "每次从待扩展集合中取出「离起点最近」的格子扩展，像水波一样向四周均匀扩散。在所有边权相等的网格上，它能保证找到最短路径，但会扩展大量与终点方向无关的格子。"
    ],
    [
      "A*",
      "在 Dijkstra 的基础上加入启发函数 <code>h(n)</code>：对到终点剩余距离的估计。每次扩展 <code>f = g + h</code> 最小的格子，让搜索优先朝终点方向推进。只要 h 从不高估真实距离（曼哈顿距离在只能上下左右移动的网格上满足这一点），A* 同样保证找到最短路径。"
    ],
    [
      "优先队列与平局处理",
      "待扩展集合用二叉堆（<code>BinaryHeap</code>）实现，每次取最小值的复杂度是 O(log n)。f 相同时优先扩展 h 更小（离终点更近）的格子，能进一步减少扩展数量。已经扩展过的旧堆条目直接跳过（惰性删除）。"
    ]
  ],
  "flow": [
    [
      "rust",
      "<code>maze_generate(61, 41, 种子)</code>：Rust 生成迷宫并保存在全局状态中。"
    ],
    [
      "rust",
      "点击「开始寻路」后调用 <code>search_start(起点, 终点, 是否用 A*)</code>，Rust 初始化 g 值数组、父节点数组和优先队列。"
    ],
    [
      "rust",
      "每一帧 JS 调用 <code>search_step(N)</code>，Rust 扩展最多 N 个格子（速度滑块控制 N = 1 ~ 512），这样就能看到搜索的动画过程。"
    ],
    [
      "js",
      "JS 调用 <code>maze_cells()</code> 取回每个格子的状态（每格 1 字节），写进一张 61×41 的小 <code>ImageData</code>，再关闭平滑、放大绘制到画布上。"
    ]
  ],
  "flow_notes": [
    "点击画布修改墙壁或移动起点、终点时，JS 会调用 <code>maze_toggle_wall()</code> 或 <code>search_clear()</code> 清除上一次的搜索结果。"
  ],
  "perf": [
    "同一座迷宫上，可以切换 A* 和 Dijkstra 各跑一次，比较底部显示的「已扩展格子数」。在完美迷宫里通路唯一，两者差距不算大；拆掉一些墙、让地图变得开阔后，A* 的优势会明显得多。",
    "整个 2,501 格的迷宫，搜索本身通常只需要不到 1 毫秒；动画的速度是有意放慢的，方便观察扩展顺序。",
    "每帧只传一个 2.5 KB 的字节数组，并用一次 <code>drawImage</code> 放大绘制，没有逐格调用 <code>fillRect</code>。"
  ],
  "src": [
    [
      "crates/algorithms/pathfind/src/lib.rs",
      ""
    ],
    [
      "www/pathfind/index.js",
      ""
    ]
  ]
}
