From b703638344c9b8377106f433b0ec25712b6f50a3 Mon Sep 17 00:00:00 2001 From: Alexander Kobjolke Date: Sat, 7 Dec 2024 21:34:29 +0100 Subject: [PATCH] WIP: Solve 2024-06 --- aoc.cabal | 2 +- data/Y2024/D06/example | 10 ++ data/Y2024/D06/riddle | 130 ++++++++++++++++++++++++ flake.lock | 72 ++++---------- flake.nix | 6 +- src/AoC/Util.hs | 21 +++- src/AoC/Y2024/D06.hs | 175 ++++++++++++++++++++++++++++++++- test/spec/AoCSpec/Y2024Spec.hs | 4 + 8 files changed, 361 insertions(+), 59 deletions(-) create mode 100644 data/Y2024/D06/example diff --git a/aoc.cabal b/aoc.cabal index fad11b5..2cb21f6 100644 --- a/aoc.cabal +++ b/aoc.cabal @@ -1,6 +1,6 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.35.2. +-- This file has been generated from package.yaml by hpack version 0.36.1. -- -- see: https://github.com/sol/hpack diff --git a/data/Y2024/D06/example b/data/Y2024/D06/example new file mode 100644 index 0000000..a4eb402 --- /dev/null +++ b/data/Y2024/D06/example @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... diff --git a/data/Y2024/D06/riddle b/data/Y2024/D06/riddle index e69de29..fed9be4 100644 --- a/data/Y2024/D06/riddle +++ b/data/Y2024/D06/riddle @@ -0,0 +1,130 @@ +.......................#....#....................#....#..##.##.........................................#...........#...........#.. +.............#........................................#....................#............#.......................#............#.... +.........#.............#..#....#..........................#.......#.#.......#...............................................##.... +..........#....#....................................................#....................#...........#....#....................... +.............#...#....................#...........#.........#...........................#............#............................ +..........................................................................................#.....#.......#...................##.... +...............................................#.#......#..............#...#...................##...........#....#..#...#......... +..#.................#......#........#......................#.......#...............................#.............................. +.........................#...............#.....................................#....#..#..#............................#.......... +......................#.................................................................#..........#..............#...#......#.... +............................#.....##..........#.....................#..........#..#.......#....................................... +......#...###...........#.................................................................#....................................... +......................#.#..#................#..........#................#...........#............#..............#...#.........#... +....#.........................#..#...............................................#....#.............#............................. +..#............#...#............#..........#...............#.....#....##.........................#........#....................... +..................#............#..............#..........................................................#..#..#........#......... +.......#...#............#..........................................................#..............................#.............#. +..#................#....................#.#...#.................................#.........#....................#.........#........ +...................................#..#..........................#........#.....#.........................................#....... +...........##.................##............#................#...#..................................##...#........................ +..............#..................#....................................................................#........................... +.#...#....#..........##..................................#.............................................................#......#... +......#.....#................................#...............................................................#......#............. +..........#.............................................#............................##....#.........................#............ +..........#......#.................#...#........#...........#.#..........#........#....................................#.......... +.#..................#.#............................#.......................#.........#.......#.................................... +.....................#....#..................#..................................................##..#................#............ +......#......................#..#..............##.......#..................................................#..............#....... +..........................................................................#........#...#..............#.................#......... +....................##....#.......................#........#...................#.............##.......#........................... +.........#............#..................................................................................#........................ +........................................................................#................#........................#.............#. +............#.......#.................................#............#.............................................................. +.#.............#...............................................#....#.........#....#..................................#.#......... +.......................................#.....................................................................................#.... +........#........................................#...............#........................................................#....... +...............................#.........#........#...........#.......................................................#.........#. +.....................##...#....................................................#............#..................#..#..........##... +................#..........#...#............................................................#...##................................ +...................#........#...............................#.................#.........#......................................... +.................................................................................................................#................ +............................#......................................................#.....................................#......#. +......#................#............................#............................................................................. +..#...........#.....#.........#....#................#............................................#................................ +..................................#.......#.......#...........#.........#................#.....................................#.# +...............................................#............................................#.#.....................#.......##.... +..............................#...............#..............................#...#...#.............................#...........#.. +.......#...........#..........................................................#........#..#.........#.....#.....#...#............. +......................................................#.#............#.........#.#...........#........##.....#.................... +...........................................................................#..........#.........................#.........#....... +....#.........................#.....................................................................................#...#......#.. +...#.......#............................................................#...............................#....................##.#. +.................................#.....#................................................................#......................... +.....................................#........................#....................................#.............................. +..............#.......................................................................#.......#....................#..........#... +................................#..........................................#.................................#.....#.............. +...........#.......................................................#...............#.....................#..............#......#.. +..................................#..........................#.................................................................#.. +.............##......#....................................................#......#...............................................# +#.......#...................#..........#...................#.................#..................................................#. +.......#..........#.....##...........#.......................#............#..............................#.............#.......... +.............#...................##......................................................................................#........ +#.............................#...................................................................#............................... +.#...................................#....##..................................................................................#... +.................................#.#..................#..#..#..........................#.......#.................................. +..................#....#....#....................................................#....................................#........#.. +..........................................#...#.....#...........#.........#............#............#..........................#.. +...............................................................................#..............................................#... +.............................#......#....................#....#....................................................#.#.#.......... +................##......#........#........#...........#..........................#......................#..............#.......... +.....................#.....#..#.............................................................................................#..... +.......#..#...........#................................................................#.......................................... +#.......................................................................................................#...#..................... +.#..........................................................#.....................................................#............... +#.....#...#...............#..#......#........#..#...................#...................#.................#....................... +..#.................................................................................#.#......................#.................... +.......................#.............#..........#.......................#...................................#..................... +.................#......#......#...#.#.#.............................#.......................................................#.... +..#...........................................................................................................#................... +.................................#..................#.....#........#.........................................................#.... +.............#......................#...............................................#...#.............................#...#....#.. +.#............................#..........................#.#...........................#..........................#.#............. +.............................#.........#.................##............................#...................#...................... +.........#......#....#.........#..............................................................................................#..# +.....................#......#.................#..#..........................#..................#..............................#.#. +........................................................#......................#............#.......#......#...................... +........................................#....##.#........#......#..............................#..........#..........#.##......... +.............#.......#.......#......................#..........................................#.........#............#...#...#.#. +..................#........................................................#...............................#.....#.....#.......... +.........#.................#........#..............^..............#.................##......#...................................#. +....#...................#.#.................................#...#.................................................#............... +.................#.............................................#................#.....#......#.......#...................#........ +...............#...............................................................................#..#...............#............... +........................................##..........................................................................##............ +............................................#...................#........#...#...#....#.........#...................#............. +.....#...#...................#....................................#......#...........#...............#............................ +........................#..................#.....................#.................................................#......##...... +...#.................#....................#..................................#.#.........................#.......#................ +....................#............#..................................#...#......#....................#...............#............. +.....#...............#.......###........#............#......................#.......#....#........................................ +....................#........#...........#..................................#..#................#.............#................... +.....#..................#...................#.#..................................#.......#..#..................................... +..#..#.......#........................................#.................................................................#......... +.......#............#...#....#.......................#.#...................................#.........................#..#.#....... +..............#......................................................................................................#............ +............#....................#........................#.........#...#......................................................... +...................................#..............................#.........................................................#..... +......##...........#.#........................#.........................................................................#......... +..........................#.....................................................#..............................#..............#... +.........................#...#.....................#..#................#................................................#....#.... +...#.................................#...#.......#...............................................................#................ +..................................#....................................#...........................##..#.#.....................#.. +.#.............#.....#...............................................................#...............#...............#..#......... +.........#.............................#........................#.............#......................#........#............#...... +...................................#..#...#.....................................#................................................. +........................................##..........#..............................................#.....................#........ +......#...........................................#....#.....................#...................#..#.........#................... +.#....#.....#........##..................................#......#................................................#....#..##....... +..........#....................................................................##.........................#...........#........... +...........#.#......#.......#..................#............#...............................................#...#..............#.. +.................................................................#.......#.........#.....#........#....##....#..........#......... +.............................#......................................................#.....#...#...#....#...........#..........#.#. +.....................#........#.........................#......................................#................#...............#. +.........................................................................#...................................................#.... +..............#...#..#................#....................................#.......#....#.#...............#.........#............. +.......#......#.#............................................#.......#............................................................ +##......................................................#..#.................................##...................#..#...........# +...........#.#...#........#............#..............................#........................#.........................#..#..... +................................................##.........................................#.................#.................... +............................#....................................................#...#........................#.#......#........#. diff --git a/flake.lock b/flake.lock index 38bb947..82ec1cd 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { @@ -21,29 +21,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -60,11 +42,11 @@ ] }, "locked": { - "lastModified": 1660459072, - "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { @@ -75,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701290038, - "narHash": "sha256-mcbPGHxG9c7Og+SkKYTAtOJwDERGx5kvTVH0BH1PNXE=", + "lastModified": 1733601786, + "narHash": "sha256-FOrDlgoS2m3RMXLTX6+nEVwyWo92/aIti9Er4yWFwAw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "231ffe19425544deb8da37b1362b545ef90bcb40", + "rev": "df05b65b13fe802eac0f449108974c05456229ce", "type": "github" }, "original": { @@ -90,16 +72,16 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1685801374, - "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "lastModified": 1730741070, + "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } @@ -107,7 +89,6 @@ "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" @@ -115,11 +96,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1700922917, - "narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=", + "lastModified": 1733318908, + "narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78", + "rev": "6f4e2a2112050951a314d2733a994fbab94864c6", "type": "github" }, "original": { @@ -149,21 +130,6 @@ "repo": "default", "type": "github" } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8af83c9..de0977c 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ overlay = final: prev: { aoc = final.callCabal2nix "aoc" ./. { }; }; - haskellPackages = pkgs.haskell.packages.ghc942.extend overlay; + haskellPackages = pkgs.haskell.packages.ghc94.extend overlay; in { packages.default = haskellPackages.aoc; @@ -35,13 +35,13 @@ checks = { pre-commit-check = pre-commit-hooks.lib.${system}.run { src = ./.; - settings = { ormolu.defaultExtensions = [ "GHC2021" ]; }; tools.fourmolu = haskellPackages.fourmolu; hooks = { - nixfmt.enable = true; + nixfmt-rfc-style.enable = true; fourmolu.enable = true; hpack.enable = true; hlint.enable = true; + ormolu.defaultExtensions = [ "GHC2021" ]; doctest = { enable = false; name = "Run documentation tests"; diff --git a/src/AoC/Util.hs b/src/AoC/Util.hs index aa91a52..a699faa 100644 --- a/src/AoC/Util.hs +++ b/src/AoC/Util.hs @@ -1,5 +1,8 @@ -- | Internal module in order to facilitate testability. -module AoC.Util (solveRiddle, readFileUtf8) where +module AoC.Util (solveRiddle, readFileUtf8, module A, mkMatrix, Matrix) where + +import Data.Array (Array) +import Data.Array qualified as A readFileUtf8 :: (MonadIO m) => FilePath -> m Text readFileUtf8 = fmap (decodeUtf8With lenientDecode) . readFileBS @@ -9,3 +12,19 @@ solveRiddle file solver = do results <- solver <$> readFileUtf8 file forM_ (results `zip` [1 :: Int ..]) $ \(solution, part) -> putTextLn $ " solution to part-" <> show part <> ": " <> solution + +type Matrix a = Array (Int, Int) a + +mkMatrix :: [[a]] -> Matrix a +mkMatrix vss = + A.array + ((1, 1), (w, h)) + [ ((x, y), v) + | (y, vs) <- zip [1 ..] vss + , (x, v) <- zip [1 ..] vs + ] + where + w = case vss of + [] -> 0 + (vs : _) -> length vs + h = length vss diff --git a/src/AoC/Y2024/D06.hs b/src/AoC/Y2024/D06.hs index 92a5945..b3d954c 100644 --- a/src/AoC/Y2024/D06.hs +++ b/src/AoC/Y2024/D06.hs @@ -1,6 +1,179 @@ +{- HLINT ignore "Use bimapF" -} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE RecordWildCards #-} + module AoC.Y2024.D06 (solve) where import AoC.Riddle +import AoC.Util + +import Data.Array ((!), (//)) +import Data.Array qualified as A + +import Data.String (lines) +import Prelude hiding (lines) + +data Direction + = U + | R + | D + | L + deriving stock (Show, Eq, Enum) + +data Tile + = Free + | Obstruction + | Visited + | Guard Direction + deriving stock (Show, Eq) + +type Position = (Int, Int) + +directionToVector :: Direction -> Position +directionToVector = \case + U -> (0, -1) + R -> (1, 0) + D -> (0, 1) + L -> (-1, 0) + +parseTile :: Char -> Maybe Tile +parseTile = \case + '.' -> pure Free + '#' -> pure Obstruction + '^' -> pure $ Guard U + '>' -> pure $ Guard R + 'v' -> pure $ Guard D + '<' -> pure $ Guard L + _ -> Nothing + +data MapState where + MapState :: + { labMap :: Matrix Tile + , guardPosition :: Maybe (Position, Direction) + , candidatesForLoop :: [Position] + } -> + MapState + deriving stock (Show) + +parseMap :: Riddle -> Maybe (Matrix Tile) +parseMap riddle = do + let + vss :: [[Char]] + vss = lines . toString $ riddle + + vss' :: [Maybe [Tile]] + vss' = mapM parseTile <$> vss + + mkMatrix <$> sequence vss' + +newMapState :: Matrix Tile -> MapState +newMapState labMap = + MapState labMap (locateGuard labMap) [] + +locateGuard :: Matrix Tile -> Maybe (Position, Direction) +locateGuard = getFirst . foldMap checkGuard . A.assocs + where + checkGuard :: (Position, Tile) -> First (Position, Direction) + checkGuard (pos, Guard d) = pure (pos, d) + checkGuard _ = mempty + +parse :: Riddle -> Maybe MapState +parse riddle = newMapState <$> parseMap riddle + +movePosition :: Position -> Direction -> Position +movePosition (x, y) d = + let (dx, dy) = directionToVector d + in (x + dx, y + dy) + +getTile :: Matrix Tile -> Position -> Maybe Tile +getTile m pos = + guard (A.inRange (A.bounds m) pos) >> Just (m ! pos) + +turnRight :: Direction -> Direction +turnRight = \case + U -> R + R -> D + D -> L + L -> U + +moveGuard :: MapState -> MapState +moveGuard s@MapState{..} = case guardPosition of + Nothing -> s + Just (pos, d) -> + let + newPos = movePosition pos d + in + case getTile labMap newPos of + Just Obstruction -> do + let + newDirection = turnRight d + s + { labMap = labMap // [(pos, Guard newDirection)] + , guardPosition = Just (pos, newDirection) + } + Just Visited -> + let + s' = + s + { labMap = labMap // [(pos, Visited), (newPos, Guard d)] + , guardPosition = Just (newPos, d) + } + newPos' = movePosition newPos d + in + case getTile labMap newPos' of + Nothing -> s' + Just Obstruction -> s' + Just _ -> s'{candidatesForLoop = newPos' : s'.candidatesForLoop} + Just _ -> + s + { labMap = labMap // [(pos, Visited), (newPos, Guard d)] + , guardPosition = Just (newPos, d) + } + Nothing -> + s + { labMap = labMap // [(pos, Visited)] + , guardPosition = Nothing + } + +updateGuard :: Maybe (Position, Direction) -> MapState -> MapState +updateGuard Nothing s = + case s.guardPosition of + Nothing -> s + Just (pos, _) -> + s + { labMap = s.labMap // [(pos, Visited)] + , guardPosition = Nothing + } +updateGuard g@(Just (pos, dir)) s = + case s.guardPosition of + Nothing -> + s + { labMap = s.labMap // [(pos, Guard dir)] + , guardPosition = g + } + Just (pos', _) -> + s + { labMap = s.labMap // [(pos', Visited), (pos, Guard dir)] + , guardPosition = g + } + +guardLeftTheMap :: MapState -> Bool +guardLeftTheMap MapState{..} = isNothing guardPosition + +moveGuardUntilSheLeaves :: MapState -> Maybe MapState +moveGuardUntilSheLeaves = + viaNonEmpty head . dropWhile (not . guardLeftTheMap) . iterate moveGuard + +part1 :: Riddle -> Maybe Int +part1 riddle = do + MapState{..} <- parse riddle >>= moveGuardUntilSheLeaves + pure $ length $ filter (\(_, t) -> t == Visited) (A.assocs labMap) + +part2 :: Riddle -> Maybe Int +part2 riddle = do + MapState{..} <- parse riddle >>= moveGuardUntilSheLeaves + pure $ length candidatesForLoop solve :: (MonadIO m) => Text -> m (Either Text Solution) -solve _ = pure $ Left "not yet implemented" +solve riddle = pure $ Right [fromIntegral $ fromMaybe 0 (part1 riddle), fromIntegral $ fromMaybe 0 (part2 riddle)] diff --git a/test/spec/AoCSpec/Y2024Spec.hs b/test/spec/AoCSpec/Y2024Spec.hs index 2f8014e..8265402 100644 --- a/test/spec/AoCSpec/Y2024Spec.hs +++ b/test/spec/AoCSpec/Y2024Spec.hs @@ -24,3 +24,7 @@ spec = do describe "Day 5" do it "calculates correctly" do runAoC Y2024 D05 `shouldReturn` Right [5452, 4598] + + describe "Day 6" do + it "calculates correctly" do + runAoC Y2024 D05 `shouldReturn` Right [5453, 0]