{ "version": "3.16", "name": "CaveZoneScout", "description": "Writes a cave-search program into an isolated child space, runs it, and captures the trace/report.", "steps": [ { "id": "Tool_010_WriteMap", "tool": "WriteFile", "input": { "file_path": "=\"cave.json\"", "content": "=mapJson" }, "next": "Tool_020_WriteSolver" }, { "id": "Tool_020_WriteSolver", "tool": "WriteFile", "input": { "file_path": "=\"explore-cave.mjs\"", "content": "import fs from 'fs';\n\nconst cavePath = process.argv[2] || 'cave.json';\nconst cave = JSON.parse(fs.readFileSync(cavePath, 'utf8'));\nconst trace = [];\nconst seen = new Map();\nlet best = null;\n\nfunction scoreState(node, energy, crystals, path) {\n return (node === cave.goal ? 500 : 0) + (crystals * 11) + energy - path.length;\n}\n\nfunction remember(signature, score) {\n const prev = seen.get(signature) ?? -Infinity;\n if (prev >= score) return false;\n seen.set(signature, score);\n return true;\n}\n\nfunction explore(node, energy, crystals, path, visitedRooms) {\n const room = cave.rooms[node] || {};\n const nextVisitedRooms = new Set(visitedRooms);\n const gained = nextVisitedRooms.has(node) ? 0 : (room.crystals || 0);\n nextVisitedRooms.add(node);\n const nextCrystals = crystals + gained;\n const nextPath = [...path, node];\n const signature = [node, energy, nextCrystals, [...nextVisitedRooms].sort().join(',')].join('|');\n const score = scoreState(node, energy, nextCrystals, nextPath);\n if (!remember(signature, score)) return;\n\n trace.push(`visit=${node}; energy=${energy}; crystals=${nextCrystals}; path=${nextPath.join('>')}`);\n if (!best || score > best.score) {\n best = { node, energy, crystals: nextCrystals, path: nextPath, score };\n }\n if (node === cave.goal) return;\n\n const edges = (cave.tunnels[node] || []).slice().sort((a, b) => {\n const aReward = (cave.rooms[a.to]?.crystals || 0) - a.cost;\n const bReward = (cave.rooms[b.to]?.crystals || 0) - b.cost;\n return bReward - aReward;\n });\n\n for (const edge of edges) {\n if (energy < edge.cost) {\n trace.push(`skip=${node}->${edge.to}; reason=energy; need=${edge.cost}; have=${energy}`);\n continue;\n }\n const recharge = cave.rooms[edge.to]?.recharge || 0;\n explore(edge.to, energy - edge.cost + recharge, nextCrystals, nextPath, nextVisitedRooms);\n }\n}\n\nexplore(cave.start, cave.energy, 0, [], new Set());\n\nconst reportLines = [\n `zone=${cave.zone}`,\n `goal=${cave.goal}`,\n `bestNode=${best?.node || 'unknown'}`,\n `score=${best?.score ?? 0}`,\n `energyLeft=${best?.energy ?? 0}`,\n `crystals=${best?.crystals ?? 0}`,\n `route=${best?.path?.join('>') || ''}`\n];\n\nfs.writeFileSync('report.txt', reportLines.join('\\n'));\nfs.writeFileSync('trace.txt', trace.join('\\n'));\nconsole.log(`best=${best?.node || 'unknown'}; score=${best?.score ?? 0}; route=${best?.path?.join('>') || ''}; crystals=${best?.crystals ?? 0}`);\n" }, "next": "Tool_030_RunSolver" }, { "id": "Tool_030_RunSolver", "tool": "Bash", "input": { "command": "=\"node explore-cave.mjs cave.json\"" }, "out": { "$solverStdout": "=_result" }, "next": "Tool_040_ReadReport" }, { "id": "Tool_040_ReadReport", "tool": "ReadFile", "input": { "file_path": "=\"report.txt\"" }, "out": { "$reportText": "=_result" }, "next": "Tool_050_ReadTrace" }, { "id": "Tool_050_ReadTrace", "tool": "ReadFile", "input": { "file_path": "=\"trace.txt\"", "limit": 80 }, "out": { "$traceText": "=_result" }, "next": "Set_060_Summary" }, { "id": "Set_060_Summary", "target": "$zoneSummary", "value": "=zoneName + \" => \" + $solverStdout", "next": "Write_070_Summary" }, { "id": "Write_070_Summary", "target": "=\"Artifacts/zone-summary.txt\"", "value": "=$zoneSummary", "mode": "overwrite", "next": "Stop_End" }, { "id": "Stop_End" } ] }