-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgriddlers.hs
202 lines (173 loc) · 7.06 KB
/
griddlers.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import Data.List
import Data.Maybe
data State = Started | CanStart | ForceWhite deriving Show
data Color = Black | White deriving (Eq, Show)
-- class Pretty capable of pretty printing
class Pretty a where
pretty :: a -> String
listPretty :: [a] -> String
listListPretty :: [[a]] -> String
instance Pretty Color where
pretty White = "."
pretty Black = "#"
listPretty (a:as) = pretty a ++ listPretty as
listPretty [] = ""
listListPretty (a:as) = listPretty a ++ "\n" ++ listListPretty as
listListPretty [] = ""
instance (Pretty a) => Pretty (Maybe a) where
pretty Nothing = "?"
pretty (Just a) = pretty a
listPretty (a:as) = pretty a ++ listPretty as
listPretty [] = ""
listListPretty (a:as) = listPretty a ++ "\n" ++ listListPretty as
listListPretty [] = ""
-- flatten - flatten an list by one degree
flatten :: [[a]] -> [a]
flatten = foldl (++) []
-- fillLeftmost - given set of rules and known cells, return left-most possible filling
fillLeftmost :: [Int] -> [Maybe Color] -> Maybe [(Int, Color)]
fillLeftmost rules known = do
x <- listToMaybe $ fillLeftmostFirst rules known
return $ mark x
-- fillRigtmost - given set of rules and known cells, return right-most possible filling
fillRightmost :: [Int] -> [Maybe Color] -> Maybe [(Int, Color)]
fillRightmost rules known = do
x <- listToMaybe $ fillLeftmostFirst (reverse rules) (reverse known)
return $ mark $ reverse x
-- fillLeftmostFirst - given set of rules and kown cells, return all possible fillings (if any), left-most first
fillLeftmostFirst :: [Int] -> [Maybe Color] -> [[Color]]
fillLeftmostFirst = fillLeftmostFirstLoop CanStart
-- fillLeftmostFirstLoop - recursive function serving as "main" part of fillLeftmostFirst function
fillLeftmostFirstLoop :: State -> [Int] -> [Maybe Color] -> [[Color]]
fillLeftmostFirstLoop _ [] [] = [[]]
fillLeftmostFirstLoop _ (0:rulex) known = fillLeftmostFirstLoop ForceWhite rulex known
fillLeftmostFirstLoop _ (rule:rulex) [] = []
fillLeftmostFirstLoop Started (rule:rulex) (col:knownx) =
if col == Just White
then []
else [Black : rest | rest <- fillLeftmostFirstLoop Started (rule-1:rulex) knownx]
fillLeftmostFirstLoop ForceWhite rules (col:knownx) =
if col == Just Black
then []
else [White : rest | rest <- fillLeftmostFirstLoop CanStart rules knownx]
fillLeftmostFirstLoop CanStart [] (col:knownx) =
if col == Just Black
then []
else [White : rest | rest <- fillLeftmostFirstLoop CanStart [] knownx]
fillLeftmostFirstLoop CanStart (rule:rulex) (col:knownx) =
case col of
Just Black -> [Black : rest | rest <- fillLeftmostFirstLoop Started (rule-1:rulex) (knownx)]
Just White -> [White : rest | rest <- fillLeftmostFirstLoop CanStart (rule:rulex) (knownx)]
Nothing ->
[Black : rest | rest <- fillLeftmostFirstLoop Started (rule-1:rulex) (knownx)] ++
[White : rest | rest <- fillLeftmostFirstLoop CanStart (rule:rulex) (knownx)]
-- mark - given filled row (col) add a number to each cell saying how many black blocks are before given cell
mark :: [Color] -> [(Int, Color)]
mark = markLoop White 0
-- makrLoop - recursive function servin as "main" part of mark fucntion
markLoop :: Color -> Int -> [Color] -> [(Int, Color)]
markLoop _ _ [] = []
markLoop lastCol lastNum (col:cols) =
if lastCol == Black || col == White
then (lastNum, col) : markLoop col lastNum cols
else (lastNum+1, col) : markLoop col (lastNum+1) cols
-- fillDat - given set of rules and known cells, fill all possible cells
fillDat :: [Int] -> [Maybe Color] -> Maybe [Maybe Color]
fillDat rules dat = do
l <- fillLeftmost rules dat
r <- fillRightmost rules dat
return $ zipWith checkKnown l r
-- checkKnown - given marked left-most and right-most filling, fill all known (overlapping) filled sells
checkKnown :: (Int, Color) -> (Int, Color) -> Maybe Color
checkKnown (xi, xc) (yi, yc) =
if xi == yi && xc == yc
then (Just xc)
else Nothing
-- walkOneDirectionRules - resolve (once each) all row-rules
walkOneDirectionRules :: [[Int]] -> [[Maybe Color]] -> Maybe [[Maybe Color]]
walkOneDirectionRules [] [] = Just []
walkOneDirectionRules (rules:rulesx) (known:knownx) = do
h <- fillDat rules known
b <- walkOneDirectionRules rulesx knownx
return (h:b)
-- walkAllRules - resolve (onec each) all rules
walkAllRules :: ([[Int]], [[Int]]) -> [[Maybe Color]] -> Maybe [[Maybe Color]]
walkAllRules (horizontal, vertical) known = do
knownUpdated <- walkOneDirectionRules horizontal known
knownFinal <- walkOneDirectionRules vertical (transpose knownUpdated)
return $ transpose knownFinal
-- solve - givenrules, solve a riddle
solve :: ([[Int]], [[Int]]) -> [[Maybe Color]]
solve rules =
case res of
Nothing -> error "Insolvable riddle"
Just x -> x
where res = solveSub rules
-- solveSub - supplementary function for function solve
solveSub :: ([[Int]], [[Int]]) -> Maybe [[Maybe Color]]
solveSub (horizontal, vertical) = solveLoop (horizontal, vertical) empty
where
empty = take (length horizontal) (cycle [singleEmpty])
singleEmpty = take (length vertical) (cycle [Nothing])
-- solveLoop - recursive function, given set of all rules and known cells, solve a riddle
solveLoop :: ([[Int]], [[Int]]) -> [[Maybe Color]] -> Maybe [[Maybe Color]]
solveLoop rules knowns = do
solved <- solveBasicLoop rules knowns
if allKnown $ flatten solved
then return solved
else
let
guessedBlack = solveLoop rules $ guess Black knowns
guessedWhite = solveLoop rules $ guess White knowns
in
case guessedBlack of
Just x -> return x
Nothing ->
case guessedWhite of
Just x -> return x
Nothing -> fail "Insolvable riddle"
-- allKnown - seek if there is any unknown cell
allKnown :: [Maybe Color] -> Bool
allKnown [] = True
allKnown (Nothing:_) = False
allKnown (Just _:rest) = allKnown rest
-- guess - given color and set of known cells, fill first unknown cell with color
guess :: Color -> [[Maybe Color]] -> [[Maybe Color]]
guess col (row:table) =
if elem Nothing row
then guessInRow col row : table
else row : guess col table
-- guessInRow - supplementary function for function guess
guessInRow :: Color -> [Maybe Color] -> [Maybe Color]
guessInRow col (Nothing:row) = (Just col) : row
guessInRow col (Just a:row) = (Just a) : guessInRow col row
-- solveBasicLoop - recursive function, given set of all rules and known cells, solve the riddle without guessing
solveBasicLoop :: ([[Int]], [[Int]]) -> [[Maybe Color]] -> Maybe [[Maybe Color]]
solveBasicLoop rules known = do
new <- walkAllRules rules known
if known == new
then return known
else solveBasicLoop rules new
-- loadInput - read initial input, return set of rules
loadInput :: IO ([[Int]], [[Int]])
loadInput = do
height <- readInt
width <- readInt
rowRules <- sequence $ take height $ cycle [readInts]
colRules <- sequence $ take width $ cycle [readInts]
return (rowRules, colRules)
-- readInt - read int from input
readInt :: IO Int
readInt = do
input <- getLine
return (read input :: Int)
-- readInts - read list of ints from input
readInts :: IO [Int]
readInts = do
input <- getLine
return (map read $ words input :: [Int])
-- main - well, main function
main :: IO()
main = do
input <- loadInput
putStrLn $ listListPretty $ solve input