Day 3: Lobby

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • VegOwOtenks@lemmy.world
    link
    fedilink
    English
    arrow-up
    3
    ·
    3 days ago

    Haskell

    Usually, I get up for AoC, way earlier than I normally would. But today I had to get up at exactly AoC time. I ended up postponing the puzzles until now:

    Complete, Dependency-Free and Runnable Program

    It reads from stdin and writes the both solutions on a separate line to stdout.

    {-# OPTIONS_GHC -Wall #-}
    import qualified Data.Text.IO as TextIO
    import Control.Monad ((<$!>))
    import qualified Data.Array.Unboxed as Array
    import qualified Data.Text as Text
    import qualified Data.Char as Char
    import Data.Array.Unboxed (UArray)
    import qualified Data.Foldable as Foldable
    import Control.Arrow ((&&&))
    import qualified Data.List as List
    
    parse :: Text.Text -> UArray (Int, Int) Int
    parse t = let
        banks = init $ Text.lines t
        bankSize = maybe 0 pred $ Text.findIndex (== '\n') t
        bankCount = Text.count "\n" t - 2
      in Array.listArray ((0, 0), (bankCount, bankSize)) $ List.concatMap (fmap Char.digitToInt . Text.unpack) banks
    
    rowsOf :: UArray (Int, Int) Int -> Int
    rowsOf = fst . snd . Array.bounds
    
    colsOf :: UArray (Int, Int) Int -> Int
    colsOf = snd . snd . Array.bounds
    
    main :: IO ()
    main = do
      batteryBanks <- parse <$!> TextIO.getContents
      print $ part1 batteryBanks
      print $ part2 batteryBanks
    
    part1 :: UArray (Int, Int) Int -> Int
    part1 batteryBanks = Foldable.sum $ pickBatteries 2 batteryBanks <$> [0.. rowsOf batteryBanks]
    
    part2 :: UArray (Int, Int) Int -> Int
    part2 banks = Foldable.sum $ pickBatteries 12 banks <$> [0.. rowsOf banks]
    
    pickBatteries :: Int -> UArray (Int, Int) Int -> Int -> Int
    pickBatteries batteryCount banks row = let
        width = colsOf banks
        getBattery col = banks Array.! (row, col)
    
        go acc 0 _      = acc
        go acc n offset = let
            effectiveEnd = width - pred n
            availableIndices = [offset .. effectiveEnd]
            batteryWithIndices = (id &&& getBattery) <$> availableIndices
            (offset', selectedBattery) = maximumOn snd batteryWithIndices
          in go (acc * 10 + selectedBattery) (pred n) (succ offset')
      in go 0 batteryCount 0
    
    maximumOn :: (Foldable t, Ord b) => (a -> b) -> t a -> a
    maximumOn f collection = case Foldable.toList collection of
      [] -> error "maximumOn: empty foldable"
      (x:xs) -> List.foldl selectMax x xs
      where
        selectMax a b = if f a < f b then b else a