Skip to content

Commit 205d44d

Browse files
committed
Day 13: Point of Incidence
1 parent 6f39bb4 commit 205d44d

File tree

6 files changed

+85
-2
lines changed

6 files changed

+85
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ Development occurs in language-specific directories:
1717
|[Day10.hs](hs/src/Day10.hs)|[Day10.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day10.kt)|[day10.py](py/aoc2023/day10.py)|[day10.rs](rs/src/day10.rs)|
1818
|[Day11.hs](hs/src/Day11.hs)|[Day11.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day11.kt)|[day11.py](py/aoc2023/day11.py)|[day11.rs](rs/src/day11.rs)|
1919
|[Day12.hs](hs/src/Day12.hs)|[Day12.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day12.kt)|[day12.py](py/aoc2023/day12.py)|[day12.rs](rs/src/day12.rs)|
20+
|[Day13.hs](hs/src/Day13.hs)||||

hs/aoc2023.cabal

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ library
3232
Day9,
3333
Day10,
3434
Day11,
35-
Day12
35+
Day12,
36+
Day13
3637

3738
-- Modules included in this library but not exported.
3839
other-modules:
@@ -92,7 +93,8 @@ test-suite aoc2023-test
9293
Day9Spec,
9394
Day10Spec,
9495
Day11Spec,
95-
Day12Spec
96+
Day12Spec,
97+
Day13Spec
9698
build-depends:
9799
aoc2023,
98100
base ^>=4.17.2.0,

hs/app/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import qualified Day9 (part1, part2)
1313
import qualified Day10 (solve)
1414
import qualified Day11 (solve)
1515
import qualified Day12 (part1, part2)
16+
import qualified Day13 (part1, part2)
1617

1718
import Control.Monad (ap, when)
1819
import Data.Foldable (find)
@@ -55,3 +56,4 @@ main = do
5556
run 10 (maybe (fail "error") $ uncurry ((>>) `on` print)) [Day10.solve]
5657
run 11 print [Day11.solve 2, Day11.solve 1000000]
5758
run 12 print [Day12.part1, Day12.part2]
59+
run 13 print [Day13.part1, Day13.part2]

hs/bench/Main.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import qualified Day9 (part1, part2)
1818
import qualified Day10 (solve)
1919
import qualified Day11 (solve)
2020
import qualified Day12 (part1, part2)
21+
import qualified Day13 (part1, part2)
2122
import System.Environment.Blank (getEnv, setEnv, unsetEnv)
2223
import System.FilePath (combine)
2324

@@ -83,4 +84,8 @@ main = defaultMain
8384
[ bench "part 1" $ nf Day12.part1 input
8485
, bench "part 2" $ nf Day12.part2 input
8586
]
87+
, env (getDayInput 13) $ \input -> bgroup "Day 13"
88+
[ bench "part 1" $ nf Day13.part1 input
89+
, bench "part 2" $ nf Day13.part2 input
90+
]
8691
]

hs/src/Day13.hs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{-|
2+
Module: Day13
3+
Description: <https://adventofcode.com/2023/day/13 Day 13: Point of Incidence>
4+
-}
5+
{-# LANGUAGE OverloadedStrings #-}
6+
module Day13 (part1, part2) where
7+
8+
import Data.List (findIndex, inits, tails)
9+
import Data.Maybe (fromMaybe)
10+
import Data.Text (Text)
11+
import qualified Data.Text as T (commonPrefixes, drop, lines, splitOn, transpose)
12+
13+
findReflection :: ([a] -> [a] -> Bool) -> [a] -> Int
14+
findReflection _ [] = 0
15+
findReflection eq lines = maybe 0 succ . findIndex (uncurry $ eq . reverse) .
16+
drop 1 . init $ zip (inits lines) (tails lines)
17+
18+
part1 :: Text -> Int
19+
part1 = sum . map (part1' . T.lines) . T.splitOn "\n\n" where
20+
part1' lines = 100 * y + x where
21+
x = findReflection eq $ T.transpose lines
22+
y = findReflection eq lines
23+
xs `eq` ys = and $ zipWith (==) xs ys
24+
25+
part2 :: Text -> Int
26+
part2 = sum . map (part2' . T.lines) . T.splitOn "\n\n" where
27+
part2' lines = 100 * y + x where
28+
x = findReflection (almostEqual False) $ T.transpose lines
29+
y = findReflection (almostEqual False) lines
30+
almostEqual k [] _ = k
31+
almostEqual k _ [] = k
32+
almostEqual k (x:xs) (y:ys)
33+
| x == y = almostEqual k xs ys
34+
| (_, x', y') <- fromMaybe ("", x, y) $ T.commonPrefixes x y
35+
, T.drop 1 x' == T.drop 1 y'
36+
= not k && almostEqual True xs ys
37+
| otherwise = False

hs/test/Day13Spec.hs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Day13Spec (spec) where
3+
4+
import Data.Text (Text)
5+
import qualified Data.Text as T (unlines)
6+
import Day13 (part1, part2)
7+
import Test.Hspec (Spec, describe, it, shouldBe)
8+
9+
example :: Text
10+
example = T.unlines
11+
[ -- :r!wl-paste | sed 's/.*/ , "&"/;1s/,/ /'
12+
"#.##..##."
13+
, "..#.##.#."
14+
, "##......#"
15+
, "##......#"
16+
, "..#.##.#."
17+
, "..##..##."
18+
, "#.#.##.#."
19+
, ""
20+
, "#...##..#"
21+
, "#....#..#"
22+
, "..##..###"
23+
, "#####.##."
24+
, "#####.##."
25+
, "..##..###"
26+
, "#....#..#"
27+
]
28+
29+
spec :: Spec
30+
spec = do
31+
describe "part 1" $ do
32+
it "examples" $ do
33+
part1 example `shouldBe` 405
34+
describe "part 2" $ do
35+
it "examples" $ do
36+
part2 example `shouldBe` 400

0 commit comments

Comments
 (0)