Python API
Everything below is importable from pencilmark directly (pencilmark.rate, pencilmark.to_export, …). This page is generated from the docstrings (tools/gen_api_md.py).
| Name | What it does |
|---|---|
def rate | The "sudoku-grade" card of one puzzle (Grade card), with only the fields you ask for. |
def rate_many | Cards for many puzzles, in input order. |
def describe | The variant name and its rules in words, from the rules alone (pencilmark/variants.py). |
def solve | The unique solution of a puzzle. |
def count_solutions | How many solutions a puzzle has, counting up to a limit. |
def generate | One puzzle for a "sudoku-spec" request (Generator spec). |
def load | Any accepted input -> a finalised engine Puzzle. |
def validate | Strict reading checks of a format_version 1 dict (Puzzle format section 4). |
def fingerprint | Content fingerprint of a puzzle: "sha256:<hex>" of its canonical form. |
def to_export | The sudoku-puzzle dict of a puzzle (format_version 1, Puzzle format). |
def dumps | Canonical JSON text of a sudoku-puzzle dict: fixed key order; pretty: one grid row per line, one rule per… |
def from_string | A puzzle as text -> sudoku-puzzle dict (Other formats). |
def to_string | A puzzle as text (Other formats). |
def from_ipuz | An ipuz sudoku -> sudoku-puzzle dict (Other formats). |
def to_ipuz | A puzzle as an ipuz 2 dict (Other formats). |
class NotUnique | the puzzle has more than one solution |
class NoSolution | the puzzle has no solution |
class Undecided | the exhaustive search hit its node limit and OR-Tools (pip install "pencilmark[verify]") is not available |
Grading
def rate(puzzle, steps=False, max_seconds=None, mode='human', se=False, fields=None, allow_guessing=False, explain=None, quality=None, alternatives=True)source
The "sudoku-grade" card of one puzzle (Grade card), with only the fields you ask for.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts: an 81-character string, a sudoku-puzzle dict or JSON text, a .json file, an ipuz file, a SudokuPad / f-puzzles / Penpa / Logic Masters link.stepsbool — Shorthand for thestepsfield with every explanation level.max_secondsfloat, optional — One wall-clock limit for the whole call. When it passes, the card says band "Unknown", difficulty and time are null andcompletedis false.modestr — "human" (default): human techniques only, a proof by full search where they stop; "computer": also forcing chains and nets, Nishio and trial.sebool — Shorthand for thesefield (Sudoku Explainer-style ratings; classic sudoku only).fieldslist of str, optional — The top-level fields to return. Default: difficulty, time, band, contains. Optional: band_index, issues, reject, warning (publishing checks), time_mean, time_pNN (any percentile 1-99, e.g. time_p80), time_dist, elapsed (wall seconds of the call), se, steps, describe, symmetry. format, format_version and grader are always present.allow_guessingbool — Guess where no technique applies (band "Unknown") instead of proving by full search (Trial and error, Extreme).explainstr, list of str or bool, optional — Explanation levels for the steps: "notation", "short", "teach", or True for all of them.qualitydict, optional — Settings of the issue checks, e.g. {"trivial": {"limit": 0.5}, "trial": {"severity": "off"}} (Grade card 4).alternativesbool — False skips the search for interchangeable techniques (each chip in contains lists one code). Band, difficulty and time are the same either way, and the card comes much faster.
- Returns
- dict — The card. Its steps walk the shortest technique list's route when the card asks for contains (or issues, reject or warning), else the full first route (Grade card 5).
- Raises
- NotUnique — The puzzle has more than one solution.
- NoSolution — The puzzle has no solution.
- Undecided — The uniqueness search hit its limit without OR-Tools installed, or max_seconds passed first.
def rate_many(puzzles, jobs=1, steps=False, max_seconds=None, mode='human', se=False, fields=None, allow_guessing=False, explain=None, quality=None, alternatives=True)source
Cards for many puzzles, in input order.
- Parameters
puzzlesiterable — Puzzles in any formrateaccepts.jobsint — Worker processes; 1 rates in this process.steps, max_seconds, mode, se, fields, allow_guessing, explain, quality, alternatives— As forrate.
- Returns
- list of dict — One card per puzzle. A puzzle that cannot be rated (not unique, no solution, unreadable) gives {"error": "..."} instead of raising.
def describe(puzzle)source
The variant name and its rules in words, from the rules alone (pencilmark/variants.py).
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.
- Returns
- dict — {"type": variant name, "rules": {short name: one-sentence rule, ...}}.
Solving
def solve(puzzle, info=False)source
The unique solution of a puzzle.
Uses the engine's exhaustive C++ search; CP-SAT (OR-Tools, optional) only when that search hits its node limit.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.infobool — Return {"solution": [...], "seconds": wall-clock seconds of the search} instead of the bare list.
- Returns
- list of int — The digits in the puzzle's cell order.
- Raises
- NotUnique — More than one solution.
- NoSolution — No solution.
- Undecided — The search hit its node limit and OR-Tools is not installed.
def count_solutions(puzzle, limit=1000)source
How many solutions a puzzle has, counting up to a limit.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.limitint — Stop counting here.
- Returns
- dict — {"count": n, "exact": bool}. exact is false when there are at least n: the count reached
limit, or the search hit its node limit without OR-Tools installed.
- dict — {"count": n, "exact": bool}. exact is false when there are at least n: the count reached
Generating
def generate(spec)source
One puzzle for a "sudoku-spec" request (Generator spec).
- Parameters
specdict, str or Path — The request: a dict, JSON text or a path to a .json file.
- Returns
- dict — {"puzzle": sudoku-puzzle dict, "card": its sudoku-grade card, "info": {...}}.
- Raises
- GenerationFailed — No puzzle met the request in the time it allows.
Reading and writing
def load(puzzle)source
Any accepted input -> a finalised engine Puzzle.
- Parameters
puzzlestr, dict, Path or Puzzle — A classic string (81 characters, with or without a trailing comment), a text or pencil-mark grid, a sudokuwiki packed string, a sudoku-puzzle dict or JSON text, an ipuz file, a .json path, a SudokuPad / f-puzzles / Penpa / Logic Masters link, or an engine Puzzle (returned as it is).
- Returns
- Puzzle — The engine's puzzle.
- Raises
- FormatError — A sudoku-puzzle document that breaks the format.
- TypeError — An input of no known form.
def validate(doc)source
Strict reading checks of a format_version 1 dict (Puzzle format section 4).
- Parameters
docdict — A sudoku-puzzle document.
- Returns
- bool — True.
- Raises
- FormatError — The document breaks the format; the message names the rule and the problem.
def fingerprint(puzzle)source
Content fingerprint of a puzzle: "sha256:<hex>" of its canonical form.
Covers the rules, grid, givens and candidates; not meta, style or the solution. Two files of the same puzzle get the same fingerprint.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.
- Returns
- str — "sha256:" followed by 64 hex digits.
def to_export(puzzle, meta=None, with_solution=True, describe=True, **meta_kw)source
The sudoku-puzzle dict of a puzzle (format_version 1, Puzzle format).
Canonical: houses and rules with "r1c1" cells, keys in a fixed order. Metadata already in a JSON input is kept.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.metadict, optional — Metadata for the "meta" object, e.g. {"title": ..., "author": ..., "date": ...}.with_solutionbool — Include the solution.describebool — Fill an empty meta.type / meta.rules_text fromdescribe; never overwrites them.**meta_kw— Metadata as keywords: title, author, source, id, url, date, rules_text.
- Returns
- dict — The sudoku-puzzle document.
def dumps(doc, pretty=True)source
Canonical JSON text of a sudoku-puzzle dict: fixed key order; pretty: one grid row per line, one rule per line.
- Parameters
docdict — A sudoku-puzzle document.prettybool — Readable layout (True) or one line (False).
- Returns
- str — The text.
def from_string(s, symbols=None)source
A puzzle as text -> sudoku-puzzle dict (Other formats).
Reads plain classic strings (with or without a trailing comment), text grids with separators, pencil-mark grids, 729-character candidate strings, HoDoKu library lines and sudokuwiki.org packed strings.
- Parameters
sstr — The text.symbolsstr, optional — For a plain string, the symbol of each digit in order (e.g. "ABCDEFGHI" reads A as 1); default 1-9, then A-Z.
- Returns
- dict — The sudoku-puzzle document.
def to_string(puzzle, form='plain')source
A puzzle as text (Other formats).
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.formstr — "plain" (81 characters), "grid" (rows with separators) or "sudokuwiki" (packed string).
- Returns
- str — The text.
- Raises
- NotSupportedError — The form cannot carry the puzzle (e.g. a variant in "plain").
def from_ipuz(ipuz)source
An ipuz sudoku -> sudoku-puzzle dict (Other formats).
- Parameters
ipuzdict or str — The ipuz document, or its JSON text.
- Returns
- dict — The sudoku-puzzle document.
def to_ipuz(puzzle)source
A puzzle as an ipuz 2 dict (Other formats).
ipuz expresses classic, Latin square, diagonal, windoku, jigsaw and killer sudoku.
- Parameters
puzzlestr, dict, Path or Puzzle — Anythingloadaccepts.
- Returns
- dict — The ipuz document.
- Raises
- NotSupportedError — The puzzle uses rules ipuz cannot express.
Errors
class NotUnique(ValueError)source
the puzzle has more than one solution
class NoSolution(ValueError)source
the puzzle has no solution
class Undecided(RuntimeError)source
the exhaustive search hit its node limit and OR-Tools (pip install "pencilmark[verify]") is not available