From a002b1c07c7b69d1841dbe51a9922a71808275c3 Mon Sep 17 00:00:00 2001 From: cdimitroulas Date: Mon, 11 Dec 2023 22:42:51 +0000 Subject: [PATCH] Day11 part1 --- advent-of-code2023.cabal | 21 +++++- data/day11.txt | 140 ++++++++++++++++++++++++++++++++++++ package.yaml | 5 ++ src/Lib/AOC.hs | 6 +- src/Lib/List.hs | 7 +- src/Lib/Matrix.hs | 47 +++++++++--- src/Lib/SearchAlgorithms.hs | 83 +++++++++++++++++++++ src/Main.hs | 4 +- src/Solutions/Day03.hs | 22 +++--- src/Solutions/Day11.hs | 82 +++++++++++++++++++++ test/Day11.hs | 54 ++++++++++++++ 11 files changed, 445 insertions(+), 26 deletions(-) create mode 100644 data/day11.txt create mode 100644 src/Lib/SearchAlgorithms.hs create mode 100644 src/Solutions/Day11.hs create mode 100644 test/Day11.hs diff --git a/advent-of-code2023.cabal b/advent-of-code2023.cabal index d656530..24972f4 100644 --- a/advent-of-code2023.cabal +++ b/advent-of-code2023.cabal @@ -29,6 +29,7 @@ library Solutions.Day07 Solutions.Day08 Solutions.Day09 + Solutions.Day11 other-modules: Lib.AOC Lib.Common @@ -37,6 +38,7 @@ library Lib.Matrix Lib.Parsing Lib.Range + Lib.SearchAlgorithms Main Solutions.DayX Paths_advent_of_code2023 @@ -69,13 +71,17 @@ library TypeOperators ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints build-depends: - attoparsec + array + , attoparsec , base >=4.7 && <5 , clock , containers , formatting + , hashable + , heap , regex-tdfa , text + , unordered-containers , vector default-language: Haskell2010 @@ -89,6 +95,7 @@ executable advent-of-code2023 Lib.Matrix Lib.Parsing Lib.Range + Lib.SearchAlgorithms Solutions.Day01 Solutions.Day02 Solutions.Day03 @@ -98,6 +105,7 @@ executable advent-of-code2023 Solutions.Day07 Solutions.Day08 Solutions.Day09 + Solutions.Day11 Solutions.DayX Paths_advent_of_code2023 autogen-modules: @@ -129,13 +137,17 @@ executable advent-of-code2023 TypeOperators ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints build-depends: - attoparsec + array + , attoparsec , base >=4.7 && <5 , clock , containers , formatting + , hashable + , heap , regex-tdfa , text + , unordered-containers , vector default-language: Haskell2010 @@ -152,6 +164,7 @@ test-suite unit-test Day07 Day08 Day09 + Day11 Paths_advent_of_code2023 autogen-modules: Paths_advent_of_code2023 @@ -185,14 +198,18 @@ test-suite unit-test tasty-discover:tasty-discover build-depends: advent-of-code2023 + , array , attoparsec , base >=4.7 && <5 , clock , containers , formatting + , hashable + , heap , regex-tdfa , tasty , tasty-hunit , text + , unordered-containers , vector default-language: Haskell2010 diff --git a/data/day11.txt b/data/day11.txt new file mode 100644 index 0000000..16a603c --- /dev/null +++ b/data/day11.txt @@ -0,0 +1,140 @@ +.......#..............#.......................#............#.......#........................#.....#..................................#...... +.................................#.................................................#........................................................ +............................................................................................................................................ +..........................................................................................................#.............#................... +...........#...............................................................#..............................................................#. +.#.......................................................................................................................................... +................#.......#........................#....................#....................#.................................#.............. +......................................#.....#.........................................................#..................................... +...................................................................................#..........................#......................#...... +......#..................................................................................................................................... +.............#............................................#.......................................................#......................... +..................#.....................#..........#.....................................................#..............#.....#............. +.................................................................#.........#................................................................ +..................................#.................................................................................................#......# +....#..........#...........#..........................#.....#................................................#.............................. +................................................................................#........................................................... +.......................................#........#.......................#...........................#....................................... +.......................................................................................................................................#.... +.#..............................#.......................#........#.................#..............................#......................... +......#..............#....................#............................................................#.................#.................. +............#............................................................................................................................... +.....................................................................................................................#...................... +.....................................................#...................................................................................#.. +...............................................#...........................#.....#.......................................................... +....................................#........................................................................#.............................. +...........#.................#.........................................................#...........#............................#........... +.....#...............#....................................#...................................#........................................#.... +..........................................................................................................#................#................ +.......................................#..............#....................................................................................# +.................................#................................................#...................#.............#....................... +...#........#...............#.....................#............#.................................#.............#............................ +............................................................................................................................................ +.............................................#........................#..................................................................... +..........................................................#................................................#..............................#. +...................#...................#........................................#..............................................#............ +....#.....#.......................#...........................................................#.....#....................................... +........................................................................................#................................................... +..............................................#.........................................................#................................... +..........................#................................................#.............................................#..............#... +........#.....................................................#.......#..........................................................#.......... +.............#.............................#..........#..............................#.....................#................................ +............................................................................................................................................ +.#..............................................................................#.................#......................................... +......................#...............#..................................................................................................... +...................................................................#..................................................................#..... +..........#.................................................................................#......................#........................ +.................#........................#............................#.................................................................... +..........................................................#................................................#............#................... +..................................................#........................#...................................................#............ +..............................................................................................#..................#.......................... +............................................................................................................................................ +.....#...............................................................................................#...................................... +....................................#.......................................................................#........#...................... +...................#............................................................#..........#................................................ +.............................#..........................................................................................................#... +...............#...............................#..........#......................................#.....#.....................#.............. +.......#...............#.............................................................#............................................#......... +............................................................................................................................................ +...................................#.......#........#........#.................................................#............................ +............................................................................................................................................ +..........#..................#.........................................#..............................................................#..... +................................................#..........................................#................#....................#.......... +.........................................................#...........................#...................................................... +#....................#...........#.................................................................#..............#......#.................. +.............................................#.......#...................................................#.................................. +............................#...........................................................#.....#............................................. +.......#........................................................................#........................................................... +..........................................................#...................................................#....................#........ +...#...................................................................................................................#.................... +...............#.................#.......................................................................................................... +....................#.................#.......#..................#.........................#.............#.............................#.... +........................................................#...........................#....................................................... +...........................#...............................................#................................................................ +.#.......#........................................................................................#........................................# +................................#................................................................................#...............#.......... +....................................................#....................................................................................... +...................................................................#.....................................#...............#............#..... +....................................#......................#.............#..........#.....#................................................. +...........#................................................................................................................................ +.......................#.....................#.................................................................#............................ +.............................#..............................................#........................#...................................... +..................#................................................................................................#................#....... +..................................................#.........#..........#..................................................#................. +.................................#.......................................................#.................................................# +....#.......................................#.........#.......................................................................#............. +............................................................................................................................................ +............................................................................................................................................ +........................................................................#................................................................... +..#.............................................#................#....................................................#..................... +..............#...............#............................................................................................................. +........................#............................#..........................#........#.................................................. +...................................................................................................#...........#........................#... +....#.............#..............#............................................................................................#............. +............................................................................................................................................ +......................................................................................................#..................................... +.................................................................#......................#................................................... +.....................#....................#...........#.................#................................................................... +................................................................................#......................................#..........#........# +........#........................................................................................#.......................................... +..................................#.........................................................#....................#..........#............... +#...........................#...........................................................................#................................... +............#................................................#.........#...............#.................................................... +....#....................................................................................................................................... +..........................................#.....................................................#..............#..............#............. +............................................................................#.........................#.............#....................... +................................#.....#..................................................................................................... +...................#......#.................................#.......................#.......................#............................... +...........................................................................................#......#...............................#......... +#.............#.......................................#..................................................................................... +.............................#..............#.............................................................................................#. +......................#..................................................#............................#..............#...................... +........#........#.....................#...................#......#.............#............................#............#................. +.........................................................................................#......................................#........... +..................................#..................#............................................#...............#..................#...... +..........................#....................#............................................................................................ +..........................................#................................................................................................. +.#...................................................................#.......................#.............#...............................# +......#.......................#................................#.....................................................#...................... +............#.....#...................#............#.....#.......................#.................#........................................ +..........................................................................................................................#.....#......#.... +..........................................................................................#.............#................................... +...........................................#........................................#....................................................... +..#...................................................................#..................................................................... +.........#...........................................#...................................................................................... +....................................#............................................................#.................................#.......# +...........................#......................................................................................#......................... +..........................................................#............................................................#.................... +...#..........#........#.................................................................................................................... +....................................................................................#......#.................#..................#........... +..............................................................................#............................................................. +.............................#.......#.....#...................#........#......................#.....................................#...... +............................................................................................................................................ +..........#.....#...................................................#.............#.....................#....................#.............. +........................#.................................#.............................#...........................#....................... +........................................#...........#........................................#...........................................#.. +.....#.........................................#.................#.....#............................#....................................... +...................................#........................................#........#...................................................... +...........................................................................................................................#................ +.#............................#..........................#...................................................#.........................#.... +.........#...................................#..........................................#.........................#......................... diff --git a/package.yaml b/package.yaml index 00bb309..bbeba81 100644 --- a/package.yaml +++ b/package.yaml @@ -38,12 +38,16 @@ default-extensions: dependencies: - base >= 4.7 && < 5 + - array - attoparsec - clock - containers - formatting + - hashable + - heap - regex-tdfa - text + - unordered-containers - vector ghc-options: @@ -74,6 +78,7 @@ library: - Solutions.Day07 - Solutions.Day08 - Solutions.Day09 + - Solutions.Day11 tests: unit-test: diff --git a/src/Lib/AOC.hs b/src/Lib/AOC.hs index 8110355..0719f3e 100644 --- a/src/Lib/AOC.hs +++ b/src/Lib/AOC.hs @@ -22,13 +22,15 @@ runSolution day parser part1 part2 = do putStrLn "Part 1:" p1Start <- getTime Monotonic - print $ part1 input + putStr $ show $ part1 input + putStrLn "" p1End <- getTime Monotonic fprint (timeSpecs % "\n") p1Start p1End putStrLn "Part 2:" p2Start <- getTime Monotonic - print $ part2 input + putStr $ show $ part2 input + putStrLn "" p2End <- getTime Monotonic fprint (timeSpecs % "\n") p2Start p2End diff --git a/src/Lib/List.hs b/src/Lib/List.hs index 2a90b18..f0570e3 100644 --- a/src/Lib/List.hs +++ b/src/Lib/List.hs @@ -1,4 +1,4 @@ -module Lib.List (safeHead, setAt, (!?)) where +module Lib.List (safeHead, setAt, (!?), pairs) where safeHead :: [a] -> Maybe a safeHead [] = Nothing @@ -15,3 +15,8 @@ xs !? n setAt :: [a] -> Int -> a -> [a] setAt xs i x = take i xs ++ [x] ++ drop (i + 1) xs + +pairs :: Eq a => [a] -> [(a, a)] +pairs [] = [] +pairs [_] = error "Odd length list provided to pairs" +pairs (x1:x2:xs) = (x1, x2) : pairs xs diff --git a/src/Lib/Matrix.hs b/src/Lib/Matrix.hs index 8045983..1d0181c 100644 --- a/src/Lib/Matrix.hs +++ b/src/Lib/Matrix.hs @@ -1,21 +1,50 @@ -module Lib.Matrix (Matrix, (!), (!?), height, width) where +module Lib.Matrix (Matrix, (!), (!?), height, width, insertCol, insertRow, getRow, getCol, getCols, findColIndices, findRowIndices, Lib.Matrix.toList, findLocations) where -import Data.Vector (Vector) -import qualified Data.Vector as V +import Data.Foldable (toList) +import Data.List (findIndices) +import Data.Sequence (Seq) +import qualified Data.Sequence as S import Prelude hiding (elem) -type Matrix a = Vector (Vector a) +type Matrix a = Seq (Seq a) type Position = (Int, Int) -- x, y -(!) :: Position -> Matrix a -> a -(!) (x, y) mat = mat V.! y V.! x +(!) :: Matrix a -> Position -> a +mat ! (x, y) = mat `S.index` y `S.index` x (!?) :: Position -> Matrix a -> Maybe a -(!?) (x, y) mat = mat V.!? y >>= (V.!? x) +(!?) (x, y) mat = mat S.!? y >>= (S.!? x) height :: Matrix a -> Int -height = V.length +height = S.length width :: Matrix a -> Int -width = V.length . V.head +width = S.length . (`S.index` 0) + +insertCol :: Seq a -> Int -> Matrix a -> Matrix a +insertCol col colIdx = fmap (S.insertAt colIdx (col `S.index` colIdx)) + +insertRow :: Seq a -> Int -> Matrix a -> Matrix a +insertRow row rowIdx = S.insertAt rowIdx row + +getRow :: Int -> Matrix a -> Seq a +getRow = flip S.index + +getCol :: Int -> Matrix a -> Seq a +getCol colIdx = fmap (`S.index` colIdx) + +getCols :: Matrix a -> [Seq a] +getCols mat = [getCol colIdx mat | colIdx <- [0 .. width mat - 1]] + +findColIndices :: (Seq a -> Bool) -> Matrix a -> [Int] +findColIndices predicate mat = findIndices predicate (getCols mat) + +findRowIndices :: (Seq a -> Bool) -> Matrix a -> [Int] +findRowIndices = S.findIndicesL + +toList :: Matrix a -> [[a]] +toList mat = Data.Foldable.toList $ fmap Data.Foldable.toList mat + +findLocations :: (a -> Bool) -> Matrix a -> [(Int, Int)] +findLocations predicate mat = [(x, y) | y <- [0 .. height mat - 1], x <- [0 .. width mat - 1], predicate (mat ! (x, y))] diff --git a/src/Lib/SearchAlgorithms.hs b/src/Lib/SearchAlgorithms.hs new file mode 100644 index 0000000..d3250d7 --- /dev/null +++ b/src/Lib/SearchAlgorithms.hs @@ -0,0 +1,83 @@ +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE FlexibleContexts #-} + +module Lib.SearchAlgorithms (DijkstraGraph(..), Distance(..), findShortestDistance) where + +import Data.Heap (MinPrioHeap) +import qualified Data.Heap as H +import Data.HashMap.Strict (HashMap) +import qualified Data.HashMap.Strict as HM +import Data.Hashable (Hashable) +import Data.Maybe (fromMaybe) +import Data.HashSet (HashSet) +import qualified Data.HashSet as HS +import Data.Kind (Type) +import Data.Foldable (foldl') + +data Distance a = Dist a | Infinity + deriving (Show, Eq) + +instance (Ord a) => Ord (Distance a) where + Infinity <= Infinity = True + Infinity <= Dist _ = False + Dist _ <= Infinity = True + Dist x <= Dist y = x <= y + +addDist :: (Num a) => Distance a -> Distance a -> Distance a +addDist (Dist x) (Dist y) = Dist (x + y) +addDist _ _ = Infinity + +(!??) :: (Hashable k) => HashMap k (Distance d) -> k -> Distance d +(!??) distanceMap key = fromMaybe Infinity (HM.lookup key distanceMap) + +class DijkstraGraph graph where + type DijkstraNode graph :: Type + type DijkstraCost graph :: Type + dijkstraEdges :: graph -> DijkstraNode graph -> [(DijkstraNode graph, DijkstraCost graph)] + + +data DijkstraState node cost = DijkstraState + { visitedSet :: HashSet node + , distanceMap :: HashMap node (Distance cost) + , nodeQueue :: MinPrioHeap (Distance cost) node + } + +-- Taken from https://mmhaskell.com/blog/2022/8/22/dijkstras-algorithm-in-haskell +findShortestDistance :: + forall g. (Hashable (DijkstraNode g), Num (DijkstraCost g), Ord (DijkstraCost g), DijkstraGraph g) => g -> DijkstraNode g -> DijkstraNode g -> Distance (DijkstraCost g) +findShortestDistance graph src dest = processQueue initialState !?? dest + where + initialVisited = HS.empty + initialDistances = HM.singleton src (Dist 0) + initialQueue = H.fromList [(Dist 0, src)] + initialState = DijkstraState initialVisited initialDistances initialQueue + + processQueue :: DijkstraState (DijkstraNode g) (DijkstraCost g) -> HashMap (DijkstraNode g) (Distance (DijkstraCost g)) + processQueue ds@(DijkstraState v0 d0 q0 ) = case H.view q0 of + -- if there is nothing left in the queue, we have processed everything and we can just return the distances + Nothing -> d0 + Just ((_, node), q1) -> + -- if we have reached the destination node, we have processed everything + if node == dest + then d0 + -- if the node is already visited, then we can immediately recurse, except plugging in the updated queue + else if HS.member node v0 then processQueue ds{ nodeQueue = q1} + -- 1. Pull a new node from our heap and consider that node “visited” + -- 2. Get all the “neighbors” of this node + -- 3. Process each neighbor and update its distance + else + let v1 = HS.insert node v0 + allNeighbors = dijkstraEdges graph node + unvisitedNeighbors = filter (\(n, _) -> not (HS.member n v1)) allNeighbors + in processQueue $ foldl' (foldNeighbor node) ds{ visitedSet=v1, nodeQueue=q1 } unvisitedNeighbors + + -- Take the distance from the source to the current node and add it to the specific edge cost from the current to this new node. + -- Then compare this distance to the existing distance we have to the neighbor in our distance map (or Infinity if it doesn’t exist). + foldNeighbor currentNode ds@(DijkstraState _ d0 q0) (neighborNode, cost) = + let altDistance = addDist (d0 !?? currentNode) (Dist cost) + in if altDistance < d0 !?? neighborNode + -- If the alternative distance is smaller, we update the distance map by associating the neighbor node with the + -- alternative distance and return the new DijkstraState. We also insert the new distance into our queue. + then ds { distanceMap = HM.insert neighborNode altDistance d0, nodeQueue = H.insert (altDistance, neighborNode) q0 } + -- If the alternative distance is not better, we make no changes, and return the original state. + else ds diff --git a/src/Main.hs b/src/Main.hs index a58d57e..7ce573e 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -8,6 +8,7 @@ import Solutions.Day06 (day06) import Solutions.Day07 (day07) import Solutions.Day08 (day08) import Solutions.Day09 (day09) +import Solutions.Day11 (day11) main :: IO () main = do @@ -19,4 +20,5 @@ main = do -- day06 -- day07 -- day08 - day09 + -- day09 + day11 diff --git a/src/Solutions/Day03.hs b/src/Solutions/Day03.hs index 77d1e43..2357017 100644 --- a/src/Solutions/Day03.hs +++ b/src/Solutions/Day03.hs @@ -6,11 +6,13 @@ import Data.Char (digitToInt) import Data.Functor (($>)) import Data.Maybe (catMaybes, fromJust, fromMaybe) import qualified Data.Text as T -import Data.Vector (Vector) -import qualified Data.Vector as V +import Data.Sequence (Seq) +import qualified Data.Sequence as S import Lib.AOC (runSolution) import qualified Lib.Matrix as Matrix import Lib.Parsing (linesOf) +import Lib.Matrix (Matrix) +import Data.Foldable (toList) data SchematicItem = Number Int | Symbol Char deriving (Eq, Show) @@ -26,20 +28,18 @@ getNumberVal :: SchematicItem -> Int getNumberVal (Number x) = x getNumberVal _ = error "Tried to extract number from non-Number SchematicItem" -type Matrix a = Vector (Vector a) - type Input = Matrix (Maybe SchematicItem) day03 :: IO () day03 = runSolution "03" parser (fmap part1) (fmap part2) parser :: String -> Either String Input -parser = fmap (V.map combineNumbers) . P.parseOnly (V.fromList <$> linesOf (V.fromList <$> P.many1 schematicItemParser)) . T.pack +parser = fmap (fmap combineNumbers) . P.parseOnly (S.fromList <$> linesOf (S.fromList <$> P.many1 schematicItemParser)) . T.pack part1 :: Input -> Int part1 input = let partNumberPositions = getPartNumberPositions input - partNumbers = map getNumberVal $ catMaybes $ removeConseqDups $ map (Matrix.! input) partNumberPositions + partNumbers = map getNumberVal $ catMaybes $ removeConseqDups $ map (input Matrix.!) partNumberPositions in sum partNumbers schematicItemParser :: P.Parser (Maybe SchematicItem) @@ -49,8 +49,8 @@ schematicItemParser = <|> (Just . Symbol <$> P.notChar '\n') -- Combines the individual digits into larger numbers -combineNumbers :: Vector (Maybe SchematicItem) -> Vector (Maybe SchematicItem) -combineNumbers = V.fromList . combineNumbers' . V.toList +combineNumbers :: Seq (Maybe SchematicItem) -> Seq (Maybe SchematicItem) +combineNumbers = S.fromList . combineNumbers' . toList where isNumber' (Just x) = isNumber x isNumber' _ = False @@ -65,7 +65,7 @@ combineNumbers = V.fromList . combineNumbers' . V.toList getSymbolPositions :: Input -> [(Int, Int)] getSymbolPositions mat = do yPosition <- [0 .. Matrix.height mat - 1] - xPosition <- V.toList $ V.findIndices (fromMaybe False . (Just isSymbol <*>)) (mat V.! yPosition) + xPosition <- toList $ S.findIndicesL (fromMaybe False . (Just isSymbol <*>)) (mat `S.index` yPosition) return (xPosition, yPosition) getPartNumberPositions :: Input -> [(Int, Int)] @@ -96,10 +96,10 @@ part2 input = sum gearRatios potentialGearPositions = do yPosition <- [0 .. Matrix.height input - 1] - xPosition <- V.toList $ V.findIndices (== Just (Symbol '*')) (input V.! yPosition) + xPosition <- toList $ S.findIndicesL (== Just (Symbol '*')) (input `S.index` yPosition) return (xPosition, yPosition) - getGearAdjacentNums = map getNumberVal . filter isNumber . catMaybes . removeConseqDups . map (Matrix.! input) . neighborPositions + getGearAdjacentNums = map getNumberVal . filter isNumber . catMaybes . removeConseqDups . map (input Matrix.!) . neighborPositions isGear :: (Int, Int) -> Bool isGear gearPos = length (getGearAdjacentNums gearPos) == 2 diff --git a/src/Solutions/Day11.hs b/src/Solutions/Day11.hs new file mode 100644 index 0000000..21df8cc --- /dev/null +++ b/src/Solutions/Day11.hs @@ -0,0 +1,82 @@ +{-# LANGUAGE TypeFamilies #-} + +module Solutions.Day11 (day11, parser, part1, part2) where + +import Data.Array (Array) +import qualified Data.Array as A +import qualified Data.Sequence as S +import Lib.AOC (runSolution) +import Lib.SearchAlgorithms (DijkstraGraph(..), Distance(..), findShortestDistance) +import Lib.Matrix (Matrix) +import qualified Lib.Matrix as Mat +import Data.Foldable (foldl', toList) +import Debug.Trace +import Data.Sequence (Seq((:<|))) +import Data.Maybe (catMaybes) +import Lib.List (pairs) + +type Input = Matrix Char + +parser :: String -> Input +parser = S.fromList . map S.fromList . lines + +isSpace :: Char -> Bool +isSpace = (==) '.' + +-- Modifes the indexes to insert at to account for the fact that insert one index will change the position where +-- the next insertion needs to occur. +indicesToInsertAt :: [Int] -> [Int] +indicesToInsertAt [] = [] +indicesToInsertAt (x:xs) = x : indicesToInsertAt (map (+ 1) xs) + +expandUniverse :: Input -> Input +expandUniverse universe = + -- We need to use indicesToInsertAt because each time we add a row the indexes where we need to insert new rows will move down + -- by 1. Same logic applies to inserting columns. + let emptyRowIndices = indicesToInsertAt $ Mat.findRowIndices (all isSpace) universe + emptyRow = S.fromList $ replicate (Mat.width universe) '.' + universeWithRowsExpanded = foldl' (flip $ Mat.insertRow emptyRow) universe emptyRowIndices + emptyColIndices = indicesToInsertAt $ Mat.findColIndices (all isSpace) universeWithRowsExpanded + emptyCol = S.fromList $ replicate (Mat.height universeWithRowsExpanded) '.' + in foldl' (flip $ Mat.insertCol emptyCol) universeWithRowsExpanded emptyColIndices + +-- Just for debugging the state of the "universe" to see what it looks like after expansion +prettyPrint :: Input -> String +prettyPrint S.Empty = "" +prettyPrint (x :<| xs) = show (toList x) ++ "\n" ++ prettyPrint xs + +part1 :: Input -> Int +part1 input = distances galaxyLocations + where + expandedUniverse = expandUniverse input + galaxyLocations = Mat.findLocations (== '#') expandedUniverse + findDistance (x0, y0) (x1, y1) = abs (x1 - x0) + abs (y1 - y0) + + distances [] = 0 + distances (x:xs) = sum (map (findDistance x) xs) + distances xs + +newtype Graph2D = Graph2D (Array (Int, Int) Char) deriving (Show) + +-- matrixToGraph2D :: Input -> Graph2D +-- matrixToGraph2D mat = Graph2D $ A.listArray ((0, 0), (Mat.height mat - 1, Mat.width mat - 1)) $ concat $ Mat.toList mat + +-- instance DijkstraGraph Graph2D where +-- type DijkstraNode Graph2D = (Int, Int) +-- type DijkstraCost Graph2D = Int +-- -- the cost is always 1 for our graph +-- dijkstraEdges (Graph2D arr) node = [(neighbor, 1) | neighbor <- getNeighbors node arr] + +-- getNeighbors :: (Int, Int) -> Array (Int, Int) Char -> [(Int, Int)] +-- getNeighbors (x, y) arr = catMaybes [up, down, left, right] +-- where +-- (maxRow, maxCol) = snd $ A.bounds arr +-- up = if y - 1 < 0 then Nothing else Just (x, y - 1) +-- down = if y + 1 > maxRow then Nothing else Just (x, y + 1) +-- left = if x - 1 < 0 then Nothing else Just (x - 1, y) +-- right = if x + 1 > maxCol then Nothing else Just (x + 1, y) + +part2 :: Input -> String +part2 = show . const 0 + +day11 :: IO () +day11 = runSolution "11" parser part1 part2 diff --git a/test/Day11.hs b/test/Day11.hs new file mode 100644 index 0000000..ec13ae2 --- /dev/null +++ b/test/Day11.hs @@ -0,0 +1,54 @@ +{-# OPTIONS_GHC -Wno-missing-export-lists #-} + +module Day11 where + +import qualified Data.Sequence as S +import Solutions.Day11 (parser, part1, part2) +import Test.Tasty +import Test.Tasty.HUnit + +exampleInput :: String +exampleInput = "...#......\n\ + \.......#..\n\ + \#.........\n\ + \..........\n\ + \......#...\n\ + \.#........\n\ + \.........#\n\ + \..........\n\ + \.......#..\n\ + \#...#....." + +test_day11 :: TestTree +test_day11 = + testGroup + "Day11" + [ testCase "parser" $ do + parser exampleInput @?= + S.fromList [ + S.fromList ['.', '.', '.', '#', '.','.','.','.','.','.'] + , S.fromList ['.', '.', '.', '.', '.','.','.','#','.','.'] + , S.fromList ['#', '.', '.', '.', '.','.','.','.','.','.'] + , S.fromList ['.', '.', '.', '.', '.','.','.','.','.','.'] + , S.fromList ['.', '.', '.', '.', '.','.','#','.','.','.'] + , S.fromList ['.', '#', '.', '.', '.','.','.','.','.','.'] + , S.fromList ['.', '.', '.', '.', '.','.','.','.','.','#'] + , S.fromList ['.', '.', '.', '.', '.','.','.','.','.','.'] + , S.fromList ['.', '.', '.', '.', '.','.','.','#','.','.'] + , S.fromList ['#', '.', '.', '.', '#','.','.','.','.','.'] + ] + + , testCase "part 1 - example input" $ do + part1 (parser exampleInput) @?= 374 + + , testCase "part 1" $ do + input <- parser <$> readFile "data/day11.txt" + part1 input @?= 9445168 + + -- , testCase "part 2 - example input" $ do + -- part2 (parser exampleInput) @?= 2 + + -- , testCase "part 2" $ do + -- input <- parser <$> readFile "data/day11.txt" + -- part2 input @?= 957 + ]