{-# LANGUAGE TupleSections #-} import Data.List (transpose, partition) main :: IO () main = readFile "4/input.txt" >>= print . solve . parse . lines type Input = ([Int], [Board]) parse :: [String] -> Input parse (l : ls) = (n, b) where n = map read $ words [ if c == ',' then ' ' else c | c <- l ] b = parseBoards (filter (/= "") ls) parseBoards :: [String] -> [Board] parseBoards [] = [] parseBoards l = parse a : parseBoards b where (a,b) = splitAt 5 l parse = map $ map ((,False) . read) . words type Board = [[Cell]] hasWon :: Board -> Bool hasWon b = check b || check (transpose b) where check = any $ all marked score :: Int -> Board -> Int score n b = n * sum [ x | c <- b, (x, False) <- c ] call :: Int -> Board -> Board call n = map (map mark) where mark (x,s) = (x, s || x == n) type Cell = (Int, Bool) marked :: Cell -> Bool marked = snd solve :: Input -> (Int, Int) solve (n, b) = (head r, last r) where r = map (uncurry score) $ bingo n b bingo :: [Int] -> [Board] -> [(Int, Board)] bingo _ [] = [] bingo (n : ns) (b : bs) = map (n,) w ++ bingo ns l where (w,l) = partition hasWon r r = iter n (b : bs) iter :: Int -> [Board] -> [Board] iter _ [] = [] iter n (b : bs) = call n b : iter n bs