Why did I do this? As computer security expert Ben Laurie
has stated, Sudoku is "a denial of service attack on human
intellect". My wife was infected by the virus, and I wanted
to convince her that the problem had been solved and didn't
need any more of her time.
I remember doing something very similar in college. My first cut used a hideous object model, but my second go at it used a 3 dimensional matrix to track all of the data and was much faster and space efficient.
The "Why?" at the end of the article pretty much sums up why I can't play most board games and puzzles. Once you 'solve' sudoku, chess, connect 6, ect. it really takes the fun out of it, even if your brain doesn't calculate the solution as quick as your code.
Doesn't apply to chess imho. I still keep discovering different views of the game on occasional plays. The standard algorithm takes too much time, so you have to find out how to see what's important.
I played chess for a while in a chess club. But to become any good you need to memorize a lot of positions to be able to efficiently recognize good moves. Playing creatively to have fun almost always leads to defeat.
I think you're being a bit unfair to chess, but anyway you can still play Go. I think it's far from "solved" as amateurs beat computer programs very often, as I understand.
Norvig tries to test his program against the hardest puzzle he can find, but only tries to find this hard puzzle by generating random ones. The program Sudoku Susser (http://www.madoverlord.com/projects/sudoku.t) actually comes with “the hardest sudoku in the world”, which I think the author of that program has proven somehow, so Norvig should try his program on that.
Sudoku Susser can solve sudoku puzzles not only the brute-force way shown in the article, but also using “human” reasoning, and show you all the steps.
I wouldn't call constraint propagation "brute-force". It isn't enumerating every combination of values and backtracking (as either a non-contstraint Prolog program or a C program with up to 81 nested for-loops would). Rather, it's removing every possibility that has already been canceled out (constraint propagation), then saving undo information, making one guess, and seeing if that sets off another chain reaction or reaches a solution.
He acknowledges the possibility of using more "reasoning" in the article, but dismisses it:
"We could try to code more sophisticated strategies. For example, the naked twins strategy looks for two squares in the same unit that both have the same two possible digits. [...] Coding up strategies like this is a possible route, but would require hundreds of lines of code (there are dozens of these strategies), and we'd never be sure if we could solve every puzzle."
Ours was a different game: Mühle. Also Mill or Nine Men's Morris.
I just discovered that Ralph Gasser solved it in 1996 using retrograde analysis and an 18-ply alpha- beta search. [1] Becoming "the first non-trivial game to be solved that does not seem to benefit from knowledge-based methods."
It's a sudoku solver based on Cryptol, which is "... a language tailored for cryptographic algorithms." built on top of Haskell. The amazing this is that all you need to define is a function that checks whether a given board is solved. Cryptol does the searching for you!
Sudoku has a human using their mind to solve things which don't need to be solved. A denial of service attack leaves a computer trying to handle things which don't need to be handled. So they have something trying to deal with things that don't need to be dealt with.
If you really want speed, then I would recommend using a good implementation of Dancing Links for solving constraint satisfaction problems. Don Knuth proposes a doubly linked list structure to speed up recursive state space exploration: www-cs-faculty.stanford.edu/~uno/papers/dancing-color.ps.gz.
It's not hyper-fast (for speed I actually implemented it as a c-extention to ruby, but it's a long time ago and I don't think I have the code around by now) but being ruby it's fairly easy to read.
Can really recommend reading the paper on Dancing Links and playing around with the algorithm, its such a great feeling once you start visualizing how the linked list trick works :)
Dancing Links is definitely a fun algorithm to implement. I wrote one in Python a while back and included an option to generate graphs as it went through the recursion tree. I put up a quick page at http://cavernum.net/dlsudoku/ demonstrating them.
I think the complexity class of Sudoko is NP-Complete (a quick google confirms it's not exactly NP but very close: http://11011110.livejournal.com/23221.html?thread=19381 -- complexity is the same as solving SAT problems which have only one unique solution)
> The solver uses depth first and/or breadth first with constraint propagation to prune the search
That would be backtracking.
Further, the purpose of many the constraint techniques seem to be aimed at creating puzzles that are amenable to humans, not solving them. The article itself states that for solving, backtracking with fewer constraints performs better.
You are right that "the purpose of many the constraint techniques seem to be aimed at creating puzzles that are amenable to humans, not solving them"
I shared the link because I found his sudoku generator and the constraint methods interesting.
> That would be backtracking.
Let me quote the first para in full:
The solver uses depth first and/or breadth first tree search
with constraint propagation to prune the search for the next
best move (forms of forward checking.) There are space/time
tradeoffs between depth/breadth first search and the constraints
used; sudoku(1) has options to control the combinations.
The common characteristic for all constraints, here and elsewhere,
is that they avoid trial and error. Its fine for a computer
to guess and backtrack but a definite breach of puzzle manners
to require a human to do so.
I could be wrong but, yes, it does use backtracking to find the constraint that can give a number for an empty cell but it never has to change a number it has put in a cell. That differs from the trial and error approach that moves forward by guessing values and checking if it leads to a valid solution.
I usually solve them by hand without guess and check, though occasionally, you get down to where there are pairs of values where you have no choice but to try one and see what works (or maybe I just need to figure out more constraints to use).
Well, an ambiguous Sudoku is like a 12 line sonnet...
It isn't computationally relevant but even if trial and error were a simpler approach I feel like that is not in the spirit of the game. Sudoku is a number maze, the goal is to backtrack.
Also I refuse to attempt something that is supposedly too difficult for humans to solve, I'm incapable of quitting puzzles and don't relish spending the next X hours proving it can be done :)
9x9 grid of digits with an ambiguous solution is not a Sudoku. It is part of the definition.
Within the set of initial grids that have unambiguous solutions there are ones which require guessing or backtracking, these are generally not considered proper Sudokus and are not presented to humans to solve.
If a Sudoku has one and only one solution, then it is always solvable without guessing or backtracking. It just might not be within the scope of the human brain. There exist (many) configurations where every cell is influenced by every other, so to solve any one cell essentially requires a simultaneous solve of the entire puzzle. There's no theoretical reason a human couldn't do that too; it's a problem simply of computational capacity not fundamental approach.
If you do the constraint propagation right, the number of trials and errors will be very small (and it will be only one trial and no errors for the easy ones).
I'd be very interested to see what an algorithm that solves any valid sudoku puzzle looks like. (apart from pathologic solutions like querying a database of all valid 9x9 sudoku combinations).
Edit: using the symmetries described in the same Wikipedia article, the size of the database could be reduced significantly to roughly 5*10^9, which is quite manageable.
The code in the post is based on depth-first search, which basically is a trial and error approach. A well implemented and effective one thanks to constraint propagation, but it is still trial and error. And there are cases, in which backtracking (trial and error) is necessary - at least one of them is documented in the post (the puzzle "hard1" that took 188 seconds).
I did the same, need to dig into my back up hard drive to find it.
Maybe i'm going to expose a REST api for generating sudokus. Do you think this might be interesting?
"Did you know that in order to generate a sudoku you need first to solve it?"