嗨,看看已经处理过这个主题的this线程 而this线程也可能是有趣的。
我正在尝试编写一个函数
candidates :: Sudoku -> Pos -> [Int]
给予数独
data Sudoku = Sudoku { rows :: [[Maybe Int]] }
deriving ( Show, Eq )
和一个职位(type Pos = (Int, Int)
)
确定您可以在那里写入的数字,例如在已包含(1,2,4,7,9,x,x)的数独行中,您无法写入最后一行中任何已存在的数字。另一个问题是检查高度和宽度,因此没有数字出现多次(普通的数独规则)。那么关于如何开始的任何建议?
实施例: 独>候选人示例(0,2) [4,8]
答案 0 :(得分:5)
我记得在大学的算法课上做这个项目。我最好的建议,特别是那些在Haskell写作学习而非制作的人,就是写“自上而下”。首先,问问自己,你需要做些什么来解决这个问题?然后用描述性函数将其写下来(即使它们尚不存在)。然后存根你需要的功能。例如,一个开头可能是:
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
从此开始,您只需开始描述如何解决rowCands
问题,直到您回答完所有问题为止。请注意,有时您会想要编写类似于union
的函数,但肯定已经编写过了。尝试查看http://haskell.org/hoogle。您可以搜索功能名称甚至键入签名。也许在标准库中已经有了union
某处?
作为一个有趣的问题,您可以自己回答,undefined
的类型是什么?为什么要键入检查?它不是一个特殊的关键字;它只是一个预定义的功能。
答案 1 :(得分:0)
以下是使用Data.Set
的解决方案。您可以使用S.elems
获取列表,但如果您正在制作数独求解器,那么您可能正在寻找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