# puzzles — logic-puzzle generator + solver pack

Logic-puzzle generator and solver pack (pure JavaScript, zero dependencies). Generate, solve and validate classic pencil-and-paper puzzles: Sudoku (generate by difficulty easy/medium/hard/expert...


Pure JavaScript (zero npm dependencies, Node built-ins only) adapter system for **generating,
solving and validating classic logic puzzles**. Every randomized tool accepts an optional `seed`
for reproducible, deterministic output. All results are plain JSON-serializable objects.

Contract: `export default { metadata, adapters: { <tool>: (args) => result } }`. Each tool takes a
single args object (an HTTP POST body maps 1:1 onto a call).

## Tools

| Tool | Args | Returns |
|---|---|---|
| `sudokuGenerate` | `{ difficulty?: 'easy'\|'medium'\|'hard'\|'expert', seed? }` | `{ puzzle, solution, clues, blanks, string }` — a uniquely-solvable 9×9 puzzle + its solution |
| `sudokuSolve` | `{ puzzle }` (2D array, flat 81 array, or 81-char string; `0`/`.` = blank) | `{ solved, unique, solution, string }` |
| `sudokuValidate` | `{ puzzle }` | `{ valid, complete, filled, blanks, conflicts }` — checks row/col/box conflicts |
| `mazeGenerate` | `{ width?=15, height?=15, seed? }` | `{ grid, ascii, svg, start, end, width, height }` — a perfect maze |
| `mazeSolve` | `{ maze }` (an object from `mazeGenerate`) | `{ solved, path, length, start, end }` — BFS shortest path |
| `wordSearchGenerate` | `{ words?, size?, theme?, directions?=8, seed? }` | `{ grid, rows, words, unplaced, answerKey, size }` |
| `nonogramFromGrid` | `{ grid }` (2D truthy/`1`/`#`/`x`) | `{ rowClues, colClues, width, height, filled, solution }` |
| `magicSquare` | `{ n }` (odd, doubly-even, or singly-even; not 2) | `{ square, magicConstant, verified, n }` |
| `nQueens` | `{ n }` (n≥4 for solutions, ≤20) | `{ count, first, board, allSolutions?, n }` |
| `knightsTour` | `{ n, start?=[0,0] }` | `{ board, path, complete, visited, n }` — Warnsdorff's heuristic |
| `listThemes` | `{}` | `{ themes, counts }` — word-search word banks |

### Encodings
- **Sudoku** boards: `0` (or `.`) is a blank. `string` output is the 81-char row-major form.
- **Maze** `grid[y][x]` is a wall bitmask — `N=1, E=2, S=4, W=8`; a **cleared** bit is an open
  passage. `start` is `[0,0]`, `end` is `[width-1, height-1]`. `ascii` uses `#` walls / spaces;
  `svg` is a self-contained inline SVG string.
- **Word search** `answerKey` entries are `{ word, row, col, dx, dy }`; the word occupies
  `grid[row + dy*i][col + dx*i]` for `i = 0..len-1`. `directions: 4` = orthogonal only, `8` = with
  diagonals. When `words` is omitted, words are drawn from the `theme` bank (see `listThemes`).
- **Magic square** covers all three parities: Siamese method (odd `n`), diagonal-flip (doubly-even
  `n % 4 === 0`), Strachey method (singly-even `n % 4 === 2`). `verified` re-checks every row,
  column and both diagonals against `magicConstant`.
- **N-Queens** `first` is an array where index = row and value = the queen's column. For `n ≤ 12`
  all solutions are enumerated (`allSolutions` + full `count`); for larger `n` the exact `count` is
  still returned but only the first board is materialized.
- **Knight's tour** `board[r][c]` is the move index (0-based) at which the knight lands there.

## Usage

```js
import puzzles from './index.js';
const { adapters } = puzzles;

const sudoku = adapters.sudokuGenerate({ difficulty: 'hard', seed: 42 });
const solved = adapters.sudokuSolve({ puzzle: sudoku.puzzle });

const maze = adapters.mazeGenerate({ width: 20, height: 20, seed: 7 });
const route = adapters.mazeSolve({ maze });      // route.path = [[x,y], …]

adapters.wordSearchGenerate({ words: ['CAT', 'DOG'], size: 12, seed: 3 });
adapters.magicSquare({ n: 5 });                  // → { magicConstant: 65, verified: true, … }
adapters.nQueens({ n: 8 });                      // → { count: 92, … }
adapters.knightsTour({ n: 8 });                  // → { complete: true, visited: 64, … }
```

## DRY boundary

This pack owns **logic puzzles**: deterministic puzzle *structure* + constraint *solving*. It does
not overlap its neighbors:

- **`dice`** owns generic randomness — dice rolls, shuffles, coin flips, weighted loot, random
  pick. If you just need a random draw, use `dice`, not this pack.
- **`fortune`** owns novelty & trivia — fortune cookies, Magic 8-Ball, would-you-rather, trivia
  Q&A, jokes. The themed word banks in `data/wordbanks.json` here are **grid fodder** for word
  searches, not a trivia/quiz dataset.

Randomness inside this pack exists only to *generate a puzzle instance*; it is always reproducible
via `seed`.

## Files

- `index.js` — all tools + inlined helpers (seeded mulberry32 PRNG, solvers). No cross-pack imports.
- `metadata.json` — discovery metadata; `inputs[0].options` lists every tool name.
- `data/wordbanks.json` — themed uppercase word banks for `wordSearchGenerate`.


---
Source: shared/engines/adapters/domain/puzzles/README.md
Canonical: https://docs.leumas.tech/p/adapters/domain/puzzles
