{"spec_id":"maze-circular","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nmaze-circular: Circular Maze Puzzle\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.collections import LineCollection\nfrom matplotlib.patches import Arc, Wedge\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\n\nGOAL_COLOR = \"#009E73\"  # Okabe-Ito position 1\nENTRY_COLOR = \"#C475FD\"  # Okabe-Ito position 2\n\n# Data — Fibonacci sector progression for naturally varied corridor widths\nnp.random.seed(13)\nrings = 6\nsectors_per_ring = [5, 8, 13, 21, 34, 34]  # Cap outer ring at 34 for solvable corridor widths\ninner_radius = 0.5\nring_width = 0.25  # Wider corridors for comfortable pen-solving\n\n# Initialize maze structure\nradial_walls = []\nring_passages = []\nfor r in range(rings):\n    radial_walls.append([True] * sectors_per_ring[r])\n    ring_passages.append([False] * sectors_per_ring[r])\n\n# Modified Prim's algorithm — guarantees exactly one solution path\nconnected = [[False] * sectors_per_ring[r] for r in range(rings)]\nconnected[0][0] = True\n\nfrontier = []\nfor s in range(sectors_per_ring[0]):\n    if s > 0:\n        frontier.append((0, s, \"radial\", 0, s - 1))\n    frontier.append((1, s * sectors_per_ring[1] // sectors_per_ring[0], \"ring\", 0, s))\n\nwhile frontier:\n    idx = np.random.randint(len(frontier))\n    r, s, conn_type, src_r, src_s = frontier.pop(idx)\n    if connected[r][s]:\n        continue\n    connected[r][s] = True\n    if conn_type == \"radial\":\n        radial_walls[r][min(s, src_s)] = False\n    else:\n        ring_passages[src_r][src_s] = True\n    num_sectors = sectors_per_ring[r]\n    next_s = (s + 1) % num_sectors\n    if not connected[r][next_s]:\n        frontier.append((r, next_s, \"radial\", r, s))\n    prev_s = (s - 1) % num_sectors\n    if not connected[r][prev_s]:\n        frontier.append((r, prev_s, \"radial\", r, s))\n    if r < rings - 1:\n        outer_sectors = sectors_per_ring[r + 1]\n        ratio = outer_sectors / num_sectors\n        for outer_s in range(int(s * ratio), int((s + 1) * ratio)):\n            if not connected[r + 1][outer_s % outer_sectors]:\n                frontier.append((r + 1, outer_s % outer_sectors, \"ring\", r, s))\n    if r > 0:\n        inner_sectors = sectors_per_ring[r - 1]\n        inner_s = int(s * inner_sectors / num_sectors)\n        if not connected[r - 1][inner_s]:\n            frontier.append((r - 1, inner_s, \"radial\", r - 1, inner_s))\n\nentry_sector = np.random.randint(sectors_per_ring[-1])\n\n# Plot — square canvas, ideal for circular maze\nouter_r = inner_radius + rings * ring_width\nmargin = outer_r * 1.38\n\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\nax.set_aspect(\"equal\")\nax.set_xlim(-margin, margin)\nax.set_ylim(-margin, margin)\nax.axis(\"off\")\n\nwall_color = INK\nwall_width = 2.5\n\n# Fill corridor area with ELEVATED_BG — distinguishes maze space from background canvas\nax.add_patch(plt.Circle((0, 0), outer_r, fill=True, facecolor=ELEVATED_BG, edgecolor=\"none\", zorder=1))\n\n# Alternating ring fills — subtle depth to distinguish inner rings from outer\nfor r in range(rings):\n    if r % 2 == 0:\n        r_inner = inner_radius + r * ring_width\n        r_outer = r_inner + ring_width\n        ax.add_patch(\n            Wedge((0, 0), r_outer, 0, 360, width=ring_width, facecolor=INK, edgecolor=\"none\", alpha=0.05, zorder=2)\n        )\n\n# Outer boundary with entry gap (two arcs bracketing the entry sector)\nentry_angle_start = entry_sector * 360 / sectors_per_ring[-1]\nentry_angle_end = (entry_sector + 1) * 360 / sectors_per_ring[-1]\n\nif entry_angle_start > 0:\n    ax.add_patch(\n        Arc(\n            (0, 0),\n            2 * outer_r,\n            2 * outer_r,\n            theta1=0,\n            theta2=entry_angle_start,\n            color=wall_color,\n            linewidth=wall_width,\n            zorder=4,\n        )\n    )\nax.add_patch(\n    Arc(\n        (0, 0),\n        2 * outer_r,\n        2 * outer_r,\n        theta1=entry_angle_end,\n        theta2=360,\n        color=wall_color,\n        linewidth=wall_width,\n        zorder=4,\n    )\n)\n\n# Ring walls — arc segments at ring boundaries with passage gaps\nfor r in range(rings - 1):\n    ring_r = inner_radius + r * ring_width\n    num_sectors = sectors_per_ring[r]\n    sector_angle = 360 / num_sectors\n    arc_r = ring_r + ring_width\n    for s in range(num_sectors):\n        if not ring_passages[r][s]:\n            ax.add_patch(\n                Arc(\n                    (0, 0),\n                    2 * arc_r,\n                    2 * arc_r,\n                    theta1=s * sector_angle,\n                    theta2=(s + 1) * sector_angle,\n                    color=wall_color,\n                    linewidth=wall_width,\n                    zorder=4,\n                )\n            )\n\n# Radial walls — batched as LineCollection for efficient compound-path rendering\nradial_segments = []\nfor r in range(rings):\n    num_sectors = sectors_per_ring[r]\n    sector_angle = 360 / num_sectors\n    r_inner = inner_radius + r * ring_width\n    r_outer = r_inner + ring_width\n    for s in range(num_sectors):\n        if radial_walls[r][s]:\n            angle = np.radians((s + 1) * sector_angle)\n            radial_segments.append(\n                [[r_inner * np.cos(angle), r_inner * np.sin(angle)], [r_outer * np.cos(angle), r_outer * np.sin(angle)]]\n            )\n\nif radial_segments:\n    ax.add_collection(LineCollection(radial_segments, colors=wall_color, linewidths=wall_width, zorder=4))\n\n# Inner boundary and goal\nax.add_patch(\n    Arc(\n        (0, 0),\n        2 * inner_radius,\n        2 * inner_radius,\n        theta1=0,\n        theta2=360,\n        color=wall_color,\n        linewidth=wall_width,\n        zorder=5,\n    )\n)\nax.add_patch(\n    plt.Circle(\n        (0, 0), inner_radius * 0.65, fill=True, facecolor=GOAL_COLOR, edgecolor=wall_color, linewidth=2, zorder=6\n    )\n)\nax.text(0, 0, \"GOAL\", ha=\"center\", va=\"center\", fontsize=8, fontweight=\"bold\", color=\"white\", zorder=7)\n\n# Entry marker\nentry_mid_angle = np.radians((entry_sector + 0.5) * 360 / sectors_per_ring[-1])\nax.text(\n    (outer_r + 0.22) * np.cos(entry_mid_angle),\n    (outer_r + 0.22) * np.sin(entry_mid_angle),\n    \"START\",\n    ha=\"center\",\n    va=\"center\",\n    fontsize=7,\n    fontweight=\"bold\",\n    color=ENTRY_COLOR,\n    zorder=7,\n)\n\n# Style\nax.set_title(\"maze-circular · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK, pad=15)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}