From 9ee35f2c248992871980af8e623773c803ea8876 Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Tue, 10 Dec 2024 21:18:50 -0800 Subject: [PATCH] 2024-11 --- common/src/Advent/Input.hs | 20 +++++++------- inputs/2024/11.txt | 1 + solutions/solutions.cabal | 5 ++++ solutions/src/2024/11.hs | 55 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 inputs/2024/11.txt create mode 100644 solutions/src/2024/11.hs diff --git a/common/src/Advent/Input.hs b/common/src/Advent/Input.hs index 3991946..fcf20de 100644 --- a/common/src/Advent/Input.hs +++ b/common/src/Advent/Input.hs @@ -15,6 +15,7 @@ module Advent.Input where import Advent.Coord (Coord(..), coordLines) import Data.Array.Unboxed qualified as A +import Data.List (findIndex) import Data.Map (Map) import Data.Map.Strict qualified as SMap import System.Environment (getArgs) @@ -38,10 +39,6 @@ getRawInput y d = "+":input:_ -> pure input fn:_ -> readFile fn --- | Default input filename given a day number -inputFileName :: Int {- ^ day -} -> FilePath -inputFileName = printf "inputs/%02d.txt" - -- | Load input file as a list of lines. getInputLines :: Int {- ^ year -} -> Int {- ^ day -} -> IO [String] getInputLines y d = lines <$> getRawInput y d @@ -49,11 +46,16 @@ getInputLines y d = lines <$> getRawInput y d -- | Load input file as a rectangular array of characters. getInputArray :: Int {- ^ year -} -> Int {- ^ day -} -> IO (A.UArray Coord Char) getInputArray y d = - do xs <- getInputLines y d - pure $! A.listArray (C 0 0, C (length xs - 1) (length (head xs) - 1)) (concat xs) + do xs <- getInputLines y d + w <- case xs of + [] -> fail "getInputArray: empty grid" + x : xs -> + case findIndex (\y -> length y /= w) xs of + Just i -> fail ("getInputArray: bad length on line " ++ show (i+2)) + Nothing -> pure w + where w = length x + pure $! A.listArray (C 0 0, C (length xs - 1) (w - 1)) (concat xs) -- | Load input file as a 2-dimensional map of characters. getInputMap :: Int {- ^ year -} -> Int {- ^ day -} -> IO (Map Coord Char) -getInputMap y d = - do xs <- getInputLines y d - pure $! SMap.fromList (coordLines xs) +getInputMap y d = SMap.fromList . coordLines <$> getInputLines y d diff --git a/inputs/2024/11.txt b/inputs/2024/11.txt new file mode 100644 index 0000000..41a9fbb --- /dev/null +++ b/inputs/2024/11.txt @@ -0,0 +1 @@ +2 72 8949 0 981038 86311 246 7636740 diff --git a/solutions/solutions.cabal b/solutions/solutions.cabal index ea77515..b29511b 100644 --- a/solutions/solutions.cabal +++ b/solutions/solutions.cabal @@ -1162,3 +1162,8 @@ executable sln_2024_10 import: day main-is: 2024/10.hs build-depends: array, containers + +executable sln_2024_11 + import: day + main-is: 2024/11.hs + build-depends: containers diff --git a/solutions/src/2024/11.hs b/solutions/src/2024/11.hs new file mode 100644 index 0000000..df77927 --- /dev/null +++ b/solutions/src/2024/11.hs @@ -0,0 +1,55 @@ +{-# Language QuasiQuotes, ImportQualifiedPost #-} +{-| +Module : Main +Description : Day 11 solution +Copyright : (c) Eric Mertens, 2024 +License : ISC +Maintainer : emertens@gmail.com + + + +This solution runs efficiently by remembering how many of each stone +there are and blinking all of that same kind of stone all at once. +While the problem does state that order is preserved, the question +it asks about the stones does not depend on order, so we forget that +order! + +>>> :main + "125 17\n" +55312 +65601038650482 + +-} +module Main (main) where + +import Advent (format, times) +import Data.Map (Map) +import Data.Map.Strict qualified as Map + +-- | >>> :main +-- 202019 +-- 239321955280205 +main :: IO () +main = + do input <- [format|2024 11 %u& %n|] + print (solve 25 input) + print (solve 75 input) + +-- | Compute the number of stones resulting from a starting set of stones +-- and a number of blink iterations. +solve :: Int -> [Int] -> Int +solve n input = sum (times n blinks (Map.fromListWith (+) [(i, 1) | i <- input])) + +-- | Blink all the stones at once. Stone numbers are mapped to multiplicity. +blinks :: Map Int Int -> Map Int Int +blinks stones = Map.fromListWith (+) [(stone', n) | (stone, n) <- Map.assocs stones, stone' <- blink stone] + +-- | Blink a single stone and figure out what stones it turns into. +blink :: Int -> [Int] +blink 0 = [1] -- 0 -> 1 +blink n -- split in half if even length + | let str = show n + , let len = length str + , even len + , (l, r) <- splitAt (len `quot` 2) str + = [read l, read r] +blink n = [n * 2024] -- otherwise multiply by 2024