2017-12-21 18:35:03 +00:00
|
|
|
import Data.List (transpose)
|
|
|
|
import Data.List.Split (splitOn, chunksOf)
|
2017-12-21 21:58:44 +00:00
|
|
|
import Data.HashMap (Map, insert, empty, (!))
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
type Rules = Map String String
|
|
|
|
squareRoot = floor . sqrt . fromIntegral
|
|
|
|
|
2017-12-21 21:58:44 +00:00
|
|
|
validTwos = [
|
2017-12-21 18:35:03 +00:00
|
|
|
[0..3],
|
|
|
|
[0, 2, 1, 3],
|
|
|
|
[1, 0, 3, 2],
|
|
|
|
[1, 3, 0, 2],
|
|
|
|
[2, 0, 3, 1],
|
|
|
|
[2, 3, 0, 1],
|
|
|
|
[3, 1, 2, 0],
|
|
|
|
[3,2..0]
|
|
|
|
]
|
|
|
|
|
|
|
|
validThrees = [
|
|
|
|
[0..8],
|
|
|
|
[0, 3, 6, 1, 4, 7, 2, 5, 8],
|
|
|
|
[2, 1, 0, 5, 4, 3, 8, 7, 6],
|
|
|
|
[2, 5, 8, 1, 4, 7, 0, 3, 6],
|
|
|
|
[6, 3, 0, 7, 4, 1, 8, 5, 2],
|
|
|
|
[6, 7, 8, 3, 4, 5, 0, 1, 2],
|
|
|
|
[8, 5, 2, 7, 4, 1, 6, 3, 0],
|
|
|
|
[8,7..0]
|
|
|
|
]
|
|
|
|
|
|
|
|
valids :: String -> [String]
|
2017-12-21 21:58:44 +00:00
|
|
|
valids str = map (map (str !!)) $ case length str of
|
|
|
|
4 -> validTwos
|
|
|
|
9 -> validThrees
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
chunk :: String -> [[String]]
|
|
|
|
chunk str =
|
2017-12-21 21:58:44 +00:00
|
|
|
let size = squareRoot $ length str
|
2017-12-21 18:35:03 +00:00
|
|
|
multiple = if even size then 2 else 3
|
2017-12-21 21:58:44 +00:00
|
|
|
makeRow = map concat . transpose . map (chunksOf multiple) . chunksOf size
|
|
|
|
in map makeRow $ chunksOf (size * multiple) str
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
dechunk :: [[String]] -> String
|
|
|
|
dechunk rows =
|
2017-12-21 21:58:44 +00:00
|
|
|
let multiple = squareRoot . length . head . head $ rows
|
|
|
|
unmakeRow = concat . concat . transpose . map (chunksOf multiple)
|
|
|
|
in concat $ map unmakeRow rows
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
enhance :: Rules -> String -> String
|
2017-12-21 21:58:44 +00:00
|
|
|
enhance rules = dechunk . map (map (rules !)) . chunk
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
parseLine :: String -> Rules -> Rules
|
2017-12-21 21:58:44 +00:00
|
|
|
parseLine line =
|
|
|
|
let input : output : [] = splitOn " => " $ filter (/= '/') line
|
|
|
|
in flip (foldr (\key currRules -> insert key output currRules)) $ valids input
|
2017-12-21 18:35:03 +00:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
|
|
|
rules <- foldr parseLine empty . lines <$> readFile "21.txt"
|
2017-12-21 21:58:44 +00:00
|
|
|
let iterations = map (length . filter (=='#')) $ iterate (enhance rules) ".#...####"
|
2017-12-21 18:35:03 +00:00
|
|
|
print $ iterations !! 5
|
|
|
|
print $ iterations !! 18
|