Today’s Advent of Code problem, “Giant Squid”, asks us to solve bingo. Let’s start with a few import to serve as a literate Haskell prologue.
import Control.Arrow ((&&&))
import Control.Monad (guard)
import Data.List (partition,transpose)
import Data.List.Split (chunksOf,wordsBy)
import Data.Maybe (catMaybes)
We’ll be marking out numbers from bingo boards, so I’ll represent
them as lists of lists of Maybe Int
s, where
Nothing
would represent a marked number.
type Board = [[Maybe Int]]
The input format is very readable, which is all too often synonymous
with painful to parse. For simplicity, I’ll assume the caller would
already have it split by words, which separates the numbers’ order
nicely as a huge first word. I then split it on commas, and form the
boards by nested application of chunksOf 5
.
parse :: [String] -> ([Int],[Board])
: boards ) =
parse ( order read <$> wordsBy (== ',') order
( 5 (chunksOf 5 (Just . read <$> boards)) ) , chunksOf
Marking can be implemented as a simple comparison. A guard-like function is a nice fit, though not really the core of the matter here.
mark :: Int -> Board -> Board
= (map . map) (guarded' (/= n)) board
mark n board where guarded' p mx = do { x <- mx ; x <$ guard (p x) }
Checking a board for a win is now a simple matter of looking for a
row or column entirely made up of Nothing
s.
isWinning :: Board -> Bool
= replicate 5 Nothing `elem` (g ++ transpose g) isWinning g
Scoring a winning board can then be implemented by flattening the board, summing and multiplying.
score :: Int -> Board -> Int
= n * (sum . catMaybes . concat) g score n g
Part 1 asks for the first board to win, part 2 for the last one, so let’s just compute all of their scores in order.
winners :: [Int] -> [Board] -> [Int]
= []
winners _ [] :ns) bs = map (score n) won ++ winners ns bs'
winners (nwhere (won,bs') = partition isWinning (mark n <$> bs)
And combine it all in a simple wrapper.
main :: IO ()
= interact $ show . (head &&& last) . uncurry winners . parse . words main
This concludes today’s solution. See you tomorrow!