{"spec_id":"maze-printable","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nmaze-printable: Printable Maze Puzzle\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-16\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nBRAND = \"#009E73\"  # Okabe-Ito position 1\n\n# Maze generation parameters\nnp.random.seed(42)\nwidth = 25\nheight = 25\n\n# Initialize maze grid (True = wall, False = passage)\n# Using cells and walls representation\nmaze = np.ones((2 * height + 1, 2 * width + 1), dtype=bool)\n\n# Mark all cells as passages initially (odd indices)\nfor y in range(height):\n    for x in range(width):\n        maze[2 * y + 1, 2 * x + 1] = False\n\n# DFS maze generation algorithm\nvisited = np.zeros((height, width), dtype=bool)\nstack = [(0, 0)]\nvisited[0, 0] = True\n\ndirections = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # right, down, left, up\n\nwhile stack:\n    cy, cx = stack[-1]\n\n    # Find unvisited neighbors\n    neighbors = []\n    for dy, dx in directions:\n        ny, nx = cy + dy, cx + dx\n        if 0 <= ny < height and 0 <= nx < width and not visited[ny, nx]:\n            neighbors.append((ny, nx, dy, dx))\n\n    if neighbors:\n        # Choose random neighbor\n        ny, nx, dy, dx = neighbors[np.random.randint(len(neighbors))]\n        # Remove wall between current cell and neighbor\n        maze[2 * cy + 1 + dy, 2 * cx + 1 + dx] = False\n        visited[ny, nx] = True\n        stack.append((ny, nx))\n    else:\n        stack.pop()\n\n# Create entrance (top of first cell) and exit (bottom of last cell)\nmaze[0, 1] = False  # Entrance opening at top-left\nmaze[2 * height, 2 * width - 1] = False  # Exit opening at bottom-right\n\n# Create figure\nfig = go.Figure()\n\n# Theme-specific colors for maze elements\nif THEME == \"light\":\n    # Light theme: black walls on white background (printable)\n    wall_color = INK\n    passage_color = None  # Passages implicit as white background\nelse:\n    # Dark theme: explicitly draw passages as medium gray for visibility\n    wall_color = INK_SOFT  # Light gray walls\n    passage_color = \"#4A4A44\"  # Medium gray passages (distinct from dark bg and light walls)\n\n# Draw maze elements as shapes\nwall_shapes = []\n\nfor y in range(maze.shape[0]):\n    for x in range(maze.shape[1]):\n        if maze[y, x]:  # Wall\n            wall_shapes.append(\n                {\n                    \"type\": \"rect\",\n                    \"x0\": x - 0.5,\n                    \"y0\": (maze.shape[0] - 1 - y) - 0.5,\n                    \"x1\": x + 0.5,\n                    \"y1\": (maze.shape[0] - 1 - y) + 0.5,\n                    \"fillcolor\": wall_color,\n                    \"line\": {\"width\": 0},\n                }\n            )\n        elif THEME == \"dark\" and passage_color:  # Passage in dark theme\n            wall_shapes.append(\n                {\n                    \"type\": \"rect\",\n                    \"x0\": x - 0.5,\n                    \"y0\": (maze.shape[0] - 1 - y) - 0.5,\n                    \"x1\": x + 0.5,\n                    \"y1\": (maze.shape[0] - 1 - y) + 0.5,\n                    \"fillcolor\": passage_color,\n                    \"line\": {\"width\": 0},\n                }\n            )\n\n# Add start marker \"START\" above entrance opening with arrow pointing down\nstart_x = 1  # Entrance column in maze coordinates\nstart_y = maze.shape[0] - 1 - 0  # Top row (entrance)\n\nfig.add_annotation(\n    x=start_x,\n    y=start_y + 2,  # Position above the maze\n    text=\"<b>START</b>\",\n    font={\"size\": 32, \"color\": BRAND},\n    showarrow=True,\n    arrowhead=2,\n    arrowsize=2,\n    arrowwidth=4,\n    arrowcolor=BRAND,\n    ay=-50,  # Arrow points down\n    ax=0,\n    yanchor=\"bottom\",\n)\n\n# Add goal marker \"GOAL\" below exit opening with arrow pointing up\ngoal_x = maze.shape[1] - 2  # Exit column in maze coordinates\ngoal_y = 0  # Bottom row (exit)\n\nfig.add_annotation(\n    x=goal_x,\n    y=goal_y - 2,  # Position below the maze\n    text=\"<b>GOAL</b>\",\n    font={\"size\": 32, \"color\": BRAND},\n    showarrow=True,\n    arrowhead=2,\n    arrowsize=2,\n    arrowwidth=4,\n    arrowcolor=BRAND,\n    ay=50,  # Arrow points up\n    ax=0,\n    yanchor=\"top\",\n)\n\n# Update layout\nfig.update_layout(\n    title={\n        \"text\": \"maze-printable · plotly · anyplot.ai\",\n        \"font\": {\"size\": 36, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    shapes=wall_shapes,\n    xaxis={\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"showticklabels\": False,\n        \"scaleanchor\": \"y\",\n        \"scaleratio\": 1,\n        \"range\": [-3, maze.shape[1] + 2],\n        \"showline\": False,\n    },\n    yaxis={\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"showticklabels\": False,\n        \"range\": [-4, maze.shape[0] + 3],\n        \"showline\": False,\n    },\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    margin={\"l\": 60, \"r\": 60, \"t\": 100, \"b\": 60},\n    width=3600,\n    height=3600,\n)\n\n# Save as PNG and HTML\nfig.write_image(f\"plot-{THEME}.png\", width=3600, height=3600, scale=1)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}