{"spec_id":"crossword-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ncrossword-basic: Crossword Puzzle Grid\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\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\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data: 15x15 crossword grid with 180-degree rotational symmetry\ngrid_size = 15\ngrid = np.zeros((grid_size, grid_size), dtype=int)\n\nblocked_positions = [\n    (0, 4),\n    (0, 10),\n    (1, 4),\n    (1, 10),\n    (2, 7),\n    (3, 0),\n    (3, 6),\n    (3, 11),\n    (3, 12),\n    (3, 13),\n    (3, 14),\n    (4, 3),\n    (4, 8),\n    (5, 5),\n    (5, 9),\n    (5, 14),\n    (6, 2),\n    (6, 6),\n    (6, 10),\n    (7, 7),\n]\n\nfor r, c in blocked_positions:\n    grid[r, c] = 1\n    grid[grid_size - 1 - r, grid_size - 1 - c] = 1\n\n# Calculate clue numbers for cells that start across or down words\nnumbers = {}\nclue_num = 1\nfor r in range(grid_size):\n    for c in range(grid_size):\n        if grid[r, c] == 1:\n            continue\n        starts_across = (c == 0 or grid[r, c - 1] == 1) and (c < grid_size - 1 and grid[r, c + 1] == 0)\n        starts_down = (r == 0 or grid[r - 1, c] == 1) and (r < grid_size - 1 and grid[r + 1, c] == 0)\n        if starts_across or starts_down:\n            numbers[(r, c)] = clue_num\n            clue_num += 1\n\n# Cell colors: open cells are warm white, blocked cells near-black (data encoding)\n# Dark mode: use pure black for blocked cells so they contrast with #1A1A17 background\ncell_open = \"#FFFFFF\" if THEME == \"light\" else \"#FAF8F1\"\ncell_blocked = \"#1A1A17\" if THEME == \"light\" else \"#000000\"\nNUMBER_INK = \"#1A1A17\"\n\n# Plot\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\n\ncmap = sns.color_palette([cell_open, cell_blocked])\nsns.heatmap(\n    grid,\n    ax=ax,\n    cmap=cmap,\n    cbar=False,\n    square=True,\n    linewidths=1.0,\n    linecolor=INK_SOFT,\n    xticklabels=False,\n    yticklabels=False,\n)\n\n# Add clue numbers to top-left corner of numbered cells\nfor (r, c), num in numbers.items():\n    ax.text(c + 0.12, r + 0.28, str(num), fontsize=9, fontweight=\"bold\", color=NUMBER_INK, ha=\"left\", va=\"top\")\n\n# Style\nax.set_title(\"crossword-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK, pad=14)\n\nfor spine in ax.spines.values():\n    spine.set_visible(True)\n    spine.set_color(INK_SOFT)\n    spine.set_linewidth(1.5)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}