205 lines
7.5 KiB
Markdown
205 lines
7.5 KiB
Markdown
# 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~~ ✅
|