-
Notifications
You must be signed in to change notification settings - Fork 0
Reflections 2025
2016 / 2018 / 2019 / 2020 / 2021 / 2022 / 2023 / 2024 / 2025
Top / Prompt / Code / Standalone
Another tradition of advent of code day 1 --- everything is just a scan!
Once we parse the input into a list of integers:
parseInp :: String -> [Int]
parseInp = read . map rephrase . lines
where
rephrase 'R' = ' '
rephrase 'L' = '-'
rephrase d = dThen we can do the cumulative sum and count the zero's. It actually becomes
even easier if we restrict ourselves to the integers modulo 100 using the
finite-typelits library and Finite n, using modulo :: Integer -> Finite n to cast:
part1 :: [Finite 100] -> Int
part1 = length . filter (== 0) . scanl' (+) 50Part 2 you can probably do using more modulo and division tricks but the
simplest way is probably just to explode all of the ranges and do the same
counts. We use mapAccumL to map a stateful function, where the state is our
current position and our output is the list of all the traveled numbers:
part2 :: [Int] -> Int
part2 = length . filter (== 0) . concat . snd . mapAccumL go 50
where
go curr bump
| bump > 0 = (curr + bump, [curr + 1 .. curr + bump])
| otherwise = (curr + bump, [curr + bump .. curr - 1])Because of lazy lists, this is constant space! :)
>> Day 01a
benchmarking...
time 167.3 μs (167.1 μs .. 167.8 μs)
1.000 R² (1.000 R² .. 1.000 R²)
mean 168.4 μs (167.9 μs .. 169.1 μs)
std dev 1.947 μs (1.349 μs .. 2.629 μs)
* parsing and formatting times excluded
>> Day 01b
benchmarking...
time 229.4 μs (228.9 μs .. 230.0 μs)
1.000 R² (1.000 R² .. 1.000 R²)
mean 229.2 μs (229.0 μs .. 229.7 μs)
std dev 1.075 μs (790.8 ns .. 1.538 μs)
* parsing and formatting times excluded
Top / Prompt / Code / Standalone
You can do this nicely using the IntSet type in the containers library,
with IS.fromRange :: (Int, Int) -> IntSet. Then you can just turn the ranges
IntSets and intersect them with the IntSet of all invalid IDs.
-- | repDigits 3 567 = 567567567
repDigits :: Int -> Int -> Int
repDigits n = read . concat . replicate n . show
-- | All duplicated IDs up to 1e11
rep2 :: IntSet
rep2 = IS.fromAscList . takeWhile (< 1e11) . map (repDigits 2) $ [1 ..]
part1 :: [(Int, Int)] -> Int
part1 = IS.foldl' (+) 0 . foldMap (IS.intersection rep2 . IS.fromRange)And you can union together rep2, rep3, etc. too:
repN :: IntSet
repN = flip foldMap [1..11] $ \n ->
IS.fromAscList . takeWhile (< 1e11) . map (repDigits n) $ [1 ..]
part2 :: [(Int, Int)] -> Int
part2 = IS.foldl' (+) 0 . foldMap (IS.intersection repN . IS.fromRange)>> Day 02a
benchmarking...
time 242.9 μs (240.6 μs .. 246.8 μs)
0.999 R² (0.998 R² .. 1.000 R²)
mean 244.3 μs (243.3 μs .. 245.7 μs)
std dev 4.414 μs (2.645 μs .. 6.995 μs)
variance introduced by outliers: 11% (moderately inflated)
* parsing and formatting times excluded
>> Day 02b
benchmarking...
time 264.2 μs (257.1 μs .. 272.4 μs)
0.994 R² (0.988 R² .. 1.000 R²)
mean 258.2 μs (256.5 μs .. 263.7 μs)
std dev 10.60 μs (4.192 μs .. 19.23 μs)
variance introduced by outliers: 38% (moderately inflated)
* parsing and formatting times excluded