From 79178aa9214234c6f7f31ec3091388c00c231751 Mon Sep 17 00:00:00 2001 From: Maciej Jur Date: Fri, 1 Dec 2023 23:03:57 +0100 Subject: [PATCH] haskell: 2023 01 --- 2023/haskell/aoc2023.cabal | 151 +++++++---------------- 2023/haskell/app/Main.hs | 7 +- 2023/haskell/solutions/Day01.hs | 53 ++++++++ 2023/haskell/{src => solutions}/Day02.hs | 0 2023/haskell/src/Day01.hs | 5 - 2023/haskell/test/Main.hs | 24 ---- 2023/haskell/tests/Main.hs | 29 +++++ 7 files changed, 133 insertions(+), 136 deletions(-) create mode 100644 2023/haskell/solutions/Day01.hs rename 2023/haskell/{src => solutions}/Day02.hs (100%) delete mode 100644 2023/haskell/src/Day01.hs delete mode 100644 2023/haskell/test/Main.hs create mode 100644 2023/haskell/tests/Main.hs diff --git a/2023/haskell/aoc2023.cabal b/2023/haskell/aoc2023.cabal index dbd2a27..65e8574 100644 --- a/2023/haskell/aoc2023.cabal +++ b/2023/haskell/aoc2023.cabal @@ -1,132 +1,77 @@ -cabal-version: 3.0 --- The cabal-version field refers to the version of the .cabal specification, --- and can be different from the cabal-install (the tool) version and the --- Cabal (the library) version you are using. As such, the Cabal (the library) --- version used must be equal or greater than the version stated in this field. --- Starting from the specification version 2.2, the cabal-version field must be --- the first thing in the cabal file. +cabal-version: 3.0 --- Initial package description 'aoc2023' generated by --- 'cabal init'. For further documentation, see: --- http://haskell.org/cabal/users-guide/ --- --- The name of the package. -name: aoc2023 +name: aoc2023 +version: 0.0.0.1 +synopsis: Solutions to Advent of Code 2023 +license: MIT +author: Maciej Jur +maintainer: maciej@kamoshi.org +build-type: Simple --- The package version. --- See the Haskell package versioning policy (PVP) for standards --- guiding when and how versions should be incremented. --- https://pvp.haskell.org --- PVP summary: +-+------- breaking API changes --- | | +----- non-breaking API additions --- | | | +--- code changes with no API change -version: 0.0.0.1 - --- A short (one-line) description of the package. --- synopsis: - --- A longer description of the package. --- description: - --- The license under which the package is released. -license: MIT - --- The file containing the license text. -license-file: LICENSE - --- The package author(s). -author: Maciej Jur - --- An email address to which users can send suggestions, bug reports, and patches. -maintainer: maciej@kamoshi.org - --- A copyright notice. --- copyright: -build-type: Simple - --- Extra doc files to be distributed with the package, such as a CHANGELOG or a README. -extra-doc-files: CHANGELOG.md - --- Extra source files to be distributed with the package, such as examples, or a tutorial module. --- extra-source-files: common warnings - ghc-options: -Wall + ghc-options: -Wall library - -- Import common warning flags. - import: warnings + import: warnings - -- Modules exported by the library. - exposed-modules: - Day01 - Day02 + hs-source-dirs: solutions - -- Modules included in this library but not exported. - -- other-modules: + exposed-modules: + Day01 + Day02 - -- LANGUAGE extensions used by modules in this package. - -- other-extensions: + -- Modules included in this library but not exported. + -- other-modules: - -- Other library packages from which modules are imported. - build-depends: base ^>=4.17.2.0 + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: - -- Directories containing source files. - hs-source-dirs: src + build-depends: + base ^>=4.17.2.0, + text ^>=2.1 - -- Base language which the package is written in. - default-language: Haskell2010 + default-language: Haskell2010 executable aoc2023 - -- Import common warning flags. - import: warnings + import: warnings - -- .hs or .lhs file containing the Main module. - main-is: Main.hs + main-is: Main.hs - -- Modules included in this executable, other than Main. - other-modules: - Utils + other-modules: + Utils - -- LANGUAGE extensions used by modules in this package. - -- other-extensions: + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: - -- Other library packages from which modules are imported. - build-depends: - base ^>=4.17.2.0, - text ^>=2.1, - aoc2023 + build-depends: + base ^>=4.17.2.0, + text ^>=2.1, + aoc2023 - -- Directories containing source files. - hs-source-dirs: app + hs-source-dirs: app - -- Base language which the package is written in. - default-language: Haskell2010 + default-language: Haskell2010 test-suite aoc2023-test - -- Import common warning flags. - import: warnings + import: warnings - -- Base language which the package is written in. - default-language: Haskell2010 + -- Modules included in this executable, other than Main. + -- other-modules: - -- Modules included in this executable, other than Main. - -- other-modules: + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: - -- LANGUAGE extensions used by modules in this package. - -- other-extensions: + -- The interface type and version of the test suite. + type: exitcode-stdio-1.0 - -- The interface type and version of the test suite. - type: exitcode-stdio-1.0 + hs-source-dirs: tests - -- Directories containing source files. - hs-source-dirs: test + main-is: Main.hs - -- The entrypoint to the test suite. - main-is: Main.hs + build-depends: + base ^>=4.17.2.0, + HUnit ^>=1.6, + aoc2023 - -- Test dependencies. - build-depends: - base ^>=4.17.2.0, - HUnit ^>=1.6, - aoc2023 + default-language: Haskell2010 diff --git a/2023/haskell/app/Main.hs b/2023/haskell/app/Main.hs index 539c72d..63dfea8 100644 --- a/2023/haskell/app/Main.hs +++ b/2023/haskell/app/Main.hs @@ -1,12 +1,11 @@ module Main where -import qualified Data.Text as T import Utils (readInput) - import qualified Day01 -import qualified Day02 + main :: IO () main = do text <- readInput 1 - putStrLn $ T.unpack text + print . Day01.solveA . Day01.parse $ text + print . Day01.solveB . Day01.parse $ text diff --git a/2023/haskell/solutions/Day01.hs b/2023/haskell/solutions/Day01.hs new file mode 100644 index 0000000..294350a --- /dev/null +++ b/2023/haskell/solutions/Day01.hs @@ -0,0 +1,53 @@ +{-# LANGUAGE OverloadedStrings #-} +module Day01 (parse, solveA, solveB) where + +import qualified Data.Text as T +import Data.Text (Text) +import Data.Char (isDigit) +import Data.Maybe (mapMaybe, listToMaybe) + + +parse :: Text -> [Text] +parse = T.lines + +merge :: [Int] -> Int +merge xs = 10 * head xs + last xs + +solveA :: [Text] -> Int +solveA = sum . map (merge . convert) + where + convert :: Text -> [Int] + convert = map (read . pure) . T.unpack . T.filter isDigit + +replaces :: [(Text, Int)] +replaces = + [ ("one", 1) + , ("two", 2) + , ("three", 3) + , ("four", 4) + , ("five", 5) + , ("six", 6) + , ("seven", 7) + , ("eight", 8) + , ("nine", 9) + ] + +solveB :: [Text] -> Int +solveB = sum . map (merge . convert) + where + -- If `text` starts with `prefix` return `Just n`, otherwise return `Nothing` + tryReplace :: Text -> (Text, Int) -> Maybe Int + tryReplace text (prefix, n) + | prefix `T.isPrefixOf` text = Just n + | otherwise = Nothing + + -- If `firstChar` is a digit return it, otherwise try replace the prefix + parsePrefix :: Text -> Maybe Int + parsePrefix text + | isDigit firstChar = Just . read . pure $ firstChar + | otherwise = listToMaybe $ mapMaybe (tryReplace text) replaces + where + firstChar = T.head text + + convert :: Text -> [Int] + convert = mapMaybe parsePrefix . filter (not . T.null) . T.tails diff --git a/2023/haskell/src/Day02.hs b/2023/haskell/solutions/Day02.hs similarity index 100% rename from 2023/haskell/src/Day02.hs rename to 2023/haskell/solutions/Day02.hs diff --git a/2023/haskell/src/Day01.hs b/2023/haskell/src/Day01.hs deleted file mode 100644 index 6beb0c4..0000000 --- a/2023/haskell/src/Day01.hs +++ /dev/null @@ -1,5 +0,0 @@ -module Day01 (someFunc) where - -someFunc :: IO () -someFunc = putStrLn "someFunc22" - diff --git a/2023/haskell/test/Main.hs b/2023/haskell/test/Main.hs deleted file mode 100644 index 140ca35..0000000 --- a/2023/haskell/test/Main.hs +++ /dev/null @@ -1,24 +0,0 @@ -module Main (main) where - -import Test.HUnit -import qualified System.Exit as Exit -import qualified Day02 - - -day01 :: Test -day01 = TestCase $ assertEqual "should return 1" 1 (Day02.xyz 0) - -day02 :: Test -day02 = TestCase $ assertEqual "should return 0" 0 (Day02.xyz 0) - -tests :: Test -tests = TestList - [ TestLabel "day 1" day01 - , TestLabel "assda" day02 - ] - -main :: IO () -main = do - result <- runTestTT tests - if failures result > 0 then Exit.exitFailure else Exit.exitSuccess - diff --git a/2023/haskell/tests/Main.hs b/2023/haskell/tests/Main.hs new file mode 100644 index 0000000..76d221c --- /dev/null +++ b/2023/haskell/tests/Main.hs @@ -0,0 +1,29 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main (main) where + +import Test.HUnit +import qualified System.Exit as Exit +import qualified Day01 + + +day01 :: Test +day01 = TestList + [ TestCase $ assertEqual "should return 142" 142 (Day01.solveA inputA) + , TestCase $ assertEqual "should return 281" 281 (Day01.solveB inputB) + ] + where + inputA = ["1abc2", "pqr3stu8vwx", "a1b2c3d4e5f", "treb7uchet"] + inputB = ["two1nine", "eightwothree", "abcone2threexyz", "xtwone3four", "4nineeightseven2", "zoneight234", "7pqrstsixteen"] + + +tests :: Test +tests = TestList + [ TestLabel "day01" day01 + ] + +main :: IO () +main = isFailed . failures =<< runTestTT tests + where + isFailed count + | count > 0 = Exit.exitFailure + | otherwise = Exit.exitSuccess