aoc-2021/4/4.hs

89 lines
2.8 KiB
Haskell
Raw Normal View History

import System.IO
import Text.Parsec
import Text.Parsec.String
import Control.Monad
import Data.List
import Data.Maybe
int :: Parser Int
int = read <$> many1 digit
eol :: Parser ()
eol = void $ char '\n'
draws :: Parser [Int]
draws = int `sepBy1` char ','
boardRow :: Parser [Int]
boardRow = do
many (char ' ')
int `sepBy1` many (char ' ')
board :: Parser [[Int]]
board = boardRow `endBy1` eol
boards :: Parser [[[Int]]]
boards = board `endBy1` (eol <|> eof)
inputParser :: Parser ([Int], [[[Int]]])
inputParser = do
d <- draws
eol
eol
b <- boards
return (d, b)
checkRow :: [Int] -> [Int] -> Bool
checkRow row drawn = all (`elem` drawn) row
checkBoard :: [[Int]] -> [Int] -> Bool
checkBoard board drawn = any (`checkRow` drawn) board || any (`checkRow` drawn) (transpose board)
checkBoards :: [[[Int]]] -> [Int] -> [Bool]
checkBoards boards drawn = map (`checkBoard` drawn) boards
processTurns :: [[[Int]]] -> [Int] -> [[Bool]]
processTurns boards draws = map (checkBoards boards) turns
where turns = [ take n draws | n <- [1 .. length draws ] ]
-- ret: (turn no, board win states)
getWinner :: [[[Int]]] -> [Int] -> (Int, Int)
getWinner boards draws = (turnNo, winnerIndex)
where results = processTurns boards draws
turnNo = fromJust (findIndex or results)
boardStates = fromJust (find or results)
winnerIndex = fromJust (elemIndex True boardStates)
getLoser :: [[[Int]]] -> [Int] -> (Int, Int)
getLoser boards draws = (turnNo, loserIndex)
where results = processTurns boards draws
turnNo = fromJust (findIndex and results)
boardStates = results!!(turnNo - 1)
loserIndex = fromJust (elemIndex False boardStates)
getFinalDraw :: [Int] -> Int -> Int
getFinalDraw draws turnNo = draws!!turnNo
sumUnmarked :: [[Int]] -> [Int] -> Int
sumUnmarked board draws = sum filtered
where filtered = [ x | xs <- board,
x <- xs,
x `notElem` draws ]
main = do
handle <- openFile "input.txt" ReadMode
contents <- hGetContents handle
case parse inputParser "" contents of
Left x -> print x
Right (draws, boards) -> print (finalDraw, unmarkedSum, finalDraw * unmarkedSum,
finalDrawLose, unmarkedSumLose, finalDrawLose * unmarkedSumLose)
where (turnNo, winnerIndex) = getWinner boards draws
finalDraw = getFinalDraw draws turnNo
unmarkedSum = sumUnmarked (boards!!winnerIndex) (take (turnNo + 1) draws)
(turnNoLose, loserIndex) = getLoser boards draws
finalDrawLose = getFinalDraw draws turnNoLose
unmarkedSumLose = sumUnmarked (boards!!loserIndex) (take (turnNoLose + 1) draws)
hClose handle