[Haskell-cafe] Sudoku Solver
Daniel Fischer
daniel.is.fischer at web.de
Mon Aug 6 20:38:00 EDT 2007
Hi,
Am Montag, 6. August 2007 15:07 schrieb Adrian Neumann:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: RIPEMD160
>
> Hi,
>
> I wrote a brute-force sudoku solver. It takes a [[Int]] and spits out
> the first solution it finds.
> Why is it, that
>
> [0,0,0,7,0,6,9,0,0]
> [9,0,0,0,0,4,7,0,0]
> [7,0,0,0,0,0,4,0,0]
> [0,2,7,0,3,5,8,0,0]
> [6,9,5,8,2,0,0,0,0]
> [0,8,0,0,0,0,5,0,0]
> [0,3,0,0,0,0,0,0,0]
> [8,7,0,9,0,0,0,0,0]
> [0,0,0,0,0,0,0,0,0]
>
> is solved instantly, but when I remove just one number my program takes
> forever?
>
Short answer: because of the enormous number of possibilities to check.
You were just incredibly lucky: with the grid above, you needn't backtrack.
The problem is genMoves, it produces too many Fields.
Point 1: If for, say, the first empty cell, there are no possibilities, you
still try out all possibilities for the other empty cells before you
backtrack, that's bound to take very long.
Point 2: Even if you take care of 1, you have to do it right.
Say in one row you have three empty cells with only one or two possibilities
altogether. Then it's futile and very time consuming to tinker with the later
rows before backtracking.
(To see what I mean, make play an IO-action and let it print out the field to
be updated, like
play :: [Field] -> IO (Maybe Field)
play (f:a)
| done f = return $ Just f
-- | isFull f= play a
| otherwise = do printField f
getLine
play ((genMoves f)++a)
play [] = return Nothing
)
A solution is to only consider the first empty cell:
genMoves a = concat $ take 1 [update a i j|i<-[1..9],j<-[1..9],isEmpty
(a!i!j)]
That'll be still slow, but should finish before the gnab gib[1].
> - -- creates a list of all allowed entries
> genMoves :: Field -> [Field]
> genMoves a = concat [update a i j|i<-[1..9],j<-[1..9],isEmpty (a!i!j)]
> where update b i j= [b //[(i,b!i //[(j,x)])]|x<-[1..9], checkField (b
> //[(i,b!i //[(j,x)])])]
>
Another thing, I think, it'd look better if You used
type Field = Array (Int,Int) Int.
Cheers,
Daniel
[1] Douglas Adams, The Restaurant at the end of the Universe
More information about the Haskell-Cafe
mailing list