-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.hs
128 lines (94 loc) · 3.35 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
module Main where
import Data.List
type Row = [ Maybe Int ]
-- Todo limit int to 0-9
type Board = [Row]
-- Todo
-- At each row, create a row of all possibilities that sum to $ sum [1..9]
-- do not replace any existing data, only Nothing
-- At each column, do not pick any numbers already used
solveSudoku :: Board -> [Board]
solveSudoku board =
let
options = possibilitiesMatrix board
beastMatrix = sequence options
in
filter sudokuTest beastMatrix
sudokuTest :: [Row] -> Bool
sudokuTest matrix =
let
rowTest = all (\x -> fst x == 1) $ concatMap frequency matrix
colTest = all (\x -> fst x == 1) $ concatMap frequency $ transpose matrix
in
(rowTest && colTest)
frequency :: Ord a => [a] -> [(Int,a)]
frequency list = map (\l -> (length l, head l)) (group (sort list))
possibilitiesMatrix :: Board -> [[Row]]
possibilitiesMatrix board =
let
side = length board - 1
in
fmap (solutionFilter board) [0..side]
solutionFilter :: Board -> Int ->[Row]
solutionFilter board i =
filter (constraintChecker i board) (rowCombinator board i)
constraintChecker :: Int -> Board -> Row -> Bool
constraintChecker i initBoard row =
let
constraints = getColumnConstraints $ colConstraints i initBoard
intRow = takenSlots row
test = zip intRow constraints
in
all (\(x, y) -> notElem x y) test
getColumnConstraints :: Board -> [[Int]]
getColumnConstraints board =
takenSlots <$> transpose board
-- This was a weird twist. You can't filter on constraints in your row
-- Those are properties of the board itself and already resolved using
-- Row combinator
colConstraints :: Int -> Board -> Board
colConstraints row board =
let
filterRows n board =
take n board ++ drop (n+1) board
in
filterRows row board
rowCombinator :: Board -> Int -> [Row]
rowCombinator board i =
let
row = board !! i
in
fmap (mergeRowAndUnusedList row) (allUnusedOptions row)
mergeRowAndUnusedList :: Row -> [Int] -> Row
mergeRowAndUnusedList = go []
where
go acc r l =
case (r, l) of
(Just r:rs, x:xs) -> go ( acc ++ [Just r] ) rs (x:xs)
(Nothing:rs, x:xs) -> go ( acc ++ [Just x] ) rs xs
(r:rs, []) -> go (acc ++ [r]) rs []
([], _) -> acc
allUnusedOptions :: Row -> [[Int]]
allUnusedOptions row = permutations $ remainingOptions row
remainingOptions :: Row -> [Int]
remainingOptions row =
let
leftovers = takenSlots row
in
filter (`notElem` leftovers) [1..9]
takenSlots :: Row -> [Int]
takenSlots row = map (\ (Just a) -> a) $ filter (/= Nothing) row
initBoard :: Board
initBoard
= [ [Just 5, Just 3, Nothing, Nothing, Just 7, Nothing, Nothing, Nothing, Nothing ]
, [Just 6, Nothing, Nothing, Just 1, Just 9, Just 5, Nothing, Nothing, Nothing ]
, [Nothing, Just 9, Just 8, Nothing, Nothing, Nothing, Nothing, Just 6, Nothing ]
, [Just 8, Nothing, Nothing, Nothing, Just 6, Nothing, Nothing, Nothing, Just 3]
, [Just 4, Nothing, Nothing, Just 8, Nothing, Just 3, Nothing, Nothing, Just 1]
, [Just 7, Nothing, Nothing, Nothing, Just 2, Nothing, Nothing, Nothing, Just 6]
, [Nothing, Just 6, Nothing, Nothing, Nothing, Nothing, Just 2, Just 8, Nothing]
, [Nothing, Nothing, Nothing, Just 4, Just 1, Just 9, Nothing, Nothing, Just 5]
, [Nothing, Nothing, Nothing, Nothing, Just 8, Nothing, Nothing, Just 7, Just 9]
]
main =
print $ solveSudoku initBoard