From 19194b5d789959491d809c5c025aac3af0311f17 Mon Sep 17 00:00:00 2001 From: Jacob Jonsson Date: Wed, 3 Dec 2025 20:30:41 +0100 Subject: [PATCH] feat: solve part 2 day 3 --- aoc25.cabal | 3 ++- app/Day3.hs | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/aoc25.cabal b/aoc25.cabal index 9f14070..55df07d 100644 --- a/aoc25.cabal +++ b/aoc25.cabal @@ -67,7 +67,8 @@ executable aoc25 -- other-extensions: -- Other library packages from which modules are imported. - build-depends: base ^>=4.18.2.1 + build-depends: base ^>=4.18.2.1, + containers >= 0.6.7 -- Directories containing source files. hs-source-dirs: app diff --git a/app/Day3.hs b/app/Day3.hs index 64730ac..3acc54d 100644 --- a/app/Day3.hs +++ b/app/Day3.hs @@ -2,7 +2,9 @@ module Main where import Data.Char (digitToInt) import Data.Either (rights) -import Debug.Trace +import Data.List (foldl') +import Data.Map (Map) +import qualified Data.Map as M import System.Environment (getArgs) -- | A candidate is either a left-most number we've just selected, or @@ -37,8 +39,43 @@ part1 = sum . map (maximum . map combine . rights . foldl go [] . map digitToInt combine :: (Int, Int) -> Int combine (a, b) = a * 10 + b +type CandidateN = [Int] + +-- | Maintain one partial candidates for each length. +-- +-- Insight: If there are at least N-1 digits left after we've spotted +-- the greatest digit, that digit needs to be the first digit of our +-- candidates. +-- +-- Insight 2: We only ever need to store one candidate per length. part2 :: String -> Int -part2 = error "Not implemented" +part2 = sum . map (combine . (M.! 12) . foldl' checkPotential mempty . map digitToInt) . lines + where + checkPotential :: Map Int CandidateN -> Int -> Map Int CandidateN + checkPotential cs x = + let partials = filter ((< 12) . length) $ M.elems cs + partials' = [x] : map (genPartial x) partials + in foldl' insertMaxCandidate cs $ filter ((<= 12) . length) partials' + + -- generates new partials by appending x at candidate or after + -- replacing a shedding smaller digits. + genPartial :: Int -> CandidateN -> CandidateN + genPartial x candidate = candidate ++ [x] + + -- replaces a candidate with a better one with the same length + insertMaxCandidate :: Map Int CandidateN -> CandidateN -> Map Int CandidateN + insertMaxCandidate m c = M.insertWith maxCandidate (length c) c m + + maxCandidate :: CandidateN -> CandidateN -> CandidateN + maxCandidate a b + | combine a > combine b = a + | otherwise = b + + combine :: CandidateN -> Int + combine xs = sum $ zipWith power [0 :: Int ..] (reverse xs) + + power :: Int -> Int -> Int + power pow b = b * 10 ^ pow testInput :: String testInput =