Other formats
The sudoku-puzzle format (Puzzle format) is all a tool needs. pencilmark can also read and write a few
other formats for convenience. None of them is part of the format or required by it.
| Function | Reads | Writes |
|---|---|---|
from_string(s) / to_string(puzzle, "plain") | plain classic strings, also with a trailing comment | plain classic strings |
from_string(s) / to_string(puzzle, "grid") | text grids with |, -, + separators (Simple Sudoku, forums) | text grids |
from_string(s) | pencil-mark grids, 729-character candidate strings | – |
from_string(s) / to_string(puzzle, "sudokuwiki") | sudokuwiki.org packed strings | sudokuwiki.org packed strings |
from_ipuz(ipuz) / to_ipuz(puzzle) | ipuz 1 and 2 sudoku | ipuz 2 |
pencilmark.sources.load(url) | f-puzzles, SudokuPad (SCL / fpuz / ctc), Penpa+, Logic Masters links | – |
from_string returns a sudoku-puzzle dict. sources.load returns pencilmark's internal puzzle JSON; to_export
turns it into a sudoku-puzzle file. Every entry point (rate, solve, load, describe, the command line) also
accepts these strings and links directly.
Plain classic string
- D×D characters in reading order; whitespace and line breaks are ignored.
- Empty cell:
.,0,-or_. Digits1–9, thenA–Zfor 10–35 (case-insensitive). - D = √length for D in {4, 6, 8, 9, 10, 12, 14, 15, 16, 20, 25}; boxes are the standard shape (4: 2×2, 6: 2 rows × 3 columns, 8: 2×4, 9: 3×3, 10: 2×5, 12: 3×4, 14: 2×7, 15: 3×5, 16: 4×4, 20: 4×5, 25: 5×5).
to_string(…, "plain")writes.for empty cells and refuses anything but a classic with standard boxes and no other rules.
Text grids
The same classic puzzle laid out on lines, as Simple Sudoku (.ss), SadMan (.sdk) and forum posts write it:
. . . | . 4 . | 8 . 3 *-----------*
. 6 . | . . 8 | . . 2 |...|.4.|8.3|
9 . 8 | 6 . 5 | . . 1 |.6.|..8|..2|
------+-------+------ |9.8|6.5|..1|
2 3 5 | . . . | . . . |---+---+---|
… …
- Lines made only of
-,+,=,|,*and spaces, with at least one-,+or=, are separators and skipped;|and spaces inside a row are ignored;*is also an empty cell. - Text after
#or;on a line is a comment (<81 characters> # rating 5.9). to_string(…, "grid")writes the left-hand form (refuses what a plain string cannot carry).
Pencil marks
- Pencil-mark grid: one whitespace-separated token per cell in reading order (separators as above). A token with one
digit is a given; several digits are that cell's candidates (
candidatesin the puzzle). - 729-character candidate string (Sukaku): 9 characters per cell, position k holds the digit k+1 when it is a
candidate and
.or0otherwise; a cell with a single candidate is a given. - HoDoKu library line (
:0901:4:<81 characters>:<removed candidates>:…): the puzzle and its removed candidates (tokensdrc= digit d is not a candidate of rRcC); the fields describing the collected step are ignored.
These are read only. A multi-line grid is one puzzle: pass it to from_string / rate as one string (the command line
reads one puzzle per line).
sudokuwiki.org packed strings
These are the puzzle strings used by the solvers on sudokuwiki.org, Andrew Stuart's site. They are described on his Sudoku String Definitions page; the full encoding reference is the puzzle-coding documentation by Quintin May (source). A string is a 3-character header (puzzle type, size, encoding version) followed by one base-36 value per cell.
pencilmark reads and writes these headers:
| Header | Puzzle | Read as |
|---|---|---|
S9B, S6B | classic 9×9, 6×6 | one box_grid |
X9B | Sudoku X | + both main diagonals (region kind diagonal) |
W9B | Windoku | + the 4 windows (region kind window) |
C9B | Colour Sudoku | + 9 groups at the same position in every box (region kind disjoint) |
J9B | Jigsaw | box rules |
L9B, L6C | Killer 9×9, 6×6 | + cage rules (L6C: + cages only) |
M9B | Killer Jigsaw | box and cage rules |
Anything else (other puzzle types or versions, placed digits or candidates, 6×6 killer operators other than +) is
refused when read. to_string(puzzle, "sudokuwiki") picks the header from the structure and refuses puzzles none of
these headers can express (a 6×6 jigsaw or X, killer-X, killer-windoku, anything above 9×9).
ipuz
to_ipuz(puzzle) writes ipuz 2 (sudoku kinds) for the subset that maps cleanly and refuses the rest:
| pencilmark | ipuz |
|---|---|
one box_grid of the standard box shape | kind http://ipuz.org/sudoku#1, boxes: true |
one grid, no boxes (Latin square) | http://ipuz.org/sudoku/latinsquare#1, boxes: false |
| + both main diagonals | http://ipuz.org/sudoku/diagonalsudoku#1, zones |
+ region window | http://ipuz.org/sudoku/hypersudoku#1, zones with rect |
one grid + box rules (jigsaw) | http://ipuz.org/sudoku/jigsawsudoku#1, boxes: false, one zone per box |
+ cage | http://ipuz.org/sudoku/killersudoku#1, cages (value), showoperators: false, cageborder: "dashed" |
puzzle and solution are row arrays (0 = empty); ipuz coordinates are [col, row], 1-based. meta title /
author / url / id / date map to title, author, url, uniqueid, date (mm/dd/yyyy). The complete pencilmark
object goes in "io.github.silly-puppyy.pencilmark:puzzle", with
"volatile": {"io.github.silly-puppyy.pencilmark": "puzzle,solution,zones,cages"}. Given candidates (Sukaku) are
refused: ipuz has no field for them.
from_ipuz(ipuz) (a dict or JSON text) reads the same subset back: puzzle and solution (numbers, digit strings or
{"cell": …} objects; empty as declared), boxes, zones (on a jigsaw, zones of D cells are its boxes; both main
diagonals become region kind diagonal, rect zones window, any other zone region) and cages with a value.
A file written by to_ipuz returns its embedded puzzle as long as the grid was not edited. Other kinds, omitted or
block cells, and cages without a sum are refused.
Site loaders
pencilmark.sources reads f-puzzles, SudokuPad (SCL / fpuz /
ctc), Penpa+ and Logic Masters links, and to_export
turns the result into a sudoku-puzzle file. Writing those formats is not supported. Loaders that fetch pages identify
themselves, obey robots.txt and pause between requests.