feat(encode): add sudoku encoding and grid parser
This commit is contained in:
1 parent
6f96d10593
commit
59b3ebd355
1 file changed
+82
@@ -0,0 +1,82 @@
|
|||||||
|
module Sift.Encode.Sudoku
|
||||||
|
( sudoku
|
||||||
|
, sudokuCell
|
||||||
|
, decodeSudoku
|
||||||
|
, validSudoku
|
||||||
|
, parseGrid
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Sift.Types
|
||||||
|
import Sift.Encode.Cardinality
|
||||||
|
import Data.Char (digitToInt, isDigit)
|
||||||
|
import Data.List (transpose)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
sudokuCell :: Int -> Int -> Int -> Int -> Var
|
||||||
|
sudokuCell n r c d = Var (((r - 1) * n + (c - 1)) * n + d)
|
||||||
|
|
||||||
|
sudoku :: Int -> [(Int, Int, Int)] -> CNF
|
||||||
|
sudoku boxN givens = CNF (cellClauses ++ rowClauses ++ colClauses ++ boxClauses ++ givenClauses)
|
||||||
|
where
|
||||||
|
n = boxN * boxN
|
||||||
|
lit r c d = posLit (sudokuCell n r c d)
|
||||||
|
cellClauses = concat
|
||||||
|
[ exactlyOne [ lit r c d | d <- [1 .. n] ]
|
||||||
|
| r <- [1 .. n], c <- [1 .. n] ]
|
||||||
|
rowClauses = concat
|
||||||
|
[ exactlyOne [ lit r c d | c <- [1 .. n] ]
|
||||||
|
| r <- [1 .. n], d <- [1 .. n] ]
|
||||||
|
colClauses = concat
|
||||||
|
[ exactlyOne [ lit r c d | r <- [1 .. n] ]
|
||||||
|
| c <- [1 .. n], d <- [1 .. n] ]
|
||||||
|
boxClauses = concat
|
||||||
|
[ exactlyOne [ lit r c d | (r, c) <- boxCells br bc ]
|
||||||
|
| br <- [1 .. boxN], bc <- [1 .. boxN], d <- [1 .. n] ]
|
||||||
|
boxCells br bc =
|
||||||
|
[ ((br - 1) * boxN + i, (bc - 1) * boxN + j)
|
||||||
|
| i <- [1 .. boxN], j <- [1 .. boxN] ]
|
||||||
|
givenClauses = [ [ lit r c d ] | (r, c, d) <- givens ]
|
||||||
|
|
||||||
|
decodeSudoku :: Int -> Assignment -> [[Int]]
|
||||||
|
decodeSudoku boxN asn =
|
||||||
|
[ [ cellDigit r c | c <- [1 .. n] ] | r <- [1 .. n] ]
|
||||||
|
where
|
||||||
|
n = boxN * boxN
|
||||||
|
cellDigit r c =
|
||||||
|
case [ d | d <- [1 .. n], Map.findWithDefault False (sudokuCell n r c d) asn ] of
|
||||||
|
(d : _) -> d
|
||||||
|
[] -> 0
|
||||||
|
|
||||||
|
validSudoku :: Int -> [(Int, Int, Int)] -> Assignment -> Bool
|
||||||
|
validSudoku boxN givens asn =
|
||||||
|
all fullPermutation grid
|
||||||
|
&& all fullPermutation (transpose grid)
|
||||||
|
&& all fullPermutation boxes
|
||||||
|
&& all givenHolds givens
|
||||||
|
where
|
||||||
|
n = boxN * boxN
|
||||||
|
grid = decodeSudoku boxN asn
|
||||||
|
fullPermutation row = permutationOf n row
|
||||||
|
boxes =
|
||||||
|
[ [ (grid !! (r - 1)) !! (c - 1)
|
||||||
|
| (r, c) <-
|
||||||
|
[ ((br - 1) * boxN + i, (bc - 1) * boxN + j)
|
||||||
|
| i <- [1 .. boxN], j <- [1 .. boxN] ] ]
|
||||||
|
| br <- [1 .. boxN], bc <- [1 .. boxN] ]
|
||||||
|
givenHolds (r, c, d) = (grid !! (r - 1)) !! (c - 1) == d
|
||||||
|
|
||||||
|
permutationOf :: Int -> [Int] -> Bool
|
||||||
|
permutationOf n row =
|
||||||
|
Map.fromList (zip row (repeat ())) == Map.fromList (zip [1 .. n] (repeat ()))
|
||||||
|
&& length row == n
|
||||||
|
|
||||||
|
parseGrid :: Int -> String -> [(Int, Int, Int)]
|
||||||
|
parseGrid boxN text =
|
||||||
|
[ (r, c, digitToInt ch)
|
||||||
|
| (r, line) <- zip [1 ..] rows
|
||||||
|
, (c, ch) <- zip [1 ..] line
|
||||||
|
, isDigit ch, ch /= '0' ]
|
||||||
|
where
|
||||||
|
rows = take n (map (take n . padCells) (lines text))
|
||||||
|
n = boxN * boxN
|
||||||
|
padCells line = line ++ replicate n '0'
|
||||||
Reference in new issue
Block a user