https://github.com/gijs-pennings/kenken-solver
Fast backtracking solver for KenKen puzzles
https://github.com/gijs-pennings/kenken-solver
backtracking kenken puzzle solver
Last synced: 11 months ago
JSON representation
Fast backtracking solver for KenKen puzzles
- Host: GitHub
- URL: https://github.com/gijs-pennings/kenken-solver
- Owner: gijs-pennings
- License: isc
- Created: 2021-01-17T12:58:04.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2021-12-03T23:50:43.000Z (over 4 years ago)
- Last Synced: 2025-03-12T02:46:26.468Z (over 1 year ago)
- Topics: backtracking, kenken, puzzle, solver
- Language: C++
- Homepage:
- Size: 43 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# KenKen solver
This is a (somewhat optimized) backtracking solver in C++11 for [KenKen](https://en.wikipedia.org/wiki/KenKen) puzzles, also known as Calcudoku. It is licensed under the [ISC license](LICENSE.txt).
The puzzle input is read from a file (path given as argument) and its solution is printed to `stdout`. No validity or uniqueness checks are performed. The format is easily determined from the available [examples](examples), noting that cages with the subtraction or division operator *must* be of size 2.
Timing information is printed to `stderr`. Only the time spent backtracking is measured; I/O is ignored, for example. On my high-end machine from 2014, the running time ranges from [<1μs](examples/kenkenpuzzle-expert-S.ken) to [~2.2s](examples/menneske9-4474.ken). 'Average' puzzles (6x6) are solved in [≪1ms](examples/menneske6-74285.ken).
## Some implementation details
* Each cage stores its intermediate result (`current`), i.e. the result of the calculation involving all non-empty cells. This way, new values can be tested more efficiently, without querying other cage cells.
* Each column, row, and cage keeps a list of candidates, i.e. values that are not proven to be illegal. This list is stored as a bitset (a simple `int` suffices) where the `i`th bit is set if `i` is a possible value. This makes it possible to take intersections and find the 'next' candidate in O(1) time, using the `&` operator and `__builtin_ctz` intrinsic (count trailing zeros) respectively.
* Using [candidates.py](candidates.py), bitsets for all cage configurations of size ≤5 are precomputed (larger cages are rare and therefore not worth the additional space). Here, a grid size of 9 and the 'worst' cage shape (i.e. a staircase, which permits the most duplicates) is assumed. For smaller grids, illegal candidates are simply ignored. Although this is sometimes suboptimal (e.g. in a `*6` cage of size 2, the value 1 is possible in a grid of size 9, but not in a grid of size 3), grids of size ≤8 are solved almost instantly anyway.