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

you are viewing a single comment's thread
view the rest of the comments
[โ€“] 3 points 9 months 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 ProgramIt 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

  • source