Files
HexTrails/labs/airport

六角机场实验室

独立的起降调度原型。前四关是 19 格教学;视觉使用原工程马卡龙方案。不覆盖主线关卡或存档。

运行

在项目根目录运行 npm run dev,打开 六角机场。静态打包包含本实验目录。设计规则见 设计文档。

点击地面飞机起飞,点击场外停机坪上的飞机降落;左右转每次 60°。成功、失败与旋转都消耗一次。灰色轨道不分颜色;来机匹配彩色专用机位。P 标记表示已停好的来机。它再次起飞后,停到实际出口那条边的停机坪,仍需重新停好。

板边轨道一直画到托盘外缘,不伸出棋盘。托盘外是以棋盘中心为焦点的六等分扇形停机坪,对应六条平边;扇形不随底盘旋转。当等待机在当前朝向下接得上同色机位时,提示线从飞机接到盘内通道;旋转时通道会亮灭,据此判断能否进场。

关卡证据

所有数据冻结在 levels.js。solution 是最优免费解,experience 是制作意图回放。

关卡 格子 最少操作 初始额度 体验回放 先清全盘再接机最少操作 最优解保留原有飞机
留一点空间 19 1 3 1 4 3
同色才停靠 19 1 3 1 4 3
转一下再接入 19 2 4 2 5 3
清障再接入 19 5 7 5 11 4
更大的停机坪 37 6 10 6 19 7
绕一圈再接入 37 10 14 10 15 5
空港全景 61 8 12 8 18 10

前四关为教学。第 5、6 关是半径 3 的练习关。第 7 关把棋盘放大到半径 4(61 格)。最优性通过统一动作成本 BFS 的完整找到最短路径证明;状态上限或深度上限只返回 unknown。

每关通过空棋盘、六朝向、六边、每色完整结果的无歧义校验。入口侧按端口位置落入的平边扇区归类,名称依次为右上方、右方、右下方、左下方、左方、左上方;角部端口只归一边。来机只能从当前停机坪那条平边进场,画在对应边外侧,不使用正北等罗盘悬停点。

npm run test:airport
npm run airport:verify
npm run airport:generate
npm run airport:practice
npm run build:airport

教学四关生成器使用固定种子 9172026。练习关生成器使用 9172027,追加两个 37 格关与一个 61 格关,不改写前四关。不会在玩家进入页面时随机生成。

结构

  • core.js:纯规则、状态变换、碰撞、原子预占、求解和关卡校验。
  • app.js / index.html / style.css:Canvas 棋盘、可访问按钮、六侧等待区和动画。
  • solver-worker.js:异步检查局面,未完成搜索不冒充已证明死局。
  • rewards.js:广告适配边界、会话隔离和幂等奖励。
  • levels.js:冻结关卡、最优解与体验解。

规则层 transition 供无动画搜索使用;AirportGame.begin/finish 管理动画期间操作锁。降落立即占位,来机起飞立即取消完成状态并更新出口侧,动画完成前该飞机不能再次点击。配置的轨道和机位在运行时固定;编辑它们后须调用 invalidateCatalogs,validateAirportLevel 已自行刷新缓存。

广告与存储边界

尚未接入真实广告 SDK。默认界面明确显示“测试补充”,每次 +5 次,每关最多 3 次,仅用来验证奖励流程。

宿主可在页面模块运行前提供 window.airportAdProvider = async ({levelId, steps}) => ({id, completed})。只有真实激励广告完成回调才能返回 completed: true;id 必须是唯一奖励凭据。取消返回 completed: false;失败拒绝 Promise。生产宿主负责验证凭据,本地幂等防重复不替代服务端或 SDK 的奖励校验。

广告期间切关或重来后,旧回调不能给新局加步数;确认死局不提供加步数入口。搜索未知时不保证加步数能解围。

唯一持久化键是 hex-airport-v1,保存本实验已完成关卡、上次关卡和音效偏好,不保存正在进行的一局,也不读写原作进度。没有撤销、主动提示、拖动旋转或缩放;原型只保留明确按钮操作。

验证范围

自动测试覆盖免费回放、最优与全清成本、六侧唯一性、反向入位、首个阻挡、邻格擦碰、入位末段碰撞、连点抢位、失败扣步、换侧返回、最后一步通关、搜索未知与死局区分、奖励取消/失败/重复/过期回调。

浏览器验证使用真实页面按钮回放三个关卡,另检查短屏布局、失败反馈、补充次数和模态操作。自动测试与模型回放不能证明玩家理解度或广告效果;尚需真人试玩。

完整执行记录与已有仓库问题见 验收报告。