Done day 24
authorNeil Smith <NeilNjae@users.noreply.github.com>
Sat, 24 Dec 2022 14:47:33 +0000 (14:47 +0000)
committerNeil Smith <NeilNjae@users.noreply.github.com>
Sat, 24 Dec 2022 15:53:53 +0000 (15:53 +0000)
advent-of-code22.cabal
advent24/Main.hs [new file with mode: 0644]
data/advent24.txt [new file with mode: 0644]
data/advent24a.txt [new file with mode: 0644]
problems/day24.html [new file with mode: 0644]

index 20d4771f790d2179a3586711741648203dcf049c..532085cd133ae57a07666bc22e747c0895ea06aa 100644 (file)
@@ -224,4 +224,8 @@ executable advent23prof
                        -Wall 
                        -threaded 
                        -rtsopts "-with-rtsopts=-N -p -s -hT"
-                       
\ No newline at end of file
+
+executable advent24
+  import: common-extensions, build-directives
+  main-is: advent24/Main.hs
+  build-depends: containers, pqueue, mtl, lens, linear, array
diff --git a/advent24/Main.hs b/advent24/Main.hs
new file mode 100644 (file)
index 0000000..c3e1469
--- /dev/null
@@ -0,0 +1,224 @@
+-- Writeup at https://work.njae.me.uk/2022/12/24/advent-of-code-2022-day-24/
+
+-- import Debug.Trace
+
+import AoC
+import qualified Data.PQueue.Prio.Min as P
+import qualified Data.Set as S
+import qualified Data.IntMap.Strict as M
+import qualified Data.Sequence as Q
+-- import Data.Sequence ((<|), (|>), (><)) 
+import Data.Sequence ((|>)) 
+import Control.Monad.Reader
+import Control.Lens hiding ((<|), (|>), (:>), (:<), indices)
+import Linear (V2(..), (^+^), (^-^))
+import Data.Array.IArray
+-- import Data.Ix
+import Data.List
+import Data.Maybe
+
+-- pattern Empty   <- (Q.viewl -> Q.EmptyL)  where Empty = Q.empty
+-- pattern x :< xs <- (Q.viewl -> x Q.:< xs) where (:<)  = (Q.<|) 
+-- pattern xs :> x <- (Q.viewr -> xs Q.:> x) where (:>)  = (Q.|>) 
+
+type Position = V2 Int -- x, y
+
+data Blizzard = Blizzard { _positionB :: Position, _headingB :: Position}
+  deriving (Eq, Ord, Show)
+makeLenses ''Blizzard
+
+type SafeValley = Array Position Bool
+type TimedValley = M.IntMap SafeValley
+
+data Valley = Valley
+  { blizzardStates :: TimedValley
+  , start :: Position
+  , goal :: Position
+  } deriving (Eq, Ord, Show)
+
+type ValleyContext = Reader Valley
+
+data Explorer = Explorer
+  { _currentPosition :: Position
+  , _currentTime :: Int
+  }deriving (Eq, Ord, Show)
+makeLenses ''Explorer
+
+data Agendum  = 
+    Agendum { _current :: Explorer
+            , _trail :: Q.Seq Explorer
+            , _trailCost :: Int
+            , _cost :: Int
+            } deriving (Show, Eq)
+makeLenses ''Agendum   
+
+type Agenda = P.MinPQueue Int Agendum
+
+type ExploredStates = S.Set Explorer
+
+main :: IO ()
+main = 
+  do  dataFileName <- getDataFileName
+      text <- readFile dataFileName
+      let (blizzards, bnds) = mkInitialMap text
+      let valley = makeValley bnds blizzards 1000
+      print $ part1 valley
+      print $ part2 valley
+
+part1, part2 :: Valley -> Int
+part1 valley = _currentTime $ _current $ fromJust result
+  where result = runSearch valley 0
+
+part2 valley = trip3End
+  where reverseValley = valley {start = (goal valley), goal = (start valley)}
+        trip1End = _currentTime $ _current $ fromJust $ runSearch valley 0
+        trip2End = _currentTime $ _current $ fromJust $ runSearch reverseValley trip1End
+        trip3End = _currentTime $ _current $ fromJust $ runSearch valley trip2End
+
+makeValley :: (Position, Position) -> S.Set Blizzard -> Int -> Valley
+makeValley bds blizzards n = Valley
+  { blizzardStates = bStates
+  , start = V2 (minX + 1) maxY
+  , goal = V2 (maxX - 1) minY
+  }
+  where bStates = simulateBlizzards bds blizzards n 
+        (V2 minX minY, V2 maxX maxY) = bounds $ bStates M.! 0
+
+runSearch :: Valley -> Int -> Maybe Agendum 
+runSearch valley t = result
+  where result = runReader (searchValley t) valley
+
+searchValley :: Int -> ValleyContext (Maybe Agendum)
+searchValley t = 
+    do agenda <- initAgenda t
+       aStar agenda S.empty
+
+initAgenda :: Int -> ValleyContext Agenda
+initAgenda t = 
+    do pos <- asks start
+       let explorer = Explorer pos t
+       c <- estimateCost explorer
+       return $ P.singleton c Agendum { _current = explorer, _trail = Q.empty, _trailCost = 0, _cost = c}
+
+aStar ::  Agenda -> ExploredStates -> ValleyContext (Maybe Agendum)
+aStar agenda closed 
+    -- | trace ("Peeping " ++ (show $ fst $ P.findMin agenda) ++ ": " ++ (show reached) ++ " <- " ++ (show $ toList $ Q.take 1 $ _trail $ currentAgendum) ++ " :: " ++ (show newAgenda)) False = undefined
+    -- | trace ("Peeping " ++ (show $ _current $ snd $ P.findMin agenda) ) False = undefined
+    -- | trace ("Peeping " ++ (show $ snd $ P.findMin agenda) ) False = undefined
+    | P.null agenda = return Nothing
+    | otherwise = 
+        do  let (_, currentAgendum) = P.findMin agenda
+            let reached = currentAgendum ^. current
+            nexts <- candidates currentAgendum closed
+            let newAgenda = foldl' (\q a -> P.insert (_cost a) a q) (P.deleteMin agenda) nexts
+            reachedGoal <- isGoal reached
+            if reachedGoal
+            then return (Just currentAgendum)
+            else if reached `S.member` closed
+                 then aStar (P.deleteMin agenda) closed
+                 else aStar newAgenda (S.insert reached closed)
+
+candidates ::  Agendum -> ExploredStates -> ValleyContext (Q.Seq Agendum)
+candidates agendum closed = 
+    do  let candidate = agendum ^. current
+        let previous = agendum ^. trail
+        let prevCost = agendum ^. trailCost
+        succs <- successors candidate
+        let nonloops = Q.filter (\s -> s `S.notMember` closed) succs
+        mapM (makeAgendum previous prevCost) nonloops
+
+makeAgendum ::  Q.Seq Explorer -> Int -> Explorer -> ValleyContext Agendum 
+makeAgendum previous prevCost newExplorer = 
+    do predicted <- estimateCost newExplorer
+       let newTrail = previous |> newExplorer
+       let incurred = prevCost + 1
+       return Agendum { _current = newExplorer
+                      , _trail = newTrail
+                      , _trailCost = incurred
+                      , _cost = incurred + predicted
+                      }
+
+isGoal :: Explorer -> ValleyContext Bool
+isGoal here = 
+  do goal <- asks goal
+     return $ (here ^. currentPosition) == goal
+
+successors :: Explorer -> ValleyContext (Q.Seq Explorer)
+successors here = 
+  do allBlizzards <- asks blizzardStates
+     let nextTime = (here ^. currentTime) + 1
+     let blizzards = allBlizzards M.! nextTime
+     let bds = bounds blizzards
+     let pos = here ^. currentPosition
+     let neighbours = 
+          filter (\p -> (blizzards ! p)) $
+          filter (inRange bds)
+            [ pos ^+^ delta
+            | delta <- [V2 0 0, V2 -1 0, V2 1 0, V2 0 -1, V2 0 1]
+            ]
+     let succs = Q.fromList 
+                  $ fmap (\nbr -> here & currentTime .~ nextTime 
+                                       & currentPosition .~ nbr ) 
+                         neighbours
+     return succs
+
+estimateCost :: Explorer -> ValleyContext Int
+estimateCost here = 
+  do goal <- asks goal
+     let (V2 dx dy) = (here ^. currentPosition) ^-^ goal
+     return $ (abs dx) + (abs dy)
+
+
+mkInitialMap :: String -> (S.Set Blizzard, (Position, Position))
+mkInitialMap text = 
+  ( S.fromList [ Blizzard (V2 (x - 1) (y - 1)) (deltaOfArrow $ charAt x y)
+               | x <- [0..maxX]
+               , y <- [0..maxY]
+               , isBlizzard x y
+               ]
+  , (V2 0 0, V2 (maxX - 1) (maxY - 1))
+  )
+  where rows = reverse $ lines text
+        maxY = length rows - 1
+        maxX = (length $ head rows) - 1
+        charAt x y = ((rows !! y) !! x)
+        isBlizzard x y = (charAt x y) `elem` ("^<>v" :: String)
+
+deltaOfArrow :: Char -> Position
+deltaOfArrow '^' = V2 0 1
+deltaOfArrow '>' = V2 1 0
+deltaOfArrow 'v' = V2 0 -1
+deltaOfArrow '<' = V2 -1 0
+deltaOfArrow _   = V2 0 0
+
+advanceBlizzard :: (Position, Position) -> S.Set Blizzard -> S.Set Blizzard
+advanceBlizzard bnds blizzards = S.map (advanceOneBlizzard bnds) blizzards
+
+advanceOneBlizzard :: (Position, Position) -> Blizzard -> Blizzard
+advanceOneBlizzard (_, V2 maxX maxY) blizzard = blizzard' & positionB %~ wrap
+  where wrap (V2 x0 y0) = V2 (x0 `mod` maxX) (y0 `mod` maxY)
+        blizzard' = blizzard & positionB %~ (^+^ (blizzard ^. headingB))
+
+toSafe :: (Position, Position) -> S.Set Blizzard -> SafeValley
+toSafe (_, V2 maxX maxY) blizzards = accumArray (\_ _ -> False) True bnds' unsafeElements
+  where unsafeElements = fmap (\i -> (i, False)) $ blizzardLocations ++ walls
+        blizzardLocations = fmap (^+^ (V2 1 1)) $ fmap (^. positionB) $ S.toList blizzards
+        walls = left ++ right ++ top ++ bottom
+        left   = range (V2 0          0         , V2 0          (maxY + 1))
+        right  = range (V2 (maxX + 1) 0         , V2 (maxX + 1) (maxY + 1))
+        top    = range (V2 2          (maxY + 1), V2 (maxX + 1) (maxY + 1))
+        bottom = range (V2 0          0         , V2 (maxX - 1) 0         )
+        bnds' = (V2 0 0, V2 (maxX + 1) (maxY + 1))
+
+simulateBlizzards :: (Position, Position) -> S.Set Blizzard -> Int -> TimedValley
+simulateBlizzards bnds blizzards n = 
+  M.fromList $ take n 
+             $ zip [0..] 
+             $ fmap (toSafe bnds) 
+             $ iterate (advanceBlizzard bnds) blizzards
+
+showSafe :: SafeValley -> String
+showSafe valley = unlines $ reverse rows
+  where (V2 minX minY, V2 maxX maxY) = bounds valley
+        rows = [mkRow y | y <- [minY..maxY]]
+        mkRow y = [if valley ! (V2 x y) then '.' else '#' | x <- [minX..maxX]]
diff --git a/data/advent24.txt b/data/advent24.txt
new file mode 100644 (file)
index 0000000..7bd0678
--- /dev/null
@@ -0,0 +1,27 @@
+#.########################################################################################################################
+#.<v>><<<^v<>^<^vv.^<^^^<^v><>vv<v^.^v>v.^><v..<><..vv><v.<.v<<^.>>>>>>^<^>^>vv<^>>^v^.<.<<>^<<>^>>^>.><>.^>.v^<<><<^vvv<#
+#>.<v>v<>v>vv^.<>^^v.><<^>^v^<>v^>>>><<^<^vv>v>><^>v.^v<<^v<.<>v>>^><>>^>^<>v<><<>.v.^<.<<>vvv<^v.<>v>^^vv^^^<>^^<<<^<v>>#
+#><.<<vvv<>.vvv<><^<>v<.v>v.<>^>^v>^<<><vv^<v>><vv<<><^^^v^>^..<<^<.><v<v>^^v.<<vv<v^^>vv><<>^v><>><>^<^^^^v^<>><.vvvv.<>#
+#>v>^v>>vvv<v><>.><>.>>v>vvv<v<v<>^>>><<>>><.vvv.<>.<>^<>v><<v^^<>v>.>^^v^.^><^<^<<v<<^<^<^<vv.><<^^^><vvv.>v><>^v^.<<>v>#
+#<^>v>vvv>v<v<vv<<.v<<v<^<v^.^v.>.>v^<..^.^<..^>>^vv^<<vv<><v.<<>>><^v><>>vv.v<^.v<v>^<>v.>^<.^v>><<>v><v^<><v>vv>><<^>>>#
+#<^v<>vv<v^^>^>><<^<<v<>^<vv<<<^vv^<>>^^<.<<^^.v<^<><vv^v.v<>>v^<^^>v>v>><v<v>v^<<.^<<^>>><^v<>^^<>v>><>.v>v.^>><>.<v>^<>#
+#<.<.>vvv^^.^.<v.>^<<<.<>>>v^><.v>v.>^^<^>^><vv^<.<v>>>^>v.v<>.^^^^.^<v<v^.v>^>v.<^>>^<v<>vv^<vv<<<v<<.>^vv>>v><^^.><>>.>#
+#><>v<<^v^v^^><v>>v^>>.v<>>>>.><^>>>.v<v>v^>>vv>.v>v^v<v^<<>>>><<<>v.v<v<^^.<>v.^<v>vvv^vv>^v..<^^^^^v^>v<<.^^<>.vv.^^>><#
+#>.v^^.v<vv^v<^^>v^<>.<><^^.<v<vv.v>v.^^<v^v^>>^>v<^<v.^><.<<<vv^^<v^<>>.v^.>v<>>^>vvv<vv<<^<><^^^v<<<^>>v^vvv^vvv>v>^<>>#
+#><^<<vv^>^<^v.><vv<^v>>^<>^>><<<<<^..^^<<^>v>.vvv^vv^>>v^v^^v<.<.v^<>v^<<><<v<^>^vv><>>^v.v.^>>^>^><>v<<<^<v<<^^v<^^^vv<#
+#><><<><.<<>>>>>^v^<v^>>^..v>^<v^<<^.><>.<<.>v>v<>.<v<<<><<>.<vv^vv>v<.v>^<>><v><<>>v<>>^><.vvv.><^<><^v>v<^v>^v<>>^.v.<>#
+#<>><^.^^v^v><^^<.>v<>^><>v^.v>vv^>>>><^vvv>>.>.<>vv>^>v<.^>^<v<>v>^v>^v>v^^vv.<<>^<..^v<>v<>vv<<<^v<^v<v<>>^^v>><v><v^<>#
+#><.<v..^<><^v><>v>>vvvv^vvv.^.v>v^^.>vvv^^<>vvv>vv<vv>>>>>^>v.>.>^><>^^.>>.^<v>.vv^<v>><vv><>><^><v^..<v^>^<<<.<<.>.v<^>#
+#><<v<>vvvv<^>^.>^.<<.<v^v<<<^^^.>.^^>.v<>^v><v^vv^<<<<<.v<v>^^>^vvv<<<v^<v<.<vv>>.^v^v<<>v^..v^<v>^<>><<>v^vv<^.^.><v^><#
+#<.<vv<v^^v>v><.>v^vv..<><.v>^>^^^^^>v^v><v<v><^>v<<v^<^^.<>v<^v>^<v^v^^<v^^>.v.>>>^^>.^^<>v>><v^>^^.v>vv^<^>v^><v<v<>>^<#
+#<^<^><>>v<.>^>v>v<>^^<>v>v<>v>><^><>>v.v^v^^^v^^vv<^>><<v><<v><>^^^>^<<<>.^<>>>.>v.v^..^<^>>>>.^>^^.>>^<v^>>^<^<v^><.^<>#
+#>><^v><>v><v^<><vv.v<v<<^<.v><.^^>.^v>^v^v.vv<^.><^^.^<>vv>>>.>v^.<^<^v>^v.<<<v^v<>vv><v^.<^>.^v^v>^<.<<.^v^>^^<>>.^^v<>#
+#>.^v^>v<..<v>v^.<>^.>^<^v.^><>^>^><^>><v<v>^<<v<<<><v<vv<v^^.<v>.>.^.<><v^<v<vvv<>>^<vv<<v>.v.^v>v<>v>v>v>>^^v>v<>^^^v<<#
+#<v>v><<>>v<^>v^v>.>v>><^v>v^>....v<<^^^^vv<>><^<^^v^>>^<<^^>^<.^^<>v<vv.>v^<^<<>v^vv^^.^>^.^>>.<>^>.v^<>^.<.<<v<<^^>^^.<#
+#>vv<v^v^<.v^><^^>^^v<v>^v<<^^v<><^v.<<v^vv^>><.>^.^^^..v<>>^>.<v<.>.><<<.v<^<>^<>>^^<^.^>^<>>v<.>^<<<<<v<v^v>>v^^.^<..<>#
+#<^^vvv^<.^<>.^^.<^<<<v<vv>>.><v>^vv^.v<>.<.>.><<^>.v<><v<^^>.v<vv.>v>vv<<<<>.>^v>>^<>.^>>^>v>.v<v><v<^^^^<^^v^v.^<..v>^<#
+#<<^<v^^>>^^>v>>v><>>>>>v>v><^^^vv<v><v><>.v<<<><.v.<><><><^.^v<<^<vv^^v<v^v^>>.<v^vv<<>v^vv><^>^^>v>>v<^.<.<^^<>^^v<><<>#
+#<^>>^<.>><>>v.^.>^^>>^<<><vvv^.vv>v<>>^v<>^>.^v<^^^>.<>v><<v<v>>^<^v<v>v<><<^^<.^^v<^^<<^<^<<^^>^^^<^^v<<>>>v^.vv<.v^><>#
+#<vv^v.v>>.>>>.<><v<>^.v<v^>^^<<^^>vv^>>>>>v^v>vv^>.<v.<<v>vv<v^vv><.vv.<.^<vv<<^><v>.>.><<^<.vv.vv>.^^>vv>><<<vv^<><.<v.#
+#<^v>><>v..><^<<>.v<.>><><.^<<<<<v<<v^.^.^<.><v.vv<v..<<>^<vv.>>>v^.<vv.v<>^>>.<v><.<<^vvv^.^vv^<>^^<.^<^<.^<<><v<<v>^<^>#
+########################################################################################################################.#
\ No newline at end of file
diff --git a/data/advent24a.txt b/data/advent24a.txt
new file mode 100644 (file)
index 0000000..6b9b892
--- /dev/null
@@ -0,0 +1,6 @@
+#.######
+#>>.<^<#
+#.<..<<#
+#>v.><>#
+#<^v^^>#
+######.#
\ No newline at end of file
diff --git a/problems/day24.html b/problems/day24.html
new file mode 100644 (file)
index 0000000..099c45c
--- /dev/null
@@ -0,0 +1,349 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+<meta charset="utf-8"/>
+<title>Day 24 - Advent of Code 2022</title>
+<!--[if lt IE 9]><script src="/static/html5.js"></script><![endif]-->
+<link href='//fonts.googleapis.com/css?family=Source+Code+Pro:300&subset=latin,latin-ext' rel='stylesheet' type='text/css'/>
+<link rel="stylesheet" type="text/css" href="/static/style.css?30"/>
+<link rel="stylesheet alternate" type="text/css" href="/static/highcontrast.css?0" title="High Contrast"/>
+<link rel="shortcut icon" href="/favicon.png"/>
+<script>window.addEventListener('click', function(e,s,r){if(e.target.nodeName==='CODE'&&e.detail===3){s=window.getSelection();s.removeAllRanges();r=document.createRange();r.selectNodeContents(e.target);s.addRange(r);}});</script>
+</head><!--
+
+
+
+
+Oh, hello!  Funny seeing you here.
+
+I appreciate your enthusiasm, but you aren't going to find much down here.
+There certainly aren't clues to any of the puzzles.  The best surprises don't
+even appear in the source until you unlock them for real.
+
+Please be careful with automated requests; I'm not a massive company, and I can
+only take so much traffic.  Please be considerate so that everyone gets to play.
+
+If you're curious about how Advent of Code works, it's running on some custom
+Perl code. Other than a few integrations (auth, analytics, social media), I
+built the whole thing myself, including the design, animations, prose, and all
+of the puzzles.
+
+The puzzles are most of the work; preparing a new calendar and a new set of
+puzzles each year takes all of my free time for 4-5 months. A lot of effort
+went into building this thing - I hope you're enjoying playing it as much as I
+enjoyed making it for you!
+
+If you'd like to hang out, I'm @ericwastl on Twitter.
+
+- Eric Wastl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-->
+<body>
+<header><div><h1 class="title-global"><a href="/">Advent of Code</a></h1><nav><ul><li><a href="/2022/about">[About]</a></li><li><a href="/2022/events">[Events]</a></li><li><a href="https://teespring.com/stores/advent-of-code" target="_blank">[Shop]</a></li><li><a href="/2022/settings">[Settings]</a></li><li><a href="/2022/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <a href="/2022/support" class="supporter-badge" title="Advent of Code Supporter">(AoC++)</a> <span class="star-count">48*</span></div></div><div><h1 class="title-event">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="title-event-wrap">/*</span><a href="/2022">2022</a><span class="title-event-wrap">*/</span></h1><nav><ul><li><a href="/2022">[Calendar]</a></li><li><a href="/2022/support">[AoC++]</a></li><li><a href="/2022/sponsors">[Sponsors]</a></li><li><a href="/2022/leaderboard">[Leaderboard]</a></li><li><a href="/2022/stats">[Stats]</a></li></ul></nav></div></header>
+
+<div id="sidebar">
+<div id="sponsor"><div class="quiet">Our <a href="/2022/sponsors">sponsors</a> help make Advent of Code possible:</div><div class="sponsor"><a href="https://www.americanexpress.com/en-us/careers/career-areas/technology/" target="_blank" onclick="if(ga)ga('send','event','sponsor','sidebar',this.href);" rel="noopener">American Express</a> - Work with the latest tech and back the engineering community through open source. Find your place in tech on #TeamAmex.</div></div>
+</div><!--/sidebar-->
+
+<main>
+<article class="day-desc"><h2>--- Day 24: Blizzard Basin ---</h2><p>With everything replanted for next year (and with elephants and monkeys to tend the grove), you and the Elves leave for the extraction point.</p>
+<p>Partway up the mountain that shields the grove is a flat, open area that serves as the extraction point. It's a bit of a climb, but nothing the expedition can't handle.</p>
+<p>At least, that would normally be true; now that the mountain is covered in snow, things have become more difficult than the Elves are used to.</p>
+<p>As the expedition reaches a valley that must be traversed to reach the extraction site, you find that strong, turbulent winds are pushing small <em>blizzards</em> of snow and sharp ice around the valley. It's a good thing everyone packed warm clothes! To make it across safely, you'll need to find a way to avoid them.</p>
+<p>Fortunately, it's easy to see all of this from the entrance to the valley, so you make a map of the valley and the blizzards (your puzzle input). For example:</p>
+<pre><code>#.#####
+#.....#
+#&gt;....#
+#.....#
+#...v.#
+#.....#
+#####.#
+</code></pre>
+<p>The walls of the valley are drawn as <code>#</code>; everything else is ground. Clear ground - where there is currently no blizzard - is drawn as <code>.</code>. Otherwise, blizzards are drawn with an arrow indicating their direction of motion: up (<code>^</code>), down (<code>v</code>), left (<code>&lt;</code>), or right (<code>&gt;</code>).</p>
+<p>The above map includes two blizzards, one moving right (<code>&gt;</code>) and one moving down (<code>v</code>). In one minute, each blizzard moves one position in the direction it is pointing:</p>
+<pre><code>#.#####
+#.....#
+#.&gt;...#
+#.....#
+#.....#
+#...v.#
+#####.#
+</code></pre>
+<p>Due to <span title="I think, anyway. Do I look like a theoretical blizzacist?">conservation of blizzard energy</span>, as a blizzard reaches the wall of the valley, a new blizzard forms on the opposite side of the valley moving in the same direction. After another minute, the bottom downward-moving blizzard has been replaced with a new downward-moving blizzard at the top of the valley instead:</p>
+<pre><code>#.#####
+#...v.#
+#..&gt;..#
+#.....#
+#.....#
+#.....#
+#####.#
+</code></pre>
+<p>Because blizzards are made of tiny snowflakes, they pass right through each other. After another minute, both blizzards temporarily occupy the same position, marked <code>2</code>:</p>
+<pre><code>#.#####
+#.....#
+#...2.#
+#.....#
+#.....#
+#.....#
+#####.#
+</code></pre>
+<p>After another minute, the situation resolves itself, giving each blizzard back its personal space:</p>
+<pre><code>#.#####
+#.....#
+#....&gt;#
+#...v.#
+#.....#
+#.....#
+#####.#
+</code></pre>
+<p>Finally, after yet another minute, the rightward-facing blizzard on the right is replaced with a new one on the left facing the same direction:</p>
+<pre><code>#.#####
+#.....#
+#&gt;....#
+#.....#
+#...v.#
+#.....#
+#####.#
+</code></pre>
+<p>This process repeats at least as long as you are observing it, but probably forever.</p>
+<p>Here is a more complex example:</p>
+<pre><code>#.######
+#&gt;&gt;.&lt;^&lt;#
+#.&lt;..&lt;&lt;#
+#&gt;v.&gt;&lt;&gt;#
+#&lt;^v^^&gt;#
+######.#
+</code></pre>
+<p>Your expedition begins in the only non-wall position in the top row and needs to reach the only non-wall position in the bottom row. On each minute, you can <em>move</em> up, down, left, or right, or you can <em>wait</em> in place. You and the blizzards act <em>simultaneously</em>, and you cannot share a position with a blizzard.</p>
+<p>In the above example, the fastest way to reach your goal requires <code><em>18</em></code> steps. Drawing the position of the expedition as <code>E</code>, one way to achieve this is:</p>
+<pre><code>Initial state:
+#<em>E</em>######
+#&gt;&gt;.&lt;^&lt;#
+#.&lt;..&lt;&lt;#
+#&gt;v.&gt;&lt;&gt;#
+#&lt;^v^^&gt;#
+######.#
+
+Minute 1, move down:
+#.######
+#<em>E</em>&gt;3.&lt;.#
+#&lt;..&lt;&lt;.#
+#&gt;2.22.#
+#&gt;v..^&lt;#
+######.#
+
+Minute 2, move down:
+#.######
+#.2&gt;2..#
+#<em>E</em>^22^&lt;#
+#.&gt;2.^&gt;#
+#.&gt;..&lt;.#
+######.#
+
+Minute 3, wait:
+#.######
+#&lt;^&lt;22.#
+#<em>E</em>2&lt;.2.#
+#&gt;&lt;2&gt;..#
+#..&gt;&lt;..#
+######.#
+
+Minute 4, move up:
+#.######
+#<em>E</em>&lt;..22#
+#&lt;&lt;.&lt;..#
+#&lt;2.&gt;&gt;.#
+#.^22^.#
+######.#
+
+Minute 5, move right:
+#.######
+#2<em>E</em>v.&lt;&gt;#
+#&lt;.&lt;..&lt;#
+#.^&gt;^22#
+#.2..2.#
+######.#
+
+Minute 6, move right:
+#.######
+#&gt;2<em>E</em>&lt;.&lt;#
+#.2v^2&lt;#
+#&gt;..&gt;2&gt;#
+#&lt;....&gt;#
+######.#
+
+Minute 7, move down:
+#.######
+#.22^2.#
+#&lt;v<em>E</em>&lt;2.#
+#&gt;&gt;v&lt;&gt;.#
+#&gt;....&lt;#
+######.#
+
+Minute 8, move left:
+#.######
+#.&lt;&gt;2^.#
+#.<em>E</em>&lt;&lt;.&lt;#
+#.22..&gt;#
+#.2v^2.#
+######.#
+
+Minute 9, move up:
+#.######
+#&lt;<em>E</em>2&gt;&gt;.#
+#.&lt;&lt;.&lt;.#
+#&gt;2&gt;2^.#
+#.v&gt;&lt;^.#
+######.#
+
+Minute 10, move right:
+#.######
+#.2<em>E</em>.&gt;2#
+#&lt;2v2^.#
+#&lt;&gt;.&gt;2.#
+#..&lt;&gt;..#
+######.#
+
+Minute 11, wait:
+#.######
+#2^<em>E</em>^2&gt;#
+#&lt;v&lt;.^&lt;#
+#..2.&gt;2#
+#.&lt;..&gt;.#
+######.#
+
+Minute 12, move down:
+#.######
+#&gt;&gt;.&lt;^&lt;#
+#.&lt;<em>E</em>.&lt;&lt;#
+#&gt;v.&gt;&lt;&gt;#
+#&lt;^v^^&gt;#
+######.#
+
+Minute 13, move down:
+#.######
+#.&gt;3.&lt;.#
+#&lt;..&lt;&lt;.#
+#&gt;2<em>E</em>22.#
+#&gt;v..^&lt;#
+######.#
+
+Minute 14, move right:
+#.######
+#.2&gt;2..#
+#.^22^&lt;#
+#.&gt;2<em>E</em>^&gt;#
+#.&gt;..&lt;.#
+######.#
+
+Minute 15, move right:
+#.######
+#&lt;^&lt;22.#
+#.2&lt;.2.#
+#&gt;&lt;2&gt;<em>E</em>.#
+#..&gt;&lt;..#
+######.#
+
+Minute 16, move right:
+#.######
+#.&lt;..22#
+#&lt;&lt;.&lt;..#
+#&lt;2.&gt;&gt;<em>E</em>#
+#.^22^.#
+######.#
+
+Minute 17, move down:
+#.######
+#2.v.&lt;&gt;#
+#&lt;.&lt;..&lt;#
+#.^&gt;^22#
+#.2..2<em>E</em>#
+######.#
+
+Minute 18, move down:
+#.######
+#&gt;2.&lt;.&lt;#
+#.2v^2&lt;#
+#&gt;..&gt;2&gt;#
+#&lt;....&gt;#
+######<em>E</em>#
+</code></pre>
+<p><em>What is the fewest number of minutes required to avoid the blizzards and reach the goal?</em></p>
+</article>
+<p>Your puzzle answer was <code>288</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>As the expedition reaches the far side of the valley, one of the Elves looks especially dismayed:</p>
+<p>He <em>forgot his snacks</em> at the entrance to the valley!</p>
+<p>Since you're so good at dodging blizzards, the Elves humbly request that you go back for his snacks. From the same initial conditions, how quickly can you make it from the start to the goal, then back to the start, then back to the goal?</p>
+<p>In the above example, the first trip to the goal takes <code>18</code> minutes, the trip back to the start takes <code>23</code> minutes, and the trip back to the goal again takes <code>13</code> minutes, for a total time of <code><em>54</em></code> minutes.</p>
+<p><em>What is the fewest number of minutes required to reach the goal, go back to the start, then reach the goal again?</em></p>
+</article>
+<p>Your puzzle answer was <code>861</code>.</p><p class="day-success">Both parts of this puzzle are complete! They provide two gold stars: **</p>
+<p>At this point, you should <a href="/2022">return to your Advent calendar</a> and try another puzzle.</p>
+<p>If you still want to see it, you can <a href="24/input" target="_blank">get your puzzle input</a>.</p>
+<p>You can also <span class="share">[Share<span class="share-content">on
+  <a href="https://twitter.com/intent/tweet?text=I%27ve+completed+%22Blizzard+Basin%22+%2D+Day+24+%2D+Advent+of+Code+2022&amp;url=https%3A%2F%2Fadventofcode%2Ecom%2F2022%2Fday%2F24&amp;related=ericwastl&amp;hashtags=AdventOfCode" target="_blank">Twitter</a>
+  <a href="javascript:void(0);" onclick="var mastodon_instance=prompt('Mastodon Instance / Server Name?'); if(typeof mastodon_instance==='string' && mastodon_instance.length){this.href='https://'+mastodon_instance+'/share?text=I%27ve+completed+%22Blizzard+Basin%22+%2D+Day+24+%2D+Advent+of+Code+2022+%23AdventOfCode+https%3A%2F%2Fadventofcode%2Ecom%2F2022%2Fday%2F24'}else{return false;}" target="_blank">Mastodon</a
+></span>]</span> this puzzle.</p>
+</main>
+
+<!-- ga -->
+<script>
+(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+ga('create', 'UA-69522494-1', 'auto');
+ga('set', 'anonymizeIp', true);
+ga('send', 'pageview');
+</script>
+<!-- /ga -->
+</body>
+</html>
\ No newline at end of file