Sudoku solver that uses Poetry's dependency resolver.
Check reddit discussion here and explainer post here.
This package is supposed to be used with devpi, a local PyPI server.
First, it generates 9 x 9 = 81 Python "packages", each of which represents a Sudoku cell. Each package has 9 versions, corresponding to cell values. Finally, each package also has dependencies on other "cell" packages, with version constraints encoding which values those "cells" can have.
For example, version 3.0.0 of the sudoku-cell25
package represents an
assertion that the cell at row 2, column 5 of the board has the number 3
in it. The pyproject.toml
for this package has a list of all "cell"
packages in the same row, column or a 3x3 square as this cell:
[tool.poetry.dependencies]
python = "^3.6"
sudoku-cell14 = "!= 3.0.0"
sudoku-cell15 = "!= 3.0.0"
sudoku-cell16 = "!= 3.0.0"
sudoku-cell21 = "!= 3.0.0"
sudoku-cell22 = "!= 3.0.0"
sudoku-cell23 = "!= 3.0.0"
sudoku-cell24 = "!= 3.0.0"
sudoku-cell26 = "!= 3.0.0"
sudoku-cell27 = "!= 3.0.0"
sudoku-cell28 = "!= 3.0.0"
sudoku-cell29 = "!= 3.0.0"
sudoku-cell34 = "!= 3.0.0"
sudoku-cell35 = "!= 3.0.0"
sudoku-cell36 = "!= 3.0.0"
sudoku-cell45 = "!= 3.0.0"
sudoku-cell55 = "!= 3.0.0"
sudoku-cell65 = "!= 3.0.0"
sudoku-cell75 = "!= 3.0.0"
sudoku-cell85 = "!= 3.0.0"
sudoku-cell95 = "!= 3.0.0"
Then, it uploads these packages to devpi. Theoretically, one could upload them to PyPI (these rules are only ever uploaded once, not every time we need to solve a board), but that feels kinda abusive.
Now, we can represent an unsolved Sudoku board as another Poetry package:
[tool.poetry.dependencies]
python = "^3.6"
sudoku-cell11 = "*"
sudoku-cell12 = "2.0.0"
sudoku-cell13 = "*"
sudoku-cell14 = "8.0.0"
sudoku-cell15 = "*"
sudoku-cell16 = "9.0.0"
sudoku-cell17 = "*"
sudoku-cell18 = "*"
sudoku-cell19 = "*"
sudoku-cell21 = "3.0.0"
sudoku-cell22 = "7.0.0"
sudoku-cell23 = "*"
sudoku-cell24 = "6.0.0"
...
This pyproject.toml
depends on all 81 "cell" packages, pinning known
cells to their values. In order to generate a lockfile for this package,
Poetry has to find a version (value) for each of the 81 packages (cells)
in such a way that they don't conflict with each other. Since we encoded
the rules of Sudoku as inter-package dependencies, the lockfile will
contain a solution to this Sudoku board.
Install Poetry.
poetry install
All the commands after this are supposed to be run in the package's virtual environment. You can enter it by running:
poetry shell
devpi-init
devpi-server
Create a devpi user and add devpi to Poetry as a repository:
devpi use http://127.0.0.1:3141/
devpi user -c poetry password=poetry
devpi login poetry --password=poetry
poetry config repositories.devpi http://localhost:3141/poetry/sudoku
(there's no need to add the devpi credentials to Poetry, since the next "publish" command embeds the password in the Poetry invocation).
You only need to do this step once (instead of to solve every Sudoku problem)
poetry-sudoku-solver generate-packages
poetry-sudoku-solver publish-packages
The second step will take a few minutes, as it will publish 9 x 9 x 9 = 729 versions of packages to the local devpi instance.
Visit https://qqwing.com/generate.html to generate a Sudoku puzzle. Paste it
into ./problem.txt
.
Generate the package with the representation of the problem:
poetry-sudoku-solver generate-problem-package ./problem.txt
Run Poetry's dependency resolver. This will pin each package to a specific version that represents the value of each Sudoku cell.
cd output/problem && poetry update --lock
Parse the lockfile and output the Sudoku solution:
poetry-sudoku-solver parse-solution ./poetry.lock
You can also run all three of these at once:
poetry-sudoku-solver solve ./problem.txt