Haskellで数独 の解説PDF
Haskellで書いた数独の自動解答プログラムの、解説PDFを作ってみました。こちら
以下のコードを解説しています。
import System import List import Array import Char import Monad isSingle [x] = True isSingle _ = False slice n [] = [] slice n l = a:(slice n b) where (a,b) = splitAt n l arrayList ar = [ar!idx | idx <- allCells] allCells = range ((0,0),(8,8)) rowCells idx = let (row,col) = idx in range ((row,0),(row,8)) colCells idx = let (row,col) = idx in range ((0,col),(8,col)) boxCells idx = let (row,col) = idx a = (row `div` 3) * 3 b = (col `div` 3) * 3 in range ((a,b),(a+2,b+2)) unfixedCells ar = filter (\idx -> not (isSingle (ar!idx))) allCells getCandidates ar idx = let used = concat [ar!x | x <- rowCells idx ++ colCells idx ++ boxCells idx, isSingle (ar!x)] in [1..9] \\ used logicalSolve ar = let ar' = foldl f ar $ unfixedCells ar where f ar idx = ar//[(idx, getCandidates ar idx)] in if any (\idx -> ar!idx /= ar'!idx) $ allCells then logicalSolve ar' else ar' trialsList ar = [ar//[(idx,[x])] | x <- ar!idx] where idx = head $ unfixedCells ar solve ar = let s ar | all (\idx -> isSingle (ar!idx)) $ allCells = return ar | any (\idx -> (ar!idx) == []) $ allCells = fail "fail" | otherwise = do t <- trialsList ar solve t in s (logicalSolve ar) main :: IO () main = do let contents = [0,0,6,0,0,0,0,0,1, 0,7,0,0,6,0,0,5,0, 8,0,0,1,0,3,2,0,0, 0,0,5,0,4,0,8,0,0, 0,4,0,7,0,2,0,9,0, 0,0,8,0,1,0,7,0,0, 0,0,1,2,0,5,0,0,3, 0,6,0,0,7,0,0,8,0, 2,0,0,0,0,0,4,0,0] let start = listArray ((0,0),(8,8)) $ map (\x -> if x == 0 then [1..9] else [x]) contents printArray (head (solve start)) where printArray ar = mapM_ putStrLn $ (slice 9 l) where l = map intToDigit (concat (arrayList ar))
もともとには、ファイルから問題を読み込む処理もちゃんと書いてあったんですが、見やすくするためにそれは省きました。
8だの9だのマジックナンバーを定数にしていないのも、わざとです。
実は Gauche でも書いたので、それもいずれ文書に含めて、数独で関数型言語入門といった感じにまとめて、HTMLに書き直そうと思っています。