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))