Skip to content

Commit 7d11a4c

Browse files
committed
Day 1: Trebuchet?!
1 parent 894a0c1 commit 7d11a4c

File tree

11 files changed

+262
-0
lines changed

11 files changed

+262
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/day*.txt

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# [Advent of Code 2023](https://adventofcode.com/2023)
22
### my answers
3+
4+
Development occurs in language-specific directories:
5+
6+
|[Haskell](hs)|
7+
|--:|
8+
|[Day1.hs](hs/src/Day1.hs)|

hs/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
day*.txt
2+
cabal.project.local
3+
dist-*
4+
.ghci
5+
.ghcid
6+
*~

hs/LICENSE

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Copyright (c) 2023, Daniel Lin
2+
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Daniel Lin nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

hs/README.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# [Advent of Code 2023](https://adventofcode.com/2023)
2+
### my answers in [Haskell](https://www.haskell.org/)
3+
4+
This project builds with [The Haskell Cabal](https://www.haskell.org/cabal/).
5+
6+
Setup:
7+
8+
```sh
9+
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
10+
ghcup install cabal latest
11+
ghcup install ghc 9.4.7
12+
cabal configure --with-compiler ghc-9.4 --enable-tests
13+
```
14+
15+
Run the [Hspec](https://hspec.github.io/) test suite:
16+
17+
```sh
18+
cabal test test:aoc2023-test
19+
```
20+
21+
Run [criterion](http://www.serpentine.com/criterion/) benchmarks ([results online](https://ephemient.github.io/aoc2023/aoc2023-bench.html)):
22+
23+
```sh
24+
cabal bench bench:aoc2023-bench
25+
```
26+
27+
Print solutions for the inputs provided in local data files:
28+
29+
```sh
30+
cabal run exe:aoc2023
31+
```
32+
33+
Generate [Haddock](https://www.haskell.org/haddock/) API documentation:
34+
35+
```sh
36+
cabal haddock lib:aoc2023
37+
```
38+
39+
Run [hlint](https://github.com/ndmitchell/hlint) source code suggestions:
40+
41+
```sh
42+
cabal install hlint
43+
hlint src test bench
44+
```

hs/aoc2023.cabal

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
cabal-version: 2.4
2+
name: aoc2023
3+
version: 0.1.0.0
4+
synopsis: Advent of Code 2023 - my solutions in Haskell
5+
6+
-- A longer description of the package.
7+
description: Please see the README on GitHub at <https://github.com/ephemient/aoc2023/blob/main/hs/README.md>
8+
homepage: https://github.com/ephemient/aoc2023/tree/main/hs
9+
10+
-- A URL where users can report bugs.
11+
bug-reports: https://github.com/ephemient/aoc2023/issues
12+
license: BSD-3-Clause
13+
license-file: LICENSE
14+
author: Daniel Lin
15+
maintainer: [email protected]
16+
17+
-- A copyright notice.
18+
copyright: (c) 2023 Daniel Lin
19+
-- category:
20+
extra-source-files: README.md
21+
22+
library
23+
exposed-modules:
24+
Day1
25+
26+
-- Modules included in this library but not exported.
27+
-- other-modules:
28+
29+
-- LANGUAGE extensions used by modules in this package.
30+
-- other-extensions:
31+
build-depends:
32+
base ^>=4.17.2.0,
33+
text ^>=2.0.1
34+
hs-source-dirs: src
35+
default-language: GHC2021
36+
37+
executable aoc2023
38+
main-is: Main.hs
39+
40+
-- Modules included in this executable, other than Main.
41+
-- other-modules:
42+
43+
-- LANGUAGE extensions used by modules in this package.
44+
-- other-extensions:
45+
build-depends:
46+
aoc2023,
47+
base ^>=4.17.2.0,
48+
filepath ^>=1.4.2.2,
49+
text ^>=2.0.1
50+
ghc-options: -threaded -rtsopts "-with-rtsopts=-N"
51+
52+
hs-source-dirs: app
53+
default-language: GHC2021
54+
55+
test-suite aoc2023-test
56+
default-language: GHC2021
57+
type: exitcode-stdio-1.0
58+
59+
-- Directories containing source files.
60+
hs-source-dirs: test
61+
main-is: Main.hs
62+
other-modules:
63+
Day1Spec
64+
build-depends:
65+
aoc2023,
66+
base ^>=4.17.2.0,
67+
hspec ^>= 2.11.7,
68+
text ^>=2.0.1
69+
build-tool-depends:
70+
hspec-discover:hspec-discover ^>=2.11.7
71+
ghc-options: -threaded -rtsopts "-with-rtsopts=-N"

hs/app/Main.hs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{-# LANGUAGE NondecreasingIndentation #-}
2+
module Main (main) where
3+
4+
import qualified Day1 (part1, part2)
5+
6+
import Control.Monad (ap, when)
7+
import Data.Foldable (find)
8+
import Data.Maybe (fromMaybe)
9+
import Data.Text (Text)
10+
import qualified Data.Text.IO as TIO (putStrLn, readFile)
11+
import System.Environment (getArgs, lookupEnv)
12+
import System.FilePath (combine)
13+
14+
getDayInput :: Int -> IO Text
15+
getDayInput i = do
16+
dataDir <- fromMaybe "." . find (not . null) <$> lookupEnv "AOC2023_DATADIR"
17+
TIO.readFile . combine dataDir $ "day" ++ show i ++ ".txt"
18+
19+
run :: Int -> (a -> IO ()) -> [Text -> a] -> IO ()
20+
run = run' `ap` show
21+
22+
run' :: Int -> String -> (a -> IO ()) -> [Text -> a] -> IO ()
23+
run' day name showIO funcs = do
24+
args <- getArgs
25+
when (null args || name `elem` args) $ do
26+
putStrLn $ "Day " ++ name
27+
contents <- getDayInput day
28+
mapM_ (showIO . ($ contents)) funcs
29+
putStrLn ""
30+
31+
main :: IO ()
32+
main = do
33+
run 1 print [Day1.part1, Day1.part2]

hs/cabal.project

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
packages: .
2+
with-compiler: ghc-9.4

hs/src/Day1.hs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{-|
2+
Module: Day1
3+
Description: <https://adventofcode.com/2023/day/1 Day 1: Trebuchet?! >
4+
-}
5+
{-# LANGUAGE OverloadedStrings #-}
6+
module Day1 (part1, part2) where
7+
8+
import Data.Maybe (fromMaybe, listToMaybe)
9+
import Data.Text (Text)
10+
import qualified Data.Text as T (inits, isPrefixOf, isSuffixOf, lines, pack, tails)
11+
12+
part1, part2 :: Text -> Int
13+
part1 = solve digits
14+
part2 = solve extendedDigits
15+
16+
solve :: [(Int, Text)] -> Text -> Int
17+
solve values = sum . map solve' . T.lines where
18+
solve' line = fromMaybe 0 . listToMaybe $ do
19+
x <- [i | s <- T.tails line, (i, t) <- values, t `T.isPrefixOf` s]
20+
y <- [j | s <- reverse $ T.inits line, (j, t) <- values, t `T.isSuffixOf` s]
21+
pure $ 10 * x + y
22+
23+
digits, extendedDigits :: [(Int, Text)]
24+
digits = [(d, T.pack $ show d) | d <- [0..9]]
25+
extendedDigits = digits ++
26+
[ (1, "one")
27+
, (2, "two")
28+
, (3, "three")
29+
, (4, "four")
30+
, (5, "five")
31+
, (6, "six")
32+
, (7, "seven")
33+
, (8, "eight")
34+
, (9, "nine")
35+
]

hs/test/Day1Spec.hs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Day1Spec (spec) where
3+
4+
import Data.Text (Text)
5+
import qualified Data.Text as T (unlines)
6+
import Day1 (part1, part2)
7+
import Test.Hspec (Spec, describe, it, shouldBe)
8+
9+
example1, example2 :: Text
10+
example1 = T.unlines
11+
[ "1abc2"
12+
, "pqr3stu8vwx"
13+
, "a1b2c3d4e5f"
14+
, "treb7uchet"
15+
]
16+
example2 = T.unlines
17+
[ "two1nine"
18+
, "eightwothree"
19+
, "abcone2threexyz"
20+
, "xtwone3four"
21+
, "4nineeightseven2"
22+
, "zoneight234"
23+
, "7pqrstsixteen"
24+
]
25+
26+
spec :: Spec
27+
spec = do
28+
describe "part 1" $ do
29+
it "examples" $ do
30+
part1 example1 `shouldBe` 142
31+
describe "part 2" $ do
32+
it "examples" $ do
33+
part2 example2 `shouldBe` 281

hs/test/Main.hs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

0 commit comments

Comments
 (0)