|
| 1 | +import Data.Map qualified as M |
| 2 | +import Data.Set qualified as S |
| 3 | +import Data.Maybe (fromJust) |
| 4 | +import Control.Arrow ((&&&)) |
| 5 | + |
| 6 | +main :: IO () |
| 7 | +main = interact $ (++ "\n") . show . (p1 &&& p2) . parse |
| 8 | + |
| 9 | +type Ix = (Int, Int) |
| 10 | +data Grid = Grid { chars :: M.Map Ix Char, mi :: Ix } |
| 11 | + |
| 12 | +parse :: String -> Grid |
| 13 | +parse = mkC . concatMap (uncurry f) . zip [0..] . lines |
| 14 | + where f y = map (uncurry g) . zip [0..] |
| 15 | + where g x = ((x, y),) |
| 16 | + mkC xs = Grid (M.fromList xs) (fst $ last xs) |
| 17 | + |
| 18 | +p1 :: Grid -> Int |
| 19 | +p1 = (`energized` ((0, 0), R)) |
| 20 | + |
| 21 | +p2 :: Grid -> Int |
| 22 | +p2 grid = maximum $ map (energized grid) $ edges grid |
| 23 | + |
| 24 | +data Direction = R | L | U | D deriving (Ord, Eq) |
| 25 | +type Beam = (Ix, Direction) |
| 26 | + |
| 27 | +energized :: Grid -> Beam -> Int |
| 28 | +energized Grid { chars, mi = (mx, my) } start = |
| 29 | + count $ trace S.empty [start] |
| 30 | + where |
| 31 | + count = S.size . S.map fst |
| 32 | + trace processed [] = processed |
| 33 | + trace processed (b:bs) |
| 34 | + | S.member b processed = trace processed bs |
| 35 | + | otherwise = |
| 36 | + let (ray, beams) = until b (char b) |
| 37 | + in trace (foldl (\s b -> S.insert b s) processed ray) |
| 38 | + (bs ++ filter inBounds beams) |
| 39 | + |
| 40 | + until b '|' | isHorizontal b = ([b], splitV b) |
| 41 | + until b '-' | isVertical b = ([b], splitH b) |
| 42 | + until b@(_, d) '\\' |
| 43 | + | d == R = ([b], [reflectD b]) |
| 44 | + | d == L = ([b], [reflectU b]) |
| 45 | + | d == U = ([b], [reflectL b]) |
| 46 | + | d == D = ([b], [reflectR b]) |
| 47 | + until b@(_, d) '/' |
| 48 | + | d == R = ([b], [reflectU b]) |
| 49 | + | d == L = ([b], [reflectD b]) |
| 50 | + | d == U = ([b], [reflectR b]) |
| 51 | + | d == D = ([b], [reflectL b]) |
| 52 | + until b _ = let n = step b in |
| 53 | + if inBounds n then let (ray, beams) = until n (char n) in (b : ray, beams) |
| 54 | + else ([b], []) |
| 55 | + |
| 56 | + inBounds ((x, y), _) = x >= 0 && y >= 0 && x <= mx && y <= my |
| 57 | + char b = fromJust $ M.lookup (fst b) chars |
| 58 | + isHorizontal (_, d) = d == L || d == R |
| 59 | + isVertical = not . isHorizontal |
| 60 | + step ((x, y), R) = ((x + 1, y), R) |
| 61 | + step ((x, y), L) = ((x - 1, y), L) |
| 62 | + step ((x, y), U) = ((x, y - 1), U) |
| 63 | + step ((x, y), D) = ((x, y + 1), D) |
| 64 | + splitH ((x, y), _) = [((x - 1, y), L), ((x + 1, y), R)] |
| 65 | + splitV ((x, y), _) = [((x, y - 1), U), ((x, y + 1), D)] |
| 66 | + reflectU ((x, y), _) = ((x, y - 1), U) |
| 67 | + reflectD ((x, y), _) = ((x, y + 1), D) |
| 68 | + reflectL ((x, y), _) = ((x - 1, y), L) |
| 69 | + reflectR ((x, y), _) = ((x + 1, y), R) |
| 70 | + |
| 71 | +edges :: Grid -> [Beam] |
| 72 | +edges Grid { mi = (mx, my) } = concat [ |
| 73 | + [b | y <- [0..my], b <- [((0, y), R), ((mx, y), L)]], |
| 74 | + [((x, 0), D) | x <- [0..mx]], |
| 75 | + [((x, my), U) | x <- [0..mx]]] |
0 commit comments