Day 3

This is a fantastic use case for Array. We can again define our custom datatype and write a Read instance as follows.

data Space = Empty | Tree
  deriving (Show, Eq, Enum, Bounded)

instance Read Space where
  readPrec =
    get >>= \case
      '.' -> pure Empty
      '#' -> pure Tree
      _   -> pfail

We should also figure out how to transform our input into an array. This can easily be achieved via the listArray function as follows.

h   = length i'
w   = length v `div` h
i'  = lines input
v   = concat $ fmap (read . pure) <$> i'
geo = listArray ((0, 0), (h - 1, w - 1)) v

Take note that the bounds are (row, column) rather than (x, y). This is because listArray will only increment the first index after reading w elements and we squished the multiline input into a single list.

Both problems ask us to count how many trees we encounter by travelling along a slope. However, this is farily straightforward as we can ask the array if the new position we hit is a tree and increment our position via the slope.

travel :: (Int, Int) -> (Int, Int) -> Int -> Array (Int, Int) Space -> Int
travel (y, x) (dy, dx) n v =
  if y' > h then n
  else case v ! (y', x') of
    Empty -> travel (y', x') (dy, dx) n v
    Tree  -> travel (y', x') (dy, dx) (n + 1) v
  where (_, (h, w)) = bounds v
        (y', x') = (y + dy, (x + dx) `mod` (w + 1))