Skip to main content

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).

NameWhat it does
def rateThe "sudoku-grade" card of one puzzle (Grade card), with only the fields you ask for.
def rate_manyCards for many puzzles, in input order.
def describeThe variant name and its rules in words, from the rules alone (pencilmark/variants.py).
def solveThe unique solution of a puzzle.
def count_solutionsHow many solutions a puzzle has, counting up to a limit.
def generateOne puzzle for a "sudoku-spec" request (Generator spec).
def loadAny accepted input -> a finalised engine Puzzle.
def validateStrict reading checks of a format_version 1 dict (Puzzle format section 4).
def fingerprintContent fingerprint of a puzzle: "sha256:<hex>" of its canonical form.
def to_exportThe sudoku-puzzle dict of a puzzle (format_version 1, Puzzle format).
def dumpsCanonical JSON text of a sudoku-puzzle dict: fixed key order; pretty: one grid row per line, one rule per…
def from_stringA puzzle as text -> sudoku-puzzle dict (Other formats).
def to_stringA puzzle as text (Other formats).
def from_ipuzAn ipuz sudoku -> sudoku-puzzle dict (Other formats).
def to_ipuzA puzzle as an ipuz 2 dict (Other formats).
class NotUniquethe puzzle has more than one solution
class NoSolutionthe puzzle has no solution
class Undecidedthe 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
  • puzzle str, dict, Path or Puzzle — Anything load accepts: 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.
  • steps bool — Shorthand for the steps field with every explanation level.
  • max_seconds float, optional — One wall-clock limit for the whole call. When it passes, the card says band "Unknown", difficulty and time are null and completed is false.
  • mode str — "human" (default): human techniques only, a proof by full search where they stop; "computer": also forcing chains and nets, Nishio and trial.
  • se bool — Shorthand for the se field (Sudoku Explainer-style ratings; classic sudoku only).
  • fields list 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_guessing bool — Guess where no technique applies (band "Unknown") instead of proving by full search (Trial and error, Extreme).
  • explain str, list of str or bool, optional — Explanation levels for the steps: "notation", "short", "teach", or True for all of them.
  • quality dict, optional — Settings of the issue checks, e.g. {"trivial": {"limit": 0.5}, "trial": {"severity": "off"}} (Grade card 4).
  • alternatives bool — 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
  • puzzles iterable — Puzzles in any form rate accepts.
  • jobs int — Worker processes; 1 rates in this process.
  • steps, max_seconds, mode, se, fields, allow_guessing, explain, quality, alternatives — As for rate.
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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
  • info bool — 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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
  • limit int — 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.

Generating​

def generate(spec)source​

One puzzle for a "sudoku-spec" request (Generator spec).

Parameters
  • spec dict, 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
  • puzzle str, 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
  • doc dict — 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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
  • meta dict, optional — Metadata for the "meta" object, e.g. {"title": ..., "author": ..., "date": ...}.
  • with_solution bool — Include the solution.
  • describe bool — Fill an empty meta.type / meta.rules_text from describe; 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
  • doc dict — A sudoku-puzzle document.
  • pretty bool — 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
  • s str — The text.
  • symbols str, 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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
  • form str — "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
  • ipuz dict 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
  • puzzle str, dict, Path or Puzzle — Anything load accepts.
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