{"spec_id":"maze-printable","library":"makie","language":"julia","code":"# anyplot.ai\n# maze-printable: Printable Maze Puzzle\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 90/100 | Created: 2026-09-05\n\nusing CairoMakie\nusing Colors\nusing Random\n\n# --- Theme tokens ------------------------------------------------------------\nTHEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nPAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nINK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nINK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nIMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#AE3030\", colorant\"#2ABCCD\", colorant\"#954477\", colorant\"#99B314\",\n]\n\n# --- Data: perfect maze via randomized depth-first carving --------------------\n# A spanning-tree maze (every cell reachable, no loops) guarantees exactly one\n# simple path between any two cells, which is what makes the puzzle solvable\n# with a single unambiguous route.\nRandom.seed!(42)\n\nwidth = 25\nheight = 25\n\nwall_n = trues(height, width)\nwall_s = trues(height, width)\nwall_e = trues(height, width)\nwall_w = trues(height, width)\n\nvisited = falses(height, width)\nstack = [(1, 1)]\nvisited[1, 1] = true\n\nwhile !isempty(stack)\n    r, c = stack[end]\n    neighbors = Tuple{Int,Int,Symbol}[]\n    r > 1 && !visited[r-1, c] && push!(neighbors, (r - 1, c, :N))\n    r < height && !visited[r+1, c] && push!(neighbors, (r + 1, c, :S))\n    c < width && !visited[r, c+1] && push!(neighbors, (r, c + 1, :E))\n    c > 1 && !visited[r, c-1] && push!(neighbors, (r, c - 1, :W))\n\n    if isempty(neighbors)\n        pop!(stack)\n        continue\n    end\n\n    nr, nc, direction = rand(neighbors)\n    if direction == :N\n        wall_n[r, c] = false\n        wall_s[nr, nc] = false\n    elseif direction == :S\n        wall_s[r, c] = false\n        wall_n[nr, nc] = false\n    elseif direction == :E\n        wall_e[r, c] = false\n        wall_w[nr, nc] = false\n    else\n        wall_w[r, c] = false\n        wall_e[nr, nc] = false\n    end\n    visited[nr, nc] = true\n    push!(stack, (nr, nc))\nend\n\nwall_segments = Point2f[]\nfor r in 1:height, c in 1:width\n    x0, x1 = Float32(c - 1), Float32(c)\n    y0, y1 = Float32(height - r), Float32(height - r + 1)\n    if wall_n[r, c]\n        push!(wall_segments, Point2f(x0, y1), Point2f(x1, y1))\n    end\n    if wall_s[r, c]\n        push!(wall_segments, Point2f(x0, y0), Point2f(x1, y0))\n    end\n    if wall_w[r, c]\n        push!(wall_segments, Point2f(x0, y0), Point2f(x0, y1))\n    end\n    if wall_e[r, c]\n        push!(wall_segments, Point2f(x1, y0), Point2f(x1, y1))\n    end\nend\n\nstart_point = Point2f(0.5, height - 0.5)\ngoal_point = Point2f(width - 0.5, 0.5)\n\n# Softly rounded print-frame border around the maze — a Makie `poly!`-built\n# rounded rectangle (traced corner-arc by corner-arc) rather than a plain\n# `lines!` rectangle, giving the puzzle sheet a finished, card-like edge.\nframe_x0, frame_x1 = -0.6, width + 0.6\nframe_y0, frame_y1 = -0.6, height + 0.6\nframe_r = 0.6\nframe_corners = [\n    (frame_x1 - frame_r, frame_y0 + frame_r, -90.0, 0.0),\n    (frame_x1 - frame_r, frame_y1 - frame_r, 0.0, 90.0),\n    (frame_x0 + frame_r, frame_y1 - frame_r, 90.0, 180.0),\n    (frame_x0 + frame_r, frame_y0 + frame_r, 180.0, 270.0),\n]\nframe_pts = Point2f[]\nfor (cx, cy, a0, a1) in frame_corners\n    for t in range(a0, a1; length=12)\n        θ = deg2rad(t)\n        push!(frame_pts, Point2f(cx + frame_r * cos(θ), cy + frame_r * sin(θ)))\n    end\nend\n\n# --- Plot ----------------------------------------------------------------------\nfig = Figure(\n    size=(1200, 1200),\n    fontsize=14,\n    backgroundcolor=PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title=\"maze-printable · julia · makie · anyplot.ai\",\n    titlesize=20,\n    titlecolor=INK,\n    backgroundcolor=PAGE_BG,\n    aspect=DataAspect(),\n)\nhidedecorations!(ax)\nhidespines!(ax)\nlimits!(ax, -1.0, width + 1.0, -1.0, height + 1.0)\n\n# Subtle accent tint on the start/goal cells — a light hint of visual\n# hierarchy beyond the markers themselves, reinforcing the start-to-goal\n# narrative before the walls are drawn on top.\npoly!(ax, Rect2f(0, height - 1, 1, 1); color=(IMPRINT_PALETTE[1], 0.12), strokewidth=0)\npoly!(ax, Rect2f(width - 1, 0, 1, 1); color=(IMPRINT_PALETTE[5], 0.12), strokewidth=0)\n\nlinesegments!(ax, wall_segments; color=INK, linewidth=6)\n\npoly!(ax, frame_pts; color=(PAGE_BG, 0.0), strokecolor=INK_SOFT, strokewidth=3)\n\n# Start (brand green, \"go\") and goal (matte red, \"stop\") — the traffic-light\n# green/red convention is a strong, widely shared color cue (semantic\n# exception in the Imprint palette), so both markers borrow from that\n# association instead of the plain 1→N categorical order.\nscatter!(ax, [start_point]; color=IMPRINT_PALETTE[1], markersize=36, strokewidth=0)\ntext!(ax, start_point; text=\"S\", color=PAGE_BG, fontsize=20, align=(:center, :center))\n\nscatter!(ax, [goal_point]; color=IMPRINT_PALETTE[5], markersize=36, strokewidth=0)\ntext!(ax, goal_point; text=\"G\", color=PAGE_BG, fontsize=20, align=(:center, :center))\n\n# --- Save ------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit=2)\n"}