|
1 |
| -import Control.Applicative ((<|>), asum) |
| 1 | +import Control.Applicative ((<|>)) |
2 | 2 | import Control.Arrow ((&&&))
|
3 |
| -import Data.Bits (complementBit) |
4 |
| -import Data.List (transpose) |
| 3 | +import Data.List (transpose, find) |
5 | 4 | import Data.Maybe (fromJust)
|
6 |
| -import Numeric (readBin) |
7 | 5 |
|
8 | 6 | main :: IO ()
|
9 | 7 | main = interact $ (++ "\n") . show . (p1 &&& p2) . parse
|
10 | 8 |
|
11 |
| -type Pattern = ([Int], [Int]) |
| 9 | +type Pattern = [String] |
12 | 10 |
|
13 | 11 | parse :: String -> [Pattern]
|
14 | 12 | parse = from . lines
|
15 | 13 | where
|
16 | 14 | from [] = []
|
17 |
| - from ls = let (pl, rest) = span (/= "") ls in pat pl : from (drop 1 rest) |
18 |
| - pat = ints &&& ints . transpose |
19 |
| - ints = map int |
20 |
| - int s = case readBin $ map (\c -> if c == '.' then '0' else '1') s of |
21 |
| - [(i, _)] -> i |
22 |
| - |
23 |
| -rIndex :: [Int] -> Maybe Int |
24 |
| -rIndex = asum . rIndices |
25 |
| - |
26 |
| -rIndices :: [Int] -> [Maybe Int] |
27 |
| -rIndices xs = map f [1..length xs - 1] |
28 |
| - where f i = let (a, b) = splitAt i xs |
29 |
| - j = min (length a) (length b) |
30 |
| - in if take j (reverse a) == take j b then Just i else Nothing |
31 |
| - |
32 |
| -p1 :: [Pattern] -> Int |
33 |
| -p1 = sum . map (fromJust . ri) |
34 |
| - where ri (rows, cols) = (*100) <$> rIndex rows <|> rIndex cols |
35 |
| - |
36 |
| -p2 :: [Pattern] -> Int |
37 |
| -p2 = sum . map smudge |
38 |
| - |
39 |
| -smudge :: Pattern -> Int |
40 |
| -smudge (rows, cols) = fromJust $ (*100) <$> rf <|> rc |
41 |
| - where |
42 |
| - or = rIndex rows |
43 |
| - oc = rIndex cols |
44 |
| - rf = asum $ filter (/= or) $ concatMap rIndices rowVariants |
45 |
| - rc = asum $ filter (/= oc) $ concatMap rIndices colVariants |
46 |
| - rowVariants = [flip y x rows | y <- [0..length rows - 1], x <- [0..length cols - 1]] |
47 |
| - colVariants = [flip x y cols | y <- [0..length rows - 1], x <- [0..length cols - 1]] |
48 |
| - flip y x ns = zipWith (\i r -> if i == y then flipBit x r else r) [0..] ns |
49 |
| - flipBit x n = n `complementBit` x |
| 15 | + from ls = let (pl, rest) = span (/= "") ls in pl : from (drop 1 rest) |
| 16 | + |
| 17 | +-- For all splits, find the differences across the reflection line. For part 1, |
| 18 | +-- where the mirroring is perfect, the won't be any difference. For part 2, |
| 19 | +-- where there's a single smidge, there'll be exactly one difference. |
| 20 | + |
| 21 | +reflectionLine :: Int -> [String] -> Maybe Int |
| 22 | +reflectionLine dx xs = find f [1..length xs - 1] |
| 23 | + where f i = let (a, b) = splitAt i xs in difference (reverse a) b == dx |
| 24 | + |
| 25 | +difference :: [String] -> [String] -> Int |
| 26 | +difference xs = sum . zipWith rd xs |
| 27 | + where rd r = sum . zipWith (\c1 c2 -> if c1 == c2 then 0 else 1) r |
| 28 | + |
| 29 | +solve :: Int -> [Pattern] -> Int |
| 30 | +solve dx = sum . map (fromJust . f) |
| 31 | + where f p = (*100) <$> reflectionLine dx p <|> reflectionLine dx (transpose p) |
| 32 | + |
| 33 | +p1, p2 :: [Pattern] -> Int |
| 34 | +p1 = solve 0 |
| 35 | +p2 = solve 1 |
0 commit comments