From f5c4473280d173f54f927c7c9a6ae3119bdf8b92 Mon Sep 17 00:00:00 2001 From: JasterV <49537445+JasterV@users.noreply.github.com> Date: Tue, 25 Mar 2025 02:12:09 +0100 Subject: [PATCH] feat: day4 part one --- aoc2024.cabal | 3 +++ src/Day4.hs | 23 +++++++++++++++++++++++ src/Day4/Matrix.hs | 42 ++++++++++++++++++++++++++++++++++++++++++ test/Day4Spec.hs | 26 ++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 src/Day4.hs create mode 100644 src/Day4/Matrix.hs create mode 100644 test/Day4Spec.hs diff --git a/aoc2024.cabal b/aoc2024.cabal index 23b4720..1dec92a 100644 --- a/aoc2024.cabal +++ b/aoc2024.cabal @@ -28,6 +28,8 @@ library Day1 Day2 Day3 + Day4 + Day4.Matrix Day5 other-modules: Paths_aoc2024 @@ -50,6 +52,7 @@ test-suite aoc2024-test Day1Spec Day2Spec Day3Spec + Day4Spec Day5Spec Paths_aoc2024 autogen-modules: diff --git a/src/Day4.hs b/src/Day4.hs new file mode 100644 index 0000000..f3edc12 --- /dev/null +++ b/src/Day4.hs @@ -0,0 +1,23 @@ +module Day4 (partOne, partTwo) where + +import Data.List (transpose) +import qualified Day4.Matrix as M + +partOne :: String -> Int +partOne input = + let horizontalLines = lines input + verticalLines = transpose horizontalLines + matrix = M.buildMatrix horizontalLines + positiveDiagonals = M.groupWith (uncurry (+)) matrix + negativeDiagonals = M.groupWith (uncurry (-)) matrix + allLines = horizontalLines ++ verticalLines ++ positiveDiagonals ++ negativeDiagonals + in sum $ map countXMAS allLines + where + countXMAS :: String -> Int + countXMAS ('X' : xs@('M' : 'A' : 'S' : _)) = 1 + countXMAS xs + countXMAS ('S' : xs@('A' : 'M' : 'X' : _)) = 1 + countXMAS xs + countXMAS (_ : xs) = countXMAS xs + countXMAS [] = 0 + +partTwo :: String -> Int +partTwo _input = 0 diff --git a/src/Day4/Matrix.hs b/src/Day4/Matrix.hs new file mode 100644 index 0000000..21dfe35 --- /dev/null +++ b/src/Day4/Matrix.hs @@ -0,0 +1,42 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Day4.Matrix (Matrix, buildMatrix, groupWith) where + +import Data.IntMap.Lazy (IntMap) +import qualified Data.IntMap.Lazy as IntMap + +type AssocList k v = [(k, v)] + +newtype Matrix v = Matrix (AssocList (Int, Int) v) + +buildMatrix :: [[a]] -> Matrix a +buildMatrix xs = Matrix (go xs 0 []) + where + go [] _ acc = acc + go (x : xs') row acc = + let acc' = parseRow x (row, 0) acc + in go xs' (row + 1) acc' + + parseRow [] _ acc = acc + parseRow (x : xs') (row, column) acc = + let acc' = ((row, column), x) : acc + in parseRow xs' (row, column + 1) acc' + +{-- +Given a matrix of elements and a function mapping a position into an aggregation of its values, +group the elements by the aggregation result +--} +groupWith :: forall v. ((Int, Int) -> Int) -> Matrix v -> [[v]] +groupWith f (Matrix matrix) = + let intMap :: IntMap [v] + intMap = foldr (\(position, value) -> insertValue (f position) value) IntMap.empty matrix + in IntMap.elems intMap + where + insertValue key value = + IntMap.alter + ( \case + Nothing -> Just [value] + Just xs -> Just (value : xs) + ) + key diff --git a/test/Day4Spec.hs b/test/Day4Spec.hs new file mode 100644 index 0000000..eea4af0 --- /dev/null +++ b/test/Day4Spec.hs @@ -0,0 +1,26 @@ +module Day4Spec (spec) where + +import Day4 (partOne, partTwo) +import Test.Hspec + +spec :: Spec +spec = do + describe "PartOne" $ do + it "works" $ do + partOne input `shouldBe` 18 + + describe "PartTwo" $ do + it "works" $ do + partTwo input `shouldBe` 9 + where + input = + "MMMSXXMASM\n\ + \MSAMXMSMSA\n\ + \AMXSXMAAMM\n\ + \MSAMASMSMX\n\ + \XMASAMXAMM\n\ + \XXAMMXXAMA\n\ + \SMSMSASXSS\n\ + \SAXAMASAAA\n\ + \MAMMMXMMMM\n\ + \MXMXAXMASX"