need help writing a function candidates in Haskell
Hi take a look at this thread already processing this subject And also this thread might be of intrest.
Im trying to write a fu开发者_开发百科nction
candidates :: Sudoku -> Pos -> [Int]
that given a Sudoku
data Sudoku = Sudoku { rows :: [[Maybe Int]] }
deriving ( Show, Eq )
and a position (type Pos = (Int, Int)
)
determines what numbers that you can write there, for example in a sudoku row that already contains (1,2,4,7,9,x,x) you cant write any of the already existing numbers in the last row. Also the other problem is to check the hight as well as the width so no numbers occur more than once (ordinary sudoku rules). So any suggestions on how to start?
Example: Sudoku> candidates example (0,2) [4,8]
I remember doing this project in my Algorithms class in college. My best advice, particularly for someone who is writing in Haskell for learning and not for production, is to write 'top down'. First, ask yourself what do you need to do to solve this problem? Then just write it down with descriptive functions (even if they don't yet exist). Then stub in the functions you need. For example, a start might be:
candidates :: Sudoku -> Pos -> [Int]
candidates s p = union (rowCands s p) (colCands s p) (blockCands s p)
rowCands :: Sudoku -> Pos -> [Int]
rowCands = undefined
colCands :: Sudoku -> Pos -> [Int]
colCands = undefined
blockCands :: Sudoku -> Pos -> [Int]
blockCands = undefined
From this, you would simply start describing top-down how to solve the rowCands
problem, until you've answered everything. Note that sometimes you'll want to write a function similar to union
, but surely its already been written before. Try checking out http://haskell.org/hoogle. You can search for function names or even type signatures. Maybe there is a union
somewhere already written in the standard libraries?
As an interesting question for you to answer yourself, what is the type of undefined
and why does it type check? It is not a special keyword; it is merely a predefined function.
Here is a solution using Data.Set
. You can use S.elems
to get the list, but if you are making a sudoku solver, you might be looking for S.size
.
import qualified Data.Set as S
import Data.Maybe(catMaybes)
fullSet = S.fromAscList [1..9]
fromJustL = S.fromList . concatMaybes
candidates s x =
rowSet s x `S.intersection` colSet s x `S.intersection` cellSet s x
rowSet s (i,_) = fullSet `S.difference` fromJustL (s !! i)
colSet s (_,i) = fullSet `S.difference` fromJustL (map (!!i) s)
cellSet s (i,j) = fullSet `S.difference` fromJustL (concatMap (g j) (g i s))
where
g i | i < 3 = take 3
| i < 6 = take 3 . drop 3
| otherwise = take 3 . drop 6
精彩评论