Files
kdp_generator/PLAN.md
T
2026-03-24 19:36:04 +02:00

205 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Crossword Puzzle Generator for Amazon KDP
## Overview
A Python CLI tool that reads words and clues from CSV files, generates crossword puzzle grids, and outputs print-ready PDF books formatted for Amazon KDP upload.
---
## How It Works (High Level)
1. **Read** a CSV file containing words and their clues
2. **Generate** crossword grids by placing words on a grid so they interlock at shared letters
3. **Render** each puzzle and its solution as pages in a print-ready PDF
4. **Format** the PDF to meet KDP's trim size, margin, and bleed requirements
---
## Input Format
A CSV file with at minimum two columns:
```csv
word,clue
PYTHON,"A large snake, or a programming language"
GRID,"A network of lines that cross each other"
PUZZLE,"A game or problem that tests ingenuity"
```
Optional columns:
- `difficulty` — to group words into easy/medium/hard puzzles
- `category` — to generate themed puzzles (e.g., "Animals", "Science")
---
## Core Components
### 1. CSV Parser (`csv_reader.py`)
- Read and validate the CSV (reject duplicates, too-short words, non-alpha characters)
- Normalize words to uppercase
- Group words by category/difficulty if those columns exist
- Return a list of `(word, clue)` tuples ready for the generator
### 2. Crossword Generator (`generator.py`)
This is the core algorithm. It places words onto a 2D grid so they intersect at shared letters.
**Algorithm (backtracking with heuristics):**
1. Sort words longest-first (longer words are harder to place, so do them early)
2. Place the first word horizontally in the center of the grid
3. For each remaining word:
a. Find all candidate positions where it intersects an already-placed word at a shared letter
b. Score each candidate (prefer positions that keep the grid compact and balanced)
c. Place the word at the best valid position (no collisions, no unintended adjacencies)
d. If no valid position exists, skip the word (or backtrack)
4. Number the cells (across and down) in reading order (left-to-right, top-to-bottom)
5. Return the grid, placed words with their positions/directions, and numbered clue lists
**Grid rules to enforce:**
- Words cannot run parallel and adjacent (would create unintended mini-words)
- Every letter in the grid must belong to a placed word
- Minimum grid density target to avoid sparse-looking puzzles
- Configurable grid size (e.g., 15x15 for standard, 10x10 for easy)
**Output of this step:** a `Crossword` object containing:
- The letter grid (2D array)
- List of placed words with start position, direction, and clue number
- Across clues list (numbered)
- Down clues list (numbered)
### 3. PDF Renderer (`renderer.py`)
Uses **ReportLab** to generate print-ready PDFs.
**Each puzzle produces two pages:**
1. **Puzzle page:**
- Title (e.g., "Puzzle 1" or a category name)
- The empty grid with numbered cells and black squares
- Across clues listed below or beside the grid
- Down clues listed below or beside the grid
2. **Solution page:**
- The filled grid with all letters visible
- Labeled "Solution to Puzzle N"
**Page layout considerations:**
- Grid cells should be large enough to write in (~0.3–0.4 inches per cell)
- Clue text should be readable (10–12pt font)
- Clean, professional look (black borders, light grid lines)
### 4. KDP Formatter (`kdp_format.py`)
Handles KDP-specific requirements:
- **Trim sizes:** Support common KDP sizes (8.5"x11", 6"x9", 8"x10")
- **Margins:** KDP requires minimum margins that vary by page count (typically 0.5" outside, 0.75"+ gutter/inside)
- **Page count:** Must be between 24–828 pages
- **Bleed:** Not needed for puzzle books (no content to edge)
- **Front matter:** Generate a title page, copyright page, and optional instructions page
- **Page numbering:** Footer with page numbers
- **Table of contents:** Optional, mapping puzzle numbers to pages
### 5. CLI Interface (`main.py`)
```
python main.py --input words.csv \
--output crossword_book.pdf \
--puzzles 50 \
--grid-size 15 \
--trim-size 8.5x11 \
--title "The Ultimate Crossword Book" \
--author "Your Name"
```
**Arguments:**
| Flag | Description | Default |
|------|-------------|---------|
| `--input` | Path to CSV file | required |
| `--output` | Output PDF path | `output.pdf` |
| `--puzzles` | Number of puzzles to generate | `20` |
| `--grid-size` | Grid dimensions (e.g., 15 for 15x15) | `13` |
| `--trim-size` | KDP page size | `8.5x11` |
| `--title` | Book title for the cover page | `"Crossword Puzzles"` |
| `--author` | Author name | `""` |
| `--words-per-puzzle` | Target words per puzzle | `20` |
| `--solutions-at-end` | Group all solutions at the back | `false` |
| `--seed` | Random seed for reproducibility | none |
---
## Project Structure
```
crossword-kdp-generator/
├── main.py # CLI entry point
├── csv_reader.py # CSV parsing and validation
├── generator.py # Crossword grid generation algorithm
├── renderer.py # PDF rendering (grids, clues, layout)
├── kdp_format.py # KDP trim sizes, margins, front matter
├── models.py # Data classes (Crossword, PlacedWord, Cell, etc.)
├── requirements.txt # Dependencies
├── sample_words.csv # Example input file
└── README.md # Usage instructions
```
---
## Dependencies
| Package | Purpose |
|---------|---------|
| `reportlab` | PDF generation |
| `click` | CLI argument parsing |
No heavy dependencies needed — the crossword algorithm is pure Python, and ReportLab handles all the PDF work.
---
## Generation Strategy for a Full Book
A single CSV might have hundreds of words, but each puzzle only uses ~15–25 of them. The tool will:
1. Shuffle the word list (using the optional seed for reproducibility)
2. Pull a batch of N words for each puzzle
3. Attempt to generate a crossword grid from that batch
4. If the grid doesn't meet a minimum quality threshold (too few intersections, too sparse), retry with a different subset
5. Repeat until the requested number of puzzles is generated
6. Assemble all puzzles into the final PDF with front matter and optional solutions section at the back
---
## Edge Cases to Handle
- **Too few words in CSV** — error out with a clear message
- **Words that can't interlock** — skip them, log a warning
- **Grid overflow** — if words don't fit the requested grid size, increase grid or reduce words per puzzle
- **Duplicate words across puzzles** — allow (different puzzles can reuse words) but avoid within a single puzzle
- **Non-ASCII characters** — strip accents or reject, since crosswords are typically A-Z only
- **Very long words** — warn if a word exceeds grid size
---
## Stretch Goals (Post-MVP)
- **Cover page PDF** — generate a separate KDP-compliant cover
- **Multiple difficulty levels** in one book (easy section, medium, hard)
- **Themed sections** based on CSV category column
- **Word search mode** — reuse the same CSV to generate word search puzzles too
- **Web UI** — a simple local web interface instead of CLI
- **ISBN barcode** placement on back cover
---
## Implementation Order
1. ~~`models.py` — define data structures~~ ✅
2. ~~`csv_reader.py` — parse and validate input~~ ✅
3. ~~`generator.py` — crossword algorithm (the hard part)~~ ✅
4. ~~`renderer.py` — PDF grid and clue rendering~~ ✅
5. ~~`kdp_format.py` — page layout and front matter~~ ✅
6. ~~`main.py` — wire it all together with CLI~~ ✅
7. ~~Test with sample data and iterate on grid quality~~ ✅