From d1dffa93388c6d983f08e937722f2b211916674d Mon Sep 17 00:00:00 2001 From: cabinw Date: Sun, 13 Sep 2026 12:19:13 +0800 Subject: [PATCH] Add three playable puzzle variants in an isolated lab --- README.md | 4 + labs/variants/README.md | 31 + labs/variants/app.js | 76 + labs/variants/generate.mjs | 46 + labs/variants/index.html | 16 + labs/variants/levels.json | 7639 ++++++++++++++++++++++++++++++++++++ labs/variants/model.js | 82 + labs/variants/style.css | 1 + scripts/build.mjs | 2 +- tests/variants.test.js | 38 + 10 files changed, 7934 insertions(+), 1 deletion(-) create mode 100644 labs/variants/README.md create mode 100644 labs/variants/app.js create mode 100644 labs/variants/generate.mjs create mode 100644 labs/variants/index.html create mode 100644 labs/variants/levels.json create mode 100644 labs/variants/model.js create mode 100644 labs/variants/style.css create mode 100644 tests/variants.test.js diff --git a/README.md b/README.md index ea4a970..fa99356 100644 --- a/README.md +++ b/README.md @@ -117,3 +117,7 @@ Cocos 示例复用规则、碰撞、渲染命令和图集;HTML 控件、文件 ## 视频 UI 实验室 [Hex Video Lab](labs/hex-video/index.html) 是基于 `examples/hex.mp4` 的独立 UI / 特效复刻,可切换地图、棋盘和领奖场景,支持自动试玩、单片翻转、彩纸、金币飞入、慢速播放及参考帧对照。棋子按本项目要求保留单片薄侧边,不使用视频中的多片堆叠。运行 `npm run dev` 后访问 `/labs/hex-video/index.html`;详见 [复刻笔记](labs/hex-video/README.md)。 + +## 玩法变种 Lab + +[打开独立实验室](http://localhost:4173/labs/variants/index.html):分色归站、机关换轨、接力停靠,各 5 个可解关卡,支持旋转、撤销、提示和重来。仅使用实验室数据,不写入主线存档。规则和验证范围见 [Lab 说明](labs/variants/README.md)。 diff --git a/labs/variants/README.md b/labs/variants/README.md new file mode 100644 index 0000000..d479604 --- /dev/null +++ b/labs/variants/README.md @@ -0,0 +1,31 @@ +# 玩法变种 Lab + +运行 `npm run dev`,打开 http://localhost:4173/labs/variants/index.html 。 + +这是用户授权的独立玩法原型,包含三种模式,各 5 关。主线规则、界面、编号和存档不变。Lab 本身不保存进度;刷新后回到首关。模式可用 `?mode=color`、`?mode=switch`、`?mode=relay` 直达。 + +## 规则 + +- 分色归站:所有边界端口分配橙色或蓝色终点,棋子只能从同色端口离场。外围终点不随底盘旋转。错色、碰撞和闭环均返回原位。 +- 机关换轨:标记 A 的棋子离场后,切换金色 A 格的两套轨道配对。机关格及其两套配对随底盘旋转。每关一个一次性机关;冻结参考解中,机关会实际打开至少一枚剩余棋子的出口。 +- 接力停靠:中央 P 点固定在世界坐标。经过 P 时先驶入格中心,停下后箭头变为该格轨道出口方向;再次点击从此方向出发。每次重新进入 P 都会停靠。P 被占用时不能进入。只检测抵达 P 之前的碰撞,不受 P 后方障碍影响。 + +全模式保留免费旋转、免费试路、弯轨自动转向和交叉不换轨。采用顺序动画输入,动画期间暂停发车和旋转;重来和切关可以取消动画。撤销恢复完整状态,包括机关、停靠位置和朝向。提示在当前局面重新搜索;无解或搜索超限有独立反馈。 + +## 实现与关卡 + +`model.js` 复用主线 `core.js` 的寻路、旋转和 `path-math.js` 的连续碰撞与曲线采样。实验规则仅在 Lab 模型中扩展,不修改主线模型。Canvas 负责实验标记与轨迹动画,棋子大小与共享碰撞体一致。 + +`levels.json` 冻结 15 关、确定性种子、完整动作解和机制证据。每关 19 格、3–5 枚棋子,先验证机制是否易懂;这些是原型样本,不代表经过真人标定的难度曲线。 + +`generate.mjs` 按确定性候选筛选:完整可解、实际经过弯轨、参考解需要旋转;机关关必须触发开路;接力关必须发生停靠。局面搜索包含朝向、剩余棋子位置与方向、机关状态,不能沿用主线“安全棋子全部贪心移除”的简化。 + +重新生成:`node labs/variants/generate.mjs`。 +规则验证:`node --test tests/variants.test.js`。 +静态打包:`node scripts/build.mjs`(Lab 已加入复制清单)。 + +## 验证范围 + +15 关数据校验、独立求解和冻结解回放;六次旋转恢复两套机关轨道;错色不改变状态;停靠截断路径、占位阻挡及继续出发;每步不修改历史快照。 + +浏览器检查桌面和 390×844 手机视口、模式切换、选关、提示与通关。当前仅 Web 原型,未移植或验收 Cocos、Android、iOS。尚未开展真人玩法偏好测试。 diff --git a/labs/variants/app.js b/labs/variants/app.js new file mode 100644 index 0000000..c01f9df --- /dev/null +++ b/labs/variants/app.js @@ -0,0 +1,76 @@ +import { createState, act, solve } from './model.js'; +import { position, hexPoints, trackPoints, PORTS } from '../../src/path-math.js'; +const $ = id => document.getElementById(id), canvas = $('board'), ctx = canvas.getContext('2d'); +const colors = ['#d66c4d', '#477fc0']; +const copy = { + color: ['分色归站', '橙色棋子进入橙色出口,蓝色棋子进入蓝色出口。外围短线就是终点;终点固定,旋转底盘改变去向。'], + switch: ['机关换轨', '带 A 标记的棋子离场,会切换 A 格的轨道连接。先观察它影响的路线,再安排出发顺序。'], + relay: ['接力停靠', '棋子经过中央 P 点时会停下,箭头沿后续轨道转向。再次点击继续出发,也可以先转盘或让其他棋子通过。'] +}; +let levels, mode = 'color', index = 0, state, history = [], animation = null, frame, size, scale, hint; +function poly(points, stroke, width = 1, fill) { + ctx.beginPath(); points.forEach((p,i) => i ? ctx.lineTo(p.x,p.y) : ctx.moveTo(p.x,p.y)); + if(fill){ctx.closePath();ctx.fillStyle=fill;ctx.fill();} + if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=width;ctx.stroke();} +} +function piece(tile, point, alpha = 1) { + const p = point || position(tile.q,tile.r);ctx.save();ctx.globalAlpha=alpha; + poly(hexPoints(p.x,p.y,.88),hint===tile.id?'#fff':'#ffffffcc',hint===tile.id?.09:.035,colors[tile.color]); + ctx.save();ctx.translate(p.x,p.y);ctx.rotate(tile.dir*Math.PI/3); + poly([{x:0,y:.3},{x:0,y:-.3}], '#fff', .09); + poly([{x:-.17,y:-.08},{x:0,y:-.3},{x:.17,y:-.08}], '#fff', .09);ctx.restore(); + ctx.fillStyle='#fff';ctx.font='bold .24px system-ui';ctx.textAlign='center'; + ctx.fillText(tile.trigger || tile.id.slice(1)*1+1,p.x+.38,p.y+.37);ctx.restore(); +} +function draw(now = performance.now()) { + if(!state)return; + ctx.setTransform(canvas.width/size,0,0,canvas.width/size,0,0);ctx.clearRect(0,0,size,size); + ctx.translate(size/2,size/2);ctx.scale(scale,scale);ctx.lineCap='round';ctx.lineJoin='round'; + for(const c of state.cells){const p=position(c.q,c.r);poly(hexPoints(p.x,p.y,.97),'#d3dfe3',.025,'#fafbf7');} + for(const c of state.cells){const p=position(c.q,c.r);for(let a=0;a<6;a++)if(ac.switchId)){const p=position(c.q,c.r);ctx.fillStyle='#7d5824';ctx.font='bold .28px system-ui';ctx.textAlign='center';ctx.fillText('A',p.x,p.y+.1);} + if(mode==='relay')for(const c of state.stops){const p=position(c.q,c.r);ctx.beginPath();ctx.arc(p.x,p.y,.4,0,Math.PI*2);ctx.fillStyle='#e4edda';ctx.fill();ctx.strokeStyle='#65874d';ctx.lineWidth=.055;ctx.stroke();ctx.fillStyle='#507238';ctx.font='bold .35px system-ui';ctx.textAlign='center';ctx.fillText('P',p.x,p.y+.12);} + for(const t of state.tiles)if(animation?.tile.id!==t.id)piece(t); + if(animation){ + let t=Math.min(1,(now-animation.start)/animation.duration); + const success=['exit','stop'].includes(animation.status); + const fraction=success?t:Math.sin(t*Math.PI); + const lengths=animation.lengths,total=lengths.at(-1),distance=fraction*total; + let i=1;while(i=1){animation=null;sync();}else frame=requestAnimationFrame(draw); + } +} +function resize(){size=canvas.getBoundingClientRect().width;scale=size/9.3;canvas.width=canvas.height=Math.round(size*Math.min(devicePixelRatio||1,2));draw();} +function sync(){ + $('count').textContent=`剩余 ${state.tiles.length} 枚`; + const busy=!!animation; + for(const id of ['left','right','hint'])$(id).disabled=busy||!state.tiles.length; + $('undo').disabled=busy||!history.length; + $('next').hidden=busy||!!state.tiles.length||index===4; + $('pieces').replaceChildren(...state.tiles.map(t=>{const b=document.createElement('button');b.textContent=`${t.id.slice(1)*1+1} 号${t.trigger?' · 机关 A':''}`;b.disabled=busy;b.onclick=()=>perform({type:'tap',id:t.id});return b;})); + if(!state.tiles.length&&!busy)$('message').textContent=index===4?'这个模式的 5 关已完成,可以切换另一种玩法。':'全部到达!可以进入下一关。'; +} +function load(){cancelAnimationFrame(frame);animation=null;history=[];hint=null;state=createState(levels.filter(l=>l.mode===mode)[index]);$('title').textContent=copy[mode][0];$('rule').textContent=copy[mode][1];$('message').textContent='点击箭头出发,遇阻可以免费试路或旋转。';$('level').value=index;sync();resize();} +function selectMode(next){mode=next;index=0;for(const b of document.querySelectorAll('[data-mode]'))b.setAttribute('aria-pressed',b.dataset.mode===mode);$('level').replaceChildren(...levels.filter(l=>l.mode===mode).map((l,i)=>new Option(`${i+1} · ${l.name}`,i)));load();} +function perform(action){ + if(animation||!state.tiles.length)return;hint=null; + const tile=state.tiles.find(t=>t.id===action.id),result=act(state,action); + if(result.state!==state){history.push(state);state=result.state;} + const messages={rotate:'底盘已旋转,棋子与外围标记保持原位。',exit:tile?.trigger?'A 机关触发,金色轨道已经换路。':'已成功离场。',stop:'已停靠 P 点。可以转盘换路,再点它继续出发。',wrong:'出口颜色不匹配,试试旋转底盘。',blocked:'前方有棋子挡路,先让路或转盘再试。',loop:'这条路线绕回了原处,试试旋转底盘。'}; + $('message').textContent=messages[result.status]; + if(result.points?.length>1){const lengths=[0];for(let i=1;i{const r=canvas.getBoundingClientRect(),x=(e.clientX-r.left-size/2)/scale,y=(e.clientY-r.top-size/2)/scale;const tile=state?.tiles.find(t=>{const p=position(t.q,t.r);return Math.hypot(x-p.x,y-p.y)<.85;});if(tile)perform({type:'tap',id:tile.id});}); +$('left').onclick=()=>perform({type:'rotate',direction:-1});$('right').onclick=()=>perform({type:'rotate',direction:1}); +$('reset').onclick=load;$('undo').onclick=()=>{if(!animation&&history.length){state=history.pop();hint=null;$('message').textContent='已恢复上一步,包括轨道机关与停靠位置。';sync();draw();}}; +$('hint').onclick=()=>{const solution=solve(state);const action=solution.actions[0];if(!action){$('message').textContent=solution.exhausted?'搜索尚未完成,可以撤销再试。':'当前状态没有通关路径,请撤销或重来。';return;}hint=action.id;$('message').textContent=action.type==='rotate'?`向${action.direction===1?'右':'左'}旋转一次。`:`点击 ${action.id.slice(1)*1+1} 号棋子${state.tiles.find(t=>t.id===action.id)?.trigger?'(A 机关)':''}。`;draw();}; +$('level').onchange=()=>{index=Number($('level').value);load();};$('next').onclick=()=>{index++;load();}; +for(const b of document.querySelectorAll('[data-mode]'))b.onclick=()=>selectMode(b.dataset.mode); +window.addEventListener('resize',resize); +try{const response=await fetch('./levels.json');if(!response.ok)throw new Error(response.status);levels=await response.json();selectMode(new URLSearchParams(location.search).get('mode') in copy?new URLSearchParams(location.search).get('mode'):'color');}catch(error){$('message').textContent=`关卡加载失败,请通过 npm run dev 启动后刷新。${error.message}`;} diff --git a/labs/variants/generate.mjs b/labs/variants/generate.mjs new file mode 100644 index 0000000..5d61fc4 --- /dev/null +++ b/labs/variants/generate.mjs @@ -0,0 +1,46 @@ +import { writeFileSync } from 'node:fs'; +import { hexagon, random, randomTracks, DIRS, key, trace } from '../../src/core.js'; +import { createState, solve, act, routeFor } from './model.js'; +const levels = []; +const names = { color: ['双色试航', '转向归站', '先让一路', '曲线分流', '各归其位'], switch: ['第一枚开关', '弯道解锁', '先清再切', '释放内圈', '换轨接力'], relay: ['中途停一停', '停靠再转向', '借位让路', '弯道接驳', '分段出发'] }; +for (const mode of ['color', 'switch', 'relay']) { + for (let slot = 0; slot < 5; slot++) { + let accepted = false; + for (let attempt = 0; attempt < 2500 && !accepted; attempt++) { + const seed = 901 + slot * 10000 + attempt + ['color','switch','relay'].indexOf(mode) * 100000; + const rng = random(seed), cells = hexagon(2).map((c, i) => ({ ...c, id: i, tracks: randomTracks(rng) })); + const coords = new Set(cells.map(c => key(c.q, c.r))); + const gates = cells.flatMap(c => DIRS.flatMap(([dq, dr], dir) => coords.has(key(c.q+dq,c.r+dr)) ? [] : [{ q:c.q, r:c.r, dir, color: (dir + c.q - c.r + 12) % 2 }])); + const shuffled = [...cells]; // Fisher–Yates keeps recipes reproducible. + for(let i=shuffled.length-1;i>0;i--){const j=Math.floor(rng()*(i+1));[shuffled[i],shuffled[j]]=[shuffled[j],shuffled[i]];} + const tiles = shuffled.slice(0, 3 + Math.floor(slot / 2)).map((c,i) => ({ id:`p${i}`, q:c.q,r:c.r,dir:Math.floor(rng()*6),color:i%2 })); + if (mode === 'switch') { + tiles[0].trigger = 'A'; + const target = cells.find(c => c.q === 0 && c.r === 0); + target.switchId = 'A'; target.alternate = randomTracks(rng); + } + const level = { version:1, id:`${mode}-${slot+1}`, mode, name:names[mode][slot], seed, cells, tiles, gates, stops:[{q:0,r:0}], moveLimit:tiles.length }; + const start = createState(level), solution = solve(start, 2500); + if (!solution.solved) continue; + let state = start, stopCount = 0, bends = 0, changedRoute = false, openedRoute = false; + for (const action of solution.actions) { + const result = act(state, action); + if (result.status === 'stop') stopCount++; + if (result.status === 'exit') bends += result.steps.filter(s => s.enter !== null && (s.enter+3)%6 !== s.exit).length; + if (result.state.fired.length > state.fired.length) { + openedRoute = result.state.tiles.some(t => routeFor(state, t).status !== 'exit' && routeFor(result.state, t).status === 'exit'); + changedRoute = result.state.tiles.some(t => JSON.stringify(trace(state,t,[],true).steps) !== JSON.stringify(trace(result.state,t,[],true).steps)); + } + state = result.state; + } + if (!bends || !solution.actions.some(a => a.type === 'rotate')) continue; + if (mode === 'relay' && !stopCount) continue; + if (mode === 'switch' && (!changedRoute || !openedRoute)) continue; + levels.push({ ...level, solution:solution.actions, evidence:{ bends, stopCount, changedRoute, openedRoute, states:solution.states } }); + console.log(level.id, seed, solution.actions.length); + accepted = true; + } + if (!accepted) throw new Error(`No candidate: ${mode} ${slot}`); + } +} +writeFileSync(new URL('./levels.json', import.meta.url), JSON.stringify(levels, null, 2)+'\n'); diff --git a/labs/variants/index.html b/labs/variants/index.html new file mode 100644 index 0000000..66b4cee --- /dev/null +++ b/labs/variants/index.html @@ -0,0 +1,16 @@ + + +玩法变种 · HEX TRAILS Lab +
+
← 返回主线HEX TRAILS / 独立实验
+

同一条轨道,三种新玩法

沿着弯轨出发,转动底盘寻找新的可能。

+ +

+
+
+

+
+ +
键盘操作 / 棋子列表
+
旋转时棋子位置与箭头不动。交叉不换轨,试路免费。
实验共 15 关 · 不写入主线进度
+
diff --git a/labs/variants/levels.json b/labs/variants/levels.json new file mode 100644 index 0000000..0409b78 --- /dev/null +++ b/labs/variants/levels.json @@ -0,0 +1,7639 @@ +[ + { + "version": 1, + "id": "color-1", + "mode": "color", + "name": "双色试航", + "seed": 902, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "id": "p1", + "q": 0, + "r": 1, + "dir": 5, + "color": 1 + }, + { + "id": "p2", + "q": -2, + "r": 0, + "dir": 3, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "tap", + "id": "p0" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p2" + } + ], + "evidence": { + "bends": 3, + "stopCount": 0, + "changedRoute": false, + "openedRoute": false, + "states": 28 + } + }, + { + "version": 1, + "id": "color-2", + "mode": "color", + "name": "转向归站", + "seed": 10902, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 0, + "r": -1, + "dir": 4, + "color": 0 + }, + { + "id": "p1", + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "id": "p2", + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": -1 + }, + { + "type": "tap", + "id": "p0" + } + ], + "evidence": { + "bends": 3, + "stopCount": 0, + "changedRoute": false, + "openedRoute": false, + "states": 22 + } + }, + { + "version": 1, + "id": "color-3", + "mode": "color", + "name": "先让一路", + "seed": 20904, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 1, + "r": -1, + "dir": 4, + "color": 0 + }, + { + "id": "p1", + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "id": "p2", + "q": -2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "id": "p3", + "q": -1, + "r": 1, + "dir": 4, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p3" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p0" + } + ], + "evidence": { + "bends": 7, + "stopCount": 0, + "changedRoute": false, + "openedRoute": false, + "states": 40 + } + }, + { + "version": 1, + "id": "color-4", + "mode": "color", + "name": "曲线分流", + "seed": 30904, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 0, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "id": "p1", + "q": 1, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "id": "p2", + "q": 0, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "id": "p3", + "q": -1, + "r": 2, + "dir": 5, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p3" + }, + { + "type": "rotate", + "direction": -1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": -1 + }, + { + "type": "tap", + "id": "p0" + } + ], + "evidence": { + "bends": 5, + "stopCount": 0, + "changedRoute": false, + "openedRoute": false, + "states": 52 + } + }, + { + "version": 1, + "id": "color-5", + "mode": "color", + "name": "各归其位", + "seed": 40902, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 1, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "id": "p1", + "q": -1, + "r": 2, + "dir": 0, + "color": 1 + }, + { + "id": "p2", + "q": -1, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "id": "p3", + "q": -2, + "r": 1, + "dir": 1, + "color": 1 + }, + { + "id": "p4", + "q": 2, + "r": -2, + "dir": 3, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 5, + "solution": [ + { + "type": "tap", + "id": "p0" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": -1 + }, + { + "type": "tap", + "id": "p4" + }, + { + "type": "rotate", + "direction": -1 + }, + { + "type": "tap", + "id": "p3" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + } + ], + "evidence": { + "bends": 14, + "stopCount": 0, + "changedRoute": false, + "openedRoute": false, + "states": 52 + } + }, + { + "version": 1, + "id": "switch-1", + "mode": "switch", + "name": "第一枚开关", + "seed": 100993, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 9, + "switchId": "A", + "alternate": [ + 2, + 4, + 0, + 5, + 1, + 3 + ] + }, + { + "q": 0, + "r": 1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 0, + "r": -1, + "dir": 1, + "color": 0, + "trigger": "A" + }, + { + "id": "p1", + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "id": "p2", + "q": 2, + "r": 0, + "dir": 5, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "tap", + "id": "p1" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p2" + } + ], + "evidence": { + "bends": 7, + "stopCount": 0, + "changedRoute": true, + "openedRoute": true, + "states": 20 + } + }, + { + "version": 1, + "id": "switch-2", + "mode": "switch", + "name": "弯道解锁", + "seed": 110939, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 9, + "switchId": "A", + "alternate": [ + 2, + 3, + 0, + 1, + 5, + 4 + ] + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": -1, + "r": 1, + "dir": 0, + "color": 0, + "trigger": "A" + }, + { + "id": "p1", + "q": 1, + "r": -1, + "dir": 4, + "color": 1 + }, + { + "id": "p2", + "q": 0, + "r": -1, + "dir": 5, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p1" + } + ], + "evidence": { + "bends": 6, + "stopCount": 0, + "changedRoute": true, + "openedRoute": true, + "states": 15 + } + }, + { + "version": 1, + "id": "switch-3", + "mode": "switch", + "name": "先清再切", + "seed": 120925, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 9, + "switchId": "A", + "alternate": [ + 2, + 4, + 0, + 5, + 1, + 3 + ] + }, + { + "q": 0, + "r": 1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": -1, + "r": 0, + "dir": 5, + "color": 0, + "trigger": "A" + }, + { + "id": "p1", + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "id": "p2", + "q": 1, + "r": 1, + "dir": 1, + "color": 0 + }, + { + "id": "p3", + "q": 2, + "r": -2, + "dir": 4, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p3" + } + ], + "evidence": { + "bends": 5, + "stopCount": 0, + "changedRoute": true, + "openedRoute": true, + "states": 60 + } + }, + { + "version": 1, + "id": "switch-4", + "mode": "switch", + "name": "释放内圈", + "seed": 130935, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 9, + "switchId": "A", + "alternate": [ + 2, + 5, + 0, + 4, + 3, + 1 + ] + }, + { + "q": 0, + "r": 1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": -1, + "r": -1, + "dir": 2, + "color": 0, + "trigger": "A" + }, + { + "id": "p1", + "q": -1, + "r": 1, + "dir": 1, + "color": 1 + }, + { + "id": "p2", + "q": -2, + "r": 0, + "dir": 5, + "color": 0 + }, + { + "id": "p3", + "q": 2, + "r": -2, + "dir": 4, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p3" + } + ], + "evidence": { + "bends": 12, + "stopCount": 0, + "changedRoute": true, + "openedRoute": true, + "states": 46 + } + }, + { + "version": 1, + "id": "switch-5", + "mode": "switch", + "name": "换轨接力", + "seed": 140934, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 9, + "switchId": "A", + "alternate": [ + 2, + 5, + 0, + 4, + 3, + 1 + ] + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 1, + "r": 0, + "dir": 4, + "color": 0, + "trigger": "A" + }, + { + "id": "p1", + "q": 2, + "r": 0, + "dir": 0, + "color": 1 + }, + { + "id": "p2", + "q": 1, + "r": -1, + "dir": 4, + "color": 0 + }, + { + "id": "p3", + "q": 2, + "r": -2, + "dir": 4, + "color": 1 + }, + { + "id": "p4", + "q": 1, + "r": 1, + "dir": 4, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 5, + "solution": [ + { + "type": "tap", + "id": "p4" + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p3" + } + ], + "evidence": { + "bends": 14, + "stopCount": 0, + "changedRoute": true, + "openedRoute": true, + "states": 31 + } + }, + { + "version": 1, + "id": "relay-1", + "mode": "relay", + "name": "中途停一停", + "seed": 200914, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 0, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "id": "p1", + "q": -1, + "r": 2, + "dir": 1, + "color": 1 + }, + { + "id": "p2", + "q": 1, + "r": 0, + "dir": 4, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p1" + } + ], + "evidence": { + "bends": 8, + "stopCount": 1, + "changedRoute": false, + "openedRoute": false, + "states": 22 + } + }, + { + "version": 1, + "id": "relay-2", + "mode": "relay", + "name": "停靠再转向", + "seed": 210913, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 2, + "r": -2, + "dir": 4, + "color": 0 + }, + { + "id": "p1", + "q": 0, + "r": 0, + "dir": 2, + "color": 1 + }, + { + "id": "p2", + "q": 0, + "r": -1, + "dir": 3, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 3, + "solution": [ + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p2" + } + ], + "evidence": { + "bends": 8, + "stopCount": 1, + "changedRoute": false, + "openedRoute": false, + "states": 49 + } + }, + { + "version": 1, + "id": "relay-3", + "mode": "relay", + "name": "借位让路", + "seed": 220936, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 4, + 3, + 5, + 1, + 0, + 2 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 1, + 0, + 5, + 4, + 3, + 2 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": -1, + "r": 1, + "dir": 4, + "color": 0 + }, + { + "id": "p1", + "q": 0, + "r": -2, + "dir": 2, + "color": 1 + }, + { + "id": "p2", + "q": -1, + "r": -1, + "dir": 4, + "color": 0 + }, + { + "id": "p3", + "q": -1, + "r": 0, + "dir": 2, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p1" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p3" + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p3" + } + ], + "evidence": { + "bends": 1, + "stopCount": 1, + "changedRoute": false, + "openedRoute": false, + "states": 82 + } + }, + { + "version": 1, + "id": "relay-4", + "mode": "relay", + "name": "弯道接驳", + "seed": 230902, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 3, + 2, + 1, + 0, + 5, + 4 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": 2, + "r": 0, + "dir": 3, + "color": 0 + }, + { + "id": "p1", + "q": -1, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "id": "p2", + "q": -2, + "r": 2, + "dir": 1, + "color": 0 + }, + { + "id": "p3", + "q": 0, + "r": 2, + "dir": 0, + "color": 1 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 4, + "solution": [ + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p3" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "tap", + "id": "p2" + } + ], + "evidence": { + "bends": 5, + "stopCount": 1, + "changedRoute": false, + "openedRoute": false, + "states": 182 + } + }, + { + "version": 1, + "id": "relay-5", + "mode": "relay", + "name": "分段出发", + "seed": 240901, + "cells": [ + { + "q": -2, + "r": 0, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 0 + }, + { + "q": -2, + "r": 1, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 1 + }, + { + "q": -2, + "r": 2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 2 + }, + { + "q": -1, + "r": -1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 3 + }, + { + "q": -1, + "r": 0, + "tracks": [ + 1, + 0, + 4, + 5, + 2, + 3 + ], + "id": 4 + }, + { + "q": -1, + "r": 1, + "tracks": [ + 3, + 4, + 5, + 0, + 1, + 2 + ], + "id": 5 + }, + { + "q": -1, + "r": 2, + "tracks": [ + 1, + 0, + 3, + 2, + 5, + 4 + ], + "id": 6 + }, + { + "q": 0, + "r": -2, + "tracks": [ + 2, + 3, + 0, + 1, + 5, + 4 + ], + "id": 7 + }, + { + "q": 0, + "r": -1, + "tracks": [ + 4, + 2, + 1, + 5, + 0, + 3 + ], + "id": 8 + }, + { + "q": 0, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 9 + }, + { + "q": 0, + "r": 1, + "tracks": [ + 5, + 3, + 4, + 1, + 2, + 0 + ], + "id": 10 + }, + { + "q": 0, + "r": 2, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 11 + }, + { + "q": 1, + "r": -2, + "tracks": [ + 5, + 4, + 3, + 2, + 1, + 0 + ], + "id": 12 + }, + { + "q": 1, + "r": -1, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 13 + }, + { + "q": 1, + "r": 0, + "tracks": [ + 2, + 5, + 0, + 4, + 3, + 1 + ], + "id": 14 + }, + { + "q": 1, + "r": 1, + "tracks": [ + 2, + 4, + 0, + 5, + 1, + 3 + ], + "id": 15 + }, + { + "q": 2, + "r": -2, + "tracks": [ + 5, + 2, + 1, + 4, + 3, + 0 + ], + "id": 16 + }, + { + "q": 2, + "r": -1, + "tracks": [ + 4, + 5, + 3, + 2, + 0, + 1 + ], + "id": 17 + }, + { + "q": 2, + "r": 0, + "tracks": [ + 3, + 5, + 4, + 0, + 2, + 1 + ], + "id": 18 + } + ], + "tiles": [ + { + "id": "p0", + "q": -2, + "r": 0, + "dir": 3, + "color": 0 + }, + { + "id": "p1", + "q": -1, + "r": 2, + "dir": 2, + "color": 1 + }, + { + "id": "p2", + "q": -1, + "r": 0, + "dir": 3, + "color": 0 + }, + { + "id": "p3", + "q": 2, + "r": 0, + "dir": 4, + "color": 1 + }, + { + "id": "p4", + "q": 1, + "r": 0, + "dir": 5, + "color": 0 + } + ], + "gates": [ + { + "q": -2, + "r": 0, + "dir": 0, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 0, + "dir": 5, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 4, + "color": 1 + }, + { + "q": -2, + "r": 1, + "dir": 5, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": -2, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": -2, + "r": 2, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": -1, + "dir": 0, + "color": 0 + }, + { + "q": -1, + "r": -1, + "dir": 5, + "color": 1 + }, + { + "q": -1, + "r": 2, + "dir": 3, + "color": 0 + }, + { + "q": -1, + "r": 2, + "dir": 4, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 0, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 0, + "r": -2, + "dir": 5, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 2, + "color": 0 + }, + { + "q": 0, + "r": 2, + "dir": 3, + "color": 1 + }, + { + "q": 0, + "r": 2, + "dir": 4, + "color": 0 + }, + { + "q": 1, + "r": -2, + "dir": 0, + "color": 1 + }, + { + "q": 1, + "r": -2, + "dir": 1, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 2, + "color": 0 + }, + { + "q": 1, + "r": 1, + "dir": 3, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 0, + "color": 0 + }, + { + "q": 2, + "r": -2, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": -2, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 1, + "color": 0 + }, + { + "q": 2, + "r": -1, + "dir": 2, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 1, + "color": 1 + }, + { + "q": 2, + "r": 0, + "dir": 2, + "color": 0 + }, + { + "q": 2, + "r": 0, + "dir": 3, + "color": 1 + } + ], + "stops": [ + { + "q": 0, + "r": 0 + } + ], + "moveLimit": 5, + "solution": [ + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p1" + }, + { + "type": "rotate", + "direction": 1 + }, + { + "type": "tap", + "id": "p2" + }, + { + "type": "tap", + "id": "p0" + }, + { + "type": "tap", + "id": "p4" + }, + { + "type": "tap", + "id": "p3" + }, + { + "type": "tap", + "id": "p4" + } + ], + "evidence": { + "bends": 10, + "stopCount": 1, + "changedRoute": false, + "openedRoute": false, + "states": 272 + } + } +] diff --git a/labs/variants/model.js b/labs/variants/model.js new file mode 100644 index 0000000..813c2a1 --- /dev/null +++ b/labs/variants/model.js @@ -0,0 +1,82 @@ +import { clone, trace, rotateBoard, rotateTracks, key } from '../../src/core.js'; +import { pathPoints, position, PORTS, sweepPath } from '../../src/path-math.js'; + +export function createState(level) { + return { ...clone(level), orientation: 0, fired: [] }; +} +export function routeFor(state, tile) { + let route = trace(state, tile, state.tiles, true); + let points = pathPoints(route); + if (state.mode === 'relay') { + const index = route.steps.findIndex((s, i) => i > 0 && state.stops.some(p => p.q === s.q && p.r === s.r)); + if (index >= 0) { + const stop = route.steps[index]; + const center = position(stop.q, stop.r), port = PORTS[stop.enter]; + points = [...pathPoints({ steps: route.steps.slice(0, index) }), { x: center.x + port.x, y: center.y + port.y }, center]; + route = { ...route, status: 'stop', steps: route.steps.slice(0, index + 1), end: { q: stop.q, r: stop.r }, dir: stop.exit }; + } + } + if (route.status === 'exit') { + const last = points.at(-1), port = PORTS[route.steps.at(-1).exit]; + points.push({ x: last.x + port.x * 4, y: last.y + port.y * 4 }); + } + const collision = sweepPath(points, state.tiles.filter(t => t.id !== tile.id).map(t => ({ ...position(t.q, t.r), id: t.id }))); + if (collision) return { ...route, status: 'blocked', blocker: collision.blocker, points: collision.points }; + if (route.status === 'exit' && state.mode === 'color') { + const last = route.steps.at(-1); + const gate = state.gates.find(g => g.q === last.q && g.r === last.r && g.dir === last.exit); + if (!gate || gate.color !== tile.color) return { ...route, status: 'wrong', points }; + } + return { ...route, points }; +} +export function act(state, action) { + if (action.type === 'rotate') { + const next = rotateBoard(state, action.direction); + next.orientation = (state.orientation + action.direction + 6) % 6; + const count = (action.direction + 6) % 6; + next.cells = next.cells.map(c => { + if (!c.alternate) return c; + let alternate = c.alternate; + for (let i = 0; i < count; i++) alternate = rotateTracks(alternate); + return { ...c, alternate }; + }); + return { state: next, status: 'rotate' }; + } + const tile = state.tiles.find(t => t.id === action.id); + if (!tile) return { state, status: 'invalid' }; + const route = routeFor(state, tile); + if (!['exit', 'stop'].includes(route.status)) return { state, ...route }; + const next = clone(state); + if (route.status === 'stop') { + Object.assign(next.tiles.find(t => t.id === tile.id), route.end, { dir: route.dir }); + } else { + next.tiles = next.tiles.filter(t => t.id !== tile.id); + if (state.mode === 'switch' && tile.trigger) { + next.cells = next.cells.map(c => c.switchId === tile.trigger ? { ...c, tracks: c.alternate, alternate: c.tracks } : c); + next.fired.push(tile.trigger); + } + } + return { state: next, ...route }; +} +export function signature(state) { + return `${state.orientation}|${state.fired.join(',')}|${state.tiles.map(t => `${t.id}:${key(t.q, t.r)}:${t.dir}`).join(';')}`; +} +// Unlike the main campaign, departures can change tracks and stops change occupancy. +// Search every action; never greedily drain all currently available pieces. +export function solve(state, limit = 12000) { + const queue = [{ state, actions: [] }], seen = new Set([signature(state)]); + for (let head = 0; head < queue.length && head < limit; head++) { + const node = queue[head]; + if (!node.state.tiles.length) return { solved: true, actions: node.actions, states: head + 1 }; + const actions = [...node.state.tiles.map(t => ({ type: 'tap', id: t.id })), { type: 'rotate', direction: 1 }, { type: 'rotate', direction: -1 }]; + for (const action of actions) { + const result = act(node.state, action); + if (result.state === node.state) continue; + const id = signature(result.state); + if (seen.has(id)) continue; + seen.add(id); + queue.push({ state: result.state, actions: [...node.actions, action] }); + } + } + return { solved: false, exhausted: queue.length > limit, actions: [] }; +} diff --git a/labs/variants/style.css b/labs/variants/style.css new file mode 100644 index 0000000..f72defd --- /dev/null +++ b/labs/variants/style.css @@ -0,0 +1 @@ +:root{font-family:system-ui,-apple-system,"PingFang SC",sans-serif;color:#253b4a;background:#eaf0f3;font-synthesis:none}*{box-sizing:border-box}body{margin:0}main{max-width:640px;margin:auto;padding:24px 20px}header,.level-row{display:flex;align-items:center;justify-content:space-between;gap:12px}header{font-size:12px;color:#657986}a{color:inherit}h1{font-size:27px;margin:30px 0 8px;letter-spacing:-1px}.intro{color:#657986;margin:0 0 24px;font-size:14px}button,select{font:inherit;border:1px solid #cbd7dd;border-radius:12px;background:#fff;color:#253b4a;padding:12px;cursor:pointer;touch-action:manipulation}button:hover{background:#edf5f7}button:focus-visible,select:focus-visible{outline:3px solid #387b99;outline-offset:3px}button:disabled{opacity:.4;cursor:default}.modes{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}.modes button{font-size:14px;padding:13px 3px}.modes button[aria-pressed=true]{background:#294d60;color:white;border-color:#294d60}.brief{padding:18px 0 12px;min-height:124px}.brief h2{font-size:19px;margin:0 0 8px}.brief p{margin:0;line-height:1.7;font-size:14px;color:#506674}.level-row{font-size:13px}.level-row select{padding:7px;max-width:220px}.board-wrap{width:100%;aspect-ratio:1;max-height:590px}canvas{display:block;width:100%;height:100%;touch-action:manipulation}#message{min-height:44px;margin:0 0 12px;text-align:center;font-size:14px;line-height:1.6}.controls{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}.controls button{padding:12px 3px;font-size:14px}#next{width:100%;margin-top:12px;background:#294d60;color:#fff}details{margin-top:20px;font-size:12px;color:#657986}#pieces{display:flex;gap:8px;flex-wrap:wrap;padding-top:10px}footer{font-size:12px;color:#657986;text-align:center;line-height:1.9;margin:24px 0 10px}@media(max-width:380px){main{padding:16px 12px}h1{font-size:24px}.modes button{font-size:12px}} diff --git a/scripts/build.mjs b/scripts/build.mjs index 61cb396..77170df 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -1,5 +1,5 @@ import { cp, mkdir, rm } from 'node:fs/promises'; const out=new URL('../dist/',import.meta.url); await rm(out,{recursive:true,force:true});await mkdir(out,{recursive:true}); -for(const name of ['index.html','design-showcase.html','style.css','src','levels','assets','design','Design.md','Design.html'])await cp(new URL('../'+name,import.meta.url),new URL(name,out),{recursive:true}); +for(const name of ['index.html','design-showcase.html','style.css','src','levels','assets','design','Design.md','Design.html','labs/variants'])await cp(new URL('../'+name,import.meta.url),new URL(name,out),{recursive:true}); console.log('Static build ready in dist/'); diff --git a/tests/variants.test.js b/tests/variants.test.js new file mode 100644 index 0000000..e32dc7f --- /dev/null +++ b/tests/variants.test.js @@ -0,0 +1,38 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { createState, act, routeFor, solve } from '../labs/variants/model.js'; +import { hexagon, validateLevel } from '../src/core.js'; +const levels=JSON.parse(readFileSync(new URL('../labs/variants/levels.json',import.meta.url))); +test('15 variant levels validate, solve, replay and use their mechanics',()=>{ + assert.equal(levels.length,15); + for(const level of levels){ + assert.deepEqual(validateLevel(level),[]); + let state=createState(level),stops=0; + for(const action of level.solution){const result=act(state,action);assert.notEqual(result.state,state,level.id);if(result.status==='stop')stops++;state=result.state;} + assert.equal(state.tiles.length,0,level.id); + assert.equal(solve(createState(level)).solved,true,level.id); + assert.ok(level.evidence.bends>0); + if(level.mode==='relay')assert.ok(stops>0); + if(level.mode==='switch'){assert.deepEqual(state.fired,['A']);assert.ok(level.evidence.changedRoute);assert.ok(level.evidence.openedRoute);} + } +}); +test('six rotations restore active and alternate tracks, gates and stops remain fixed',()=>{ + for(const level of levels){let state=createState(level);for(let i=0;i<6;i++)state=act(state,{type:'rotate',direction:1}).state;assert.deepEqual(state,createState(level));} +}); +test('wrong color rejects departure without mutating the snapshot',()=>{ + const state=createState({mode:'color',cells:hexagon(2),tiles:[{id:'x',q:0,r:0,dir:0,color:0}],gates:[{q:0,r:-2,dir:0,color:1}]}); + const result=act(state,{type:'tap',id:'x'});assert.equal(result.status,'wrong');assert.equal(result.state,state); + state.gates[0].color=0;assert.equal(act(state,{type:'tap',id:'x'}).state.tiles.length,0); +}); +test('relay truncates collision checking at stop and resumes to exit',()=>{ + const state=createState({mode:'relay',cells:hexagon(2),stops:[{q:0,r:0}],tiles:[{id:'x',q:0,r:2,dir:0,color:0},{id:'y',q:0,r:-2,dir:0,color:1}]}); + const result=act(state,{type:'tap',id:'x'});assert.equal(result.status,'stop');assert.equal(result.state.tiles[0].r,0);assert.equal(state.tiles[0].r,2); + assert.equal(routeFor(result.state,result.state.tiles[0]).status,'blocked'); + const cleared=act(result.state,{type:'tap',id:'y'}).state;assert.equal(act(cleared,{type:'tap',id:'x'}).status,'exit'); +}); +test('occupied stop blocks; state snapshots allow exact undo of switch and parking',()=>{ + const state=createState({mode:'relay',cells:hexagon(2),stops:[{q:0,r:0}],tiles:[{id:'x',q:0,r:2,dir:0,color:0},{id:'y',q:0,r:0,dir:0,color:1}]}); + assert.equal(act(state,{type:'tap',id:'x'}).status,'blocked'); + for(const level of levels){let current=createState(level);for(const action of level.solution){const snapshot=JSON.stringify(current);const next=act(current,action).state;assert.equal(JSON.stringify(current),snapshot);current=next;}} +});