1 Monadic non-deterministic solver

Here is a solver by CaleGibbard. It possibly looks even more naïve than it actually is. This does a backtracking search, trying possibilities until it finds one which works, and backtracking when it can no longer make a legal move.

import MonadNondet (option)import Sudoku
import System
import Control.Monad
solve = forM [(i,j)| i <-[1..9], j <-[1..9]]$ \(i,j)->do
v <- valAt (i,j)-- ^ for each board position
when (v ==0)$do-- if it's empty (we represent that with a 0)
a <- option [1..9]-- pick a number
place (i,j) a -- and try to put it there
main =do[f]<- getArgs
xs <-readFile f
putStrLn. evalSudoku $do{ readSudoku xs; solve; showSudoku }

Now, to the meat of the thing, the monad which makes the above look so nice. We construct a monad which is suitable for maintaining Sudoku grids and trying options nondeterministically. Note that outside of this module, it's impossible to create a state which has an invalid Sudoku grid, since the only way to update the state handles the check to ensure that the move is legal.

This is a fast NonDeterminism monad. It's a drop-in replacement for the list monad in this case. It's twice as fast when compiled with optimisations but a little slower without. You can also find it on the wiki at NonDeterminism.

I've made a few small modifications to this one to hopefully make it more concretely readable.

2 Simple solver

By AlsonKemp. This solver is probably similar to Cale's but I don't grok the non-deterministic monad...

Note: this solver is exhaustive and will output all of the solutions, not just the first one. In order to make it non-exhaustive, add a case statement to solve' in order to check "r" and branch on the result.

4 No guessing

By Simon Peyton Jones.

Since this page is here I thought I'd add a solver I wrote sometime last year. The main constraint I imposed is that it never guesses, and that it outputs a human-comprehensible explanation of every step of its reasoning. That means there are some puzzles it can't solve. I'd be interested to know if there are any puzzles that it gets stuck on where there is a no-guessing way forward. I made no attempt to make it fast.

5 Just guessing

By ChrisKuklewicz

This solver is an implementation of Knuth's "Dancing Links" algorithm for solving binary-cover problems. This algorithm represents the constraints as a sparse binary matrix, with 1's as linked nodes. The nodes are in a vertical and a horizontal doubly linked list, and each vertical list is headed by another node that represents one of the constraints. It is interesting as an example of the rare beast in Haskell: a mutable data structure. The code has been rewritten and cleaned up here Media:DancingSudoku.lhs. Its main routine is designed to handle the input from sudoku17 on stdin. Currently it only returns the first solution or calls an error, it can be modified (see comments in the file) to return all solutions in a list. An earlier version used ST.Lazy instead of ST.Strict which made operating on puzzles with many solutions more tractable.

Other trivia: It uses "mdo" and lazyness to initialize some of the doubly linked lists.

6 Very smart, with only a little guessing

by ChrisKuklewicz

This solver does its best to avoid the branch and guess approach. On the 36628 puzzles of length 17 it resorts to guessing on only 164. This extra strength comes from examining the constraints that can only be solved in exactly two ways, and how these constraints overlap and interact with each other and remaining possibilities.

The source code compiles to take a list of puzzles as input and produces a description of the number of (good and total) guesses required, as well as a shuffled version of the input. If there was guessing, then the shuffled version could be sent back into the solver to see how the difficulty depended on luck. The list of 164 hard puzzles is included with the source code. The Deduce.hs file contains comments.

The data is stored in a 9x9x9 boolean array, and the only operations are turning off possibilities and branching. For performance the array is thawed, mutated, and frozen. On the set of 36628 puzzles the speed averages 9.4 puzzles solved per second on a 1.33 GHz G4 (ghc-6.4.1 on OS X). I liked the 9x9x9 array since it emphasized the symmetry of the problem.

7 Only guessing without dancing links

by AndrewBromage

This solver uses a different implementation of Knuth's algorithm, without using pointers. It instead relies on the fact that in Haskell, tree-like data structure (in this case, a Priority Search Queue) "undo" operations are essentially free.

8 Generalized solver

By Thorkil Naur

This Su Doku solver is able to solve classes of Su Doku puzzles that extend the ordinary 9*9 puzzles. The documentation describes the solver and also some (to the present author at least) surprising properties of various reduction strategies used when solving Su Doku puzzles.

10 Backtrack monad solver

Besides being Yet Another Example of a Sudoko solver,
I think it is also a nice somewhat-nontrivial example of
monads in practice.

The idea is that the monad StateT s [] does backtracking.
It means "iterate over a list while keeping state,
but re-initialize to the original state on each iteration".

I have several (Unix command line) front-ends to this
module, available upon request. The one I use most creates
and prints six new Sudoku puzzles on a page, with
fine-grain control over the difficulty of the puzzle.
This has made me quite popular among friends and
extended family.

11 In-flight entertainment

By Lennart Augustsson

When on a Lufthansa trans-atlantic flight in 2005 I picked up the in-flight magazine and found a Sudoku puzzle. I decided to finally try one. After solving half of it by hand I got bored. Surely, this mechanical task is better performed by a machine? So I pulled out my laptop and wrote a Haskell program.

The program below is what I wrote on the plane, except for some comments that I've added. I have made no attempt as making it fast, so the nefarious test puzzle below takes a minute to solve.

12 Sudoku incrementally, à la Bird

As part of a new Advanced Functional Programming course in Nottingham, Graham Hutton presented a Haskell approach to solving Sudoku puzzles, based upon notes from Richard Bird. The approach is classic Bird: start with a simple but impractical solver, whose efficiency is then improved in a series of steps. The end result is an elegant program that is able to solve any Sudoku puzzle in an instant. Its also an excellent example of what has been termed wholemeal programming focusing on entire data structures rather than their elements. (Transplanted from LtU.)

I've also written Media:sudokuWss.hs, a parallel version of this solver. It uses STM to prune the boxes, columns, and rows simultaneously, which is kind of cool. I'm pretty sure it can be optimized quite a bit... --WouterSwierstra, August 2007.

13 607 bytes / 12 lines

A super quick attempt at a smallest solution, based on the
707 byte sudoku solver:

14 A parallel solver

15 Another simple solver

One day I wrote a completely naive sudoku solver which tried all possibilities to try arrays in Haskell. It works, however I doubt that I'll see it actually solve a puzzle during my remaining lifetime.

So I set out to improve it. The new version still tries all possibilities, but it starts with the cell that has a minimal number of possibilities.

I let it run on the 41747 minimal puzzles. On a 2.66 GHz Intel Xeon it took 15441m1.920s, which is about 22 seconds per puzzle. It could probably be further improved by making remPoss smarter. At the time of writing this the naive version from which I started is crunching for 20 days on a simple puzzle with 32 hints. I'd say that's quite a performance improvement.

Chris Kuklewicz writes, "You can get over 47,000 distict minimal puzzles from
csse.uwa.edu that have only 17 clues. Then you can run all of them through your program to locate the most evil ones, and use them on your associates."