Skip to content

Latest commit

 

History

History
202 lines (150 loc) · 6.27 KB

File metadata and controls

202 lines (150 loc) · 6.27 KB

puz

A command-line toolkit for reading, validating, and extracting data from .puz crossword files. It parses puzzles to JSON, validates directories in bulk, inspects raw file structure, and exports clue/answer data. It's built on the puz-parse library.

Contents

Installation

cargo install puz

Or build from source:

git clone https://github.com/mwln/puz.rs.git
cd puz.rs
cargo install --path cli

Prebuilt binaries for common platforms are also attached to each release.

Commands

puz [FILES]...              parse puzzles to JSON (default)
puz parse [FILES]...        parse puzzles to JSON (explicit form)
puz validate <DIR>          bulk-validate every .puz file under a directory
puz export <DIR>            export clue/answer pairs as JSON Lines
puz dump header <FILE>      declared dimensions, clue count, bitmask, version
puz dump grid <FILE>        the solution and blank grids, with any mismatches
puz dump strings <FILE>     title, author, copyright, the clue list, and notes
puz dump clues <FILE>       clue numbering vs. the file's declared/provided clues
puz dump answers <FILE>     clues paired with their answers, as a JSON array
puz inspect sections <FILE> extension sections (GRBS, RTBL, GEXT, ...)

The dump and inspect commands read the file bytes directly rather than fully parsing, so they still produce useful output for files that fail to parse.

Colored, Unicode-styled output is used when writing to a terminal. It is disabled automatically when output is redirected (e.g. piped to a file), when the NO_COLOR environment variable is set, or with the global --no-color flag.

Parsing to JSON

Running puz with file arguments (no subcommand) parses them to JSON, the same as puz parse. Parse warnings are printed to stderr.

Parse a file and print JSON to stdout:

puz puzzle.puz

Pretty-print the output:

puz puzzle.puz --pretty

Parse several files at once (returned as a JSON array):

puz puzzle1.puz puzzle2.puz --pretty

For a single file, drop the surrounding array and print just the object:

puz puzzle.puz --single --pretty

Write to a file instead of stdout:

puz puzzle.puz --output output.json

Options (parse)

Option Description
<FILES>... One or more .puz files to parse. Supports shell globs.
-o, --output <FILE> Write output to a file instead of stdout.
-p, --pretty Indent the JSON for readability.
-s, --single For a single file, output the puzzle object directly instead of wrapping it in an array.

Validating a directory

Recursively parse every .puz file under a directory and print a summary of parse errors and warnings:

puz validate ./puzzles
Option Description
<DIR> Directory to scan recursively for .puz files.
--verbose Print a line for every file, including clean ones.
--errors-only Print only hard parse failures, not warnings.

Exporting clue/answer pairs

Extract every clue paired with its answer across a directory, as JSON Lines (one JSON object per line):

puz export ./puzzles > clues.jsonl

Each line has the fields reliably found in the file, plus the source path:

{
  "file": "<path>",
  "title": "<string>",
  "author": "<string>",
  "direction": "across|down",
  "number": <int>,
  "clue": "<string>",
  "answer": "<string>"
}

Outlet and date are not emitted: they are inconsistent inside .puz files and usually live in the directory layout. Derive them from file downstream. A progress summary is written to stderr, so redirecting stdout gives a clean data file. Files that fail to parse are skipped with a note on stderr.

The output streams, so it composes with standard tools:

puz export ./puzzles | jq -r 'select(.answer == "OREO") | .clue' | sort | uniq -c

Inspecting a file

The dump and inspect commands show a file's raw structure. They are useful for understanding an unusual puzzle or debugging one that does not parse.

puz dump header  puzzle.puz    # dimensions, clue count, bitmask, version
puz dump grid    puzzle.puz    # solution + blank grids, black-square mismatches
puz dump strings puzzle.puz    # title/author/copyright, numbered clues, notes
puz dump clues   puzzle.puz    # computed clue numbering vs. the file's clue list
puz dump answers puzzle.puz    # clues paired with answers, as JSON
puz inspect sections puzzle.puz  # GRBS / RTBL / GEXT extension sections

dump clues is handy for puzzles whose declared clue count does not match the grid geometry: it shows the across/down slot counts, the declared num_clues, the number of clue strings in the file, and any extras.

dump answers prints a JSON array of every clue with the answer read from the solution grid, one object per entry:

[
  { "direction": "across", "number": 1, "clue": "Cry of disgust", "answer": "BAH" },
  { "direction": "down", "number": 1, "clue": "...", "answer": "BRAVE" }
]

The answer is the solution-grid characters for that slot, taken as-is, so a rebus or theme cell shows whatever character the grid stores. Pass --pretty to indent the output. This is a quick way to check that a puzzle's clues and answers line up.

Output format

The parse command (and the bare puz FILES... default) prints a JSON array of parsed puzzles, one entry per input file. With --single and exactly one file, it prints that puzzle object on its own.

Each puzzle object mirrors the puz-parse data model:

  • info: metadata (title, author, copyright, notes, width, height, version, scrambled flag, diagramless flag)
  • grid: the blank and solution grids, each an array of row strings
  • clues: across and down clues keyed by clue number, plus the raw clue list
  • extensions: rebus, circled, and given squares, when the puzzle has them

See the puz-parse README for what each field contains.

License

Licensed under the MIT License.