@@ -12,6 +12,7 @@ common common
|
|||||||
LambdaCase
|
LambdaCase
|
||||||
TupleSections
|
TupleSections
|
||||||
ViewPatterns
|
ViewPatterns
|
||||||
|
MultiWayIf
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, base >=4.14 && <5
|
, base >=4.14 && <5
|
||||||
@@ -122,3 +123,9 @@ executable day15
|
|||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
main-is: Day15.hs
|
main-is: Day15.hs
|
||||||
build-depends: containers
|
build-depends: containers
|
||||||
|
|
||||||
|
executable day16
|
||||||
|
import: common
|
||||||
|
hs-source-dirs: src
|
||||||
|
main-is: Day16.hs
|
||||||
|
build-depends: containers
|
||||||
|
94
src/Day16.hs
Normal file
94
src/Day16.hs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
module Main where
|
||||||
|
|
||||||
|
import qualified Data.Map as M
|
||||||
|
import qualified Data.Set as S
|
||||||
|
|
||||||
|
type Coord = (Int, Int)
|
||||||
|
|
||||||
|
type Grid = M.Map Coord Char
|
||||||
|
|
||||||
|
data Dir = East | West | North | South deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
type State = (Coord, Dir)
|
||||||
|
|
||||||
|
type Queue = S.Set (Int, Coord, Dir)
|
||||||
|
|
||||||
|
dirs :: [Dir]
|
||||||
|
dirs = [East, West, North, South]
|
||||||
|
|
||||||
|
next :: Coord -> Dir -> Coord
|
||||||
|
next (x, y) East = (x + 1, y)
|
||||||
|
next (x, y) West = (x - 1, y)
|
||||||
|
next (x, y) North = (x, y - 1)
|
||||||
|
next (x, y) South = (x, y + 1)
|
||||||
|
|
||||||
|
rotate :: Dir -> Dir
|
||||||
|
rotate East = South
|
||||||
|
rotate South = West
|
||||||
|
rotate West = North
|
||||||
|
rotate North = East
|
||||||
|
|
||||||
|
rotate' :: Dir -> Dir
|
||||||
|
rotate' East = North
|
||||||
|
rotate' North = West
|
||||||
|
rotate' West = South
|
||||||
|
rotate' South = East
|
||||||
|
|
||||||
|
dijkstra :: Queue -> Char -> Grid -> M.Map State Int
|
||||||
|
dijkstra queue end grid = case travel queue M.empty of
|
||||||
|
Just distances -> distances
|
||||||
|
Nothing -> error "what?"
|
||||||
|
where
|
||||||
|
travel :: Queue -> M.Map State Int -> Maybe (M.Map State Int)
|
||||||
|
travel q dist = do
|
||||||
|
((dis, c, dir), q') <- S.minView q
|
||||||
|
|
||||||
|
let q'' =
|
||||||
|
S.insert (dis + 1000, c, rotate dir) $
|
||||||
|
S.insert (dis + 1000, c, rotate' dir) q'
|
||||||
|
n = next c dir
|
||||||
|
dist' = M.insert (c, dir) dis dist
|
||||||
|
|
||||||
|
ch <- M.lookup n grid
|
||||||
|
|
||||||
|
if
|
||||||
|
| (c, dir) `M.member` dist -> if S.null q' then Just dist else travel q' dist
|
||||||
|
| ch `elem` [end, '.'] -> travel (S.insert (dis + 1, n, dir) q'') dist'
|
||||||
|
| otherwise -> travel q'' dist'
|
||||||
|
|
||||||
|
part1 :: Grid -> Coord -> Coord -> Int
|
||||||
|
part1 grid start end = minimum [dis | ((c, _), dis) <- M.assocs dist, c == end]
|
||||||
|
where
|
||||||
|
dist :: M.Map State Int
|
||||||
|
dist = dijkstra (S.fromList [(0, start, East)]) 'E' grid
|
||||||
|
|
||||||
|
part2 :: Grid -> Coord -> Coord -> Int -> Int
|
||||||
|
part2 grid start end cost =
|
||||||
|
(+ 2) . S.size . S.fromList $
|
||||||
|
[ c
|
||||||
|
| (c, ch) <- M.assocs grid,
|
||||||
|
ch == '.',
|
||||||
|
dir <- dirs,
|
||||||
|
let Just d1 = M.lookup (c, dir) dist,
|
||||||
|
let Just d2 = M.lookup (c, (rotate . rotate) dir) dist',
|
||||||
|
d1 + d2 == cost
|
||||||
|
]
|
||||||
|
where
|
||||||
|
dist :: M.Map State Int
|
||||||
|
dist = dijkstra (S.fromList [(0, start, East)]) 'E' grid
|
||||||
|
|
||||||
|
dist' :: M.Map State Int
|
||||||
|
dist' = dijkstra (S.fromList [(0, end, dir) | dir <- dirs]) 'S' grid
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main =
|
||||||
|
do
|
||||||
|
raw <- lines <$> readFile "./inputs/day16.in"
|
||||||
|
|
||||||
|
let grid = M.fromList [((x, y), ch) | (y, row) <- zip [0 ..] raw, (x, ch) <- zip [0 ..] row]
|
||||||
|
[start] = [(x, y) | (y, row) <- zip [0 ..] raw, (x, ch) <- zip [0 ..] row, ch == 'S']
|
||||||
|
[end] = [(x, y) | (y, row) <- zip [0 ..] raw, (x, ch) <- zip [0 ..] row, ch == 'E']
|
||||||
|
cost = part1 grid start end
|
||||||
|
|
||||||
|
putStr "Part 1: " >> print cost
|
||||||
|
putStr "Part 2: " >> print (part2 grid start end cost)
|
Reference in New Issue
Block a user