{"spec_id":"maze-printable","library":"echarts","language":"javascript","code":"// anyplot.ai\n// maze-printable: Printable Maze Puzzle\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-05\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\nconst size = window.ANYPLOT_SIZE;\n\n// --- Deterministic RNG (LCG — the browser has no seeded Math.random) --------\nfunction makeLcg(seed) {\n  let state = seed >>> 0;\n  return () => {\n    state = (Math.imul(state, 1664525) + 1013904223) >>> 0;\n    return state / 4294967296;\n  };\n}\n\n// --- Maze generation: recursive backtracker (guarantees a perfect maze — --\n// --- exactly one simple path between any two cells, incl. start -> goal) --\nconst cols = 26;\nconst rows = 26;\nconst rng = makeLcg(20260905);\n\nconst index = (r, c) => r * cols + c;\nconst cells = Array.from({ length: rows * cols }, () => ({ N: true, S: true, E: true, W: true }));\nconst visited = new Array(rows * cols).fill(false);\n\nconst DIRECTIONS = [\n  { key: \"N\", opposite: \"S\", dr: -1, dc: 0 },\n  { key: \"S\", opposite: \"N\", dr: 1, dc: 0 },\n  { key: \"E\", opposite: \"W\", dr: 0, dc: 1 },\n  { key: \"W\", opposite: \"E\", dr: 0, dc: -1 },\n];\n\nconst stack = [[0, 0]];\nvisited[index(0, 0)] = true;\nwhile (stack.length > 0) {\n  const [r, c] = stack[stack.length - 1];\n  const unvisitedNeighbors = DIRECTIONS.map((d) => ({ ...d, nr: r + d.dr, nc: c + d.dc })).filter(\n    (d) => d.nr >= 0 && d.nr < rows && d.nc >= 0 && d.nc < cols && !visited[index(d.nr, d.nc)]\n  );\n\n  if (unvisitedNeighbors.length === 0) {\n    stack.pop();\n    continue;\n  }\n\n  const next = unvisitedNeighbors[Math.floor(rng() * unvisitedNeighbors.length)];\n  cells[index(r, c)][next.key] = false;\n  cells[index(next.nr, next.nc)][next.opposite] = false;\n  visited[index(next.nr, next.nc)] = true;\n  stack.push([next.nr, next.nc]);\n}\n\n// --- Layout: fit the cell grid inside the mount, below the title/caption ---\nconst margin = { top: 150, bottom: 60, left: 60, right: 60 };\nconst usableWidth = size.width - margin.left - margin.right;\nconst usableHeight = size.height - margin.top - margin.bottom;\nconst cellSize = Math.min(usableWidth / cols, usableHeight / rows);\nconst gridWidth = cellSize * cols;\nconst gridHeight = cellSize * rows;\nconst originX = margin.left + (usableWidth - gridWidth) / 2;\nconst originY = margin.top + (usableHeight - gridHeight) / 2;\n\nconst cellLeft = (c) => originX + c * cellSize;\nconst cellTop = (r) => originY + r * cellSize;\n\n// --- Walls as individual line segments (N + W per cell, plus the two -------\n// --- outer edges so the boundary is never drawn twice) ----------------------\nconst wallWidth = Math.max(3, cellSize * 0.12);\nconst wallSegments = [];\nfor (let r = 0; r < rows; r += 1) {\n  for (let c = 0; c < cols; c += 1) {\n    const cell = cells[index(r, c)];\n    const x0 = cellLeft(c);\n    const y0 = cellTop(r);\n    const x1 = x0 + cellSize;\n    const y1 = y0 + cellSize;\n    if (cell.N) wallSegments.push([x0, y0, x1, y0]);\n    if (cell.W) wallSegments.push([x0, y0, x0, y1]);\n    if (r === rows - 1 && cell.S) wallSegments.push([x0, y1, x1, y1]);\n    if (c === cols - 1 && cell.E) wallSegments.push([x1, y0, x1, y1]);\n  }\n}\n\nconst wallElements = wallSegments.map(([x1, y1, x2, y2]) => ({\n  type: \"line\",\n  shape: { x1, y1, x2, y2 },\n  style: { stroke: t.ink, lineWidth: wallWidth, lineCap: \"square\" },\n  silent: true,\n}));\n\n// --- Heavier outer border frames the puzzle and separates it from the -------\n// --- page, reinforcing the print-ready boundary beyond the interior walls --\nconst outerBorder = {\n  type: \"rect\",\n  shape: { x: originX, y: originY, width: gridWidth, height: gridHeight },\n  style: { stroke: t.ink, lineWidth: wallWidth * 2, fill: \"transparent\" },\n  silent: true,\n};\n\n// --- Start / goal markers (traffic-light convention: green = go, red = stop)\nconst markerRadius = cellSize * 0.36;\nconst markerFont = Math.max(14, cellSize * 0.55);\nconst startCenter = { cx: cellLeft(0) + cellSize / 2, cy: cellTop(0) + cellSize / 2 };\nconst goalCenter = { cx: cellLeft(cols - 1) + cellSize / 2, cy: cellTop(rows - 1) + cellSize / 2 };\n\n// Soft radial halos (echarts.graphic.RadialGradient) behind each marker —\n// an ECharts-distinctive touch that draws the eye from start to goal.\nconst hexToRgba = (hex, alpha) => {\n  const n = parseInt(hex.slice(1), 16);\n  const r = (n >> 16) & 255;\n  const g = (n >> 8) & 255;\n  const b = n & 255;\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\nconst makeHalo = (cx, cy, color) => ({\n  type: \"circle\",\n  shape: { cx, cy, r: markerRadius * 1.9 },\n  style: {\n    fill: new echarts.graphic.RadialGradient(0.5, 0.5, 0.5, [\n      { offset: 0, color: hexToRgba(color, 0.32) },\n      { offset: 1, color: hexToRgba(color, 0) },\n    ]),\n  },\n  silent: true,\n});\n\nconst startHalo = makeHalo(startCenter.cx, startCenter.cy, t.palette[0]);\nconst goalHalo = makeHalo(goalCenter.cx, goalCenter.cy, \"#AE3030\");\n\nconst startMarker = {\n  type: \"circle\",\n  shape: { cx: startCenter.cx, cy: startCenter.cy, r: markerRadius },\n  style: {\n    fill: t.palette[0],\n    text: \"S\",\n    textFill: t.pageBg,\n    textPosition: \"inside\",\n    fontSize: markerFont,\n    fontWeight: \"bold\",\n  },\n  silent: true,\n};\n\nconst goalMarker = {\n  type: \"circle\",\n  shape: { cx: goalCenter.cx, cy: goalCenter.cy, r: markerRadius },\n  style: {\n    fill: \"#AE3030\",\n    text: \"G\",\n    textFill: t.pageBg,\n    textPosition: \"inside\",\n    fontSize: markerFont,\n    fontWeight: \"bold\",\n  },\n  silent: true,\n};\n\nconst caption = {\n  type: \"text\",\n  left: \"center\",\n  top: 78,\n  style: {\n    text: `${cols} × ${rows} cells · one guaranteed solution path`,\n    fill: t.inkSoft,\n    fontSize: 18,\n  },\n};\n\n// --- Init --------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option ------------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"maze-printable · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 28,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  graphic: {\n    elements: [caption, startHalo, goalHalo, ...wallElements, outerBorder, startMarker, goalMarker],\n  },\n});\n"}