75 lines
1.8 KiB
Haskell
75 lines
1.8 KiB
Haskell
|
import Data.List
|
||
|
import Debug.Trace
|
||
|
|
||
|
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)
|
||
|
|
||
|
solve :: Input -> (Int, Int)
|
||
|
solve input = (f input, g input)
|
||
|
where f = uncurry winBingo
|
||
|
g = uncurry loseBingo
|
||
|
|
||
|
parseBoards :: [String] -> [Board]
|
||
|
parseBoards [] = []
|
||
|
parseBoards list = Board (map (map (Unmarked . read) . words) a) : parseBoards b
|
||
|
where
|
||
|
(a, b) = splitAt 5 list
|
||
|
|
||
|
newtype Board = Board [[Cell]]
|
||
|
deriving
|
||
|
Show
|
||
|
|
||
|
data Cell = Unmarked Int
|
||
|
| Marked Int
|
||
|
deriving
|
||
|
Show
|
||
|
|
||
|
hasWon :: Board -> Bool
|
||
|
hasWon (Board b) = completed b || completed (transpose b)
|
||
|
where
|
||
|
completed = any (all isMarked)
|
||
|
|
||
|
isMarked :: Cell -> Bool
|
||
|
isMarked (Marked _) = True
|
||
|
isMarked _ = False
|
||
|
|
||
|
winBingo :: [Int] -> [Board] -> Int
|
||
|
winBingo (n : ns) (b : bs) =
|
||
|
if any hasWon r
|
||
|
then score n $ head (filter hasWon r)
|
||
|
else winBingo ns r
|
||
|
where
|
||
|
r = iter n (b : bs)
|
||
|
|
||
|
loseBingo :: [Int] -> [Board] -> Int
|
||
|
loseBingo (n : ns) [board]
|
||
|
| hasWon b = score n b
|
||
|
| otherwise = loseBingo ns [b]
|
||
|
where
|
||
|
[b] = iter n [board]
|
||
|
loseBingo (n : ns) (b : bs) =
|
||
|
loseBingo ns (filter (not . hasWon) r)
|
||
|
where
|
||
|
r = iter n (b : bs)
|
||
|
|
||
|
iter :: Int -> [Board] -> [Board]
|
||
|
iter n (b : bs) = callNumber n b : iter n bs
|
||
|
iter _ [] = []
|
||
|
|
||
|
callNumber :: Int -> Board -> Board
|
||
|
callNumber n (Board b) = Board (map (map mark) b)
|
||
|
where
|
||
|
mark (Unmarked x) | x == n = Marked x
|
||
|
mark v = v
|
||
|
|
||
|
score :: Int -> Board -> Int
|
||
|
score n (Board b) = n * sum [ x | c <- b, Unmarked x <- c ]
|