{-# Language QuasiQuotes #-}
module Main (main) where
import Advent (format)
import Data.List (partition, transpose)
type Board = [[Int]]
main :: IO ()
IO ()
main =
do ([Int]
calls, [[[Int]]]
boards) <- [format|2021 4 %u&,%n(%n(( *%u)+%n)+)*|]
let outcomes :: [Int]
outcomes = [Int] -> [[[Int]]] -> [Int]
play [Int]
calls [[[Int]]]
boards
Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
outcomes)
Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int
forall a. HasCallStack => [a] -> a
last [Int]
outcomes)
play :: [Int] -> [Board] -> [Int]
play :: [Int] -> [[[Int]]] -> [Int]
play [] [[[Int]]]
_ = []
play (Int
c:[Int]
calls) [[[Int]]]
boards =
case ([[Int]] -> Bool) -> [[[Int]]] -> ([[[Int]]], [[[Int]]])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition [[Int]] -> Bool
isWinner (([[Int]] -> [[Int]]) -> [[[Int]]] -> [[[Int]]]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [[Int]] -> [[Int]]
mark Int
c) [[[Int]]]
boards) of
([[[Int]]]
winners, [[[Int]]]
losers) -> ([[Int]] -> Int) -> [[[Int]]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [[Int]] -> Int
score Int
c) [[[Int]]]
winners [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ [Int] -> [[[Int]]] -> [Int]
play [Int]
calls [[[Int]]]
losers
mark :: Int -> Board -> Board
mark :: Int -> [[Int]] -> [[Int]]
mark Int
c = ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
x -> if Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
c then -Int
1 else Int
x))
score :: Int -> Board -> Int
score :: Int -> [[Int]] -> Int
score Int
c [[Int]]
b = Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
* [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (-Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/=) ([[Int]] -> [Int]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Int]]
b))
isWinner :: Board -> Bool
isWinner :: [[Int]] -> Bool
isWinner [[Int]]
b = [[Int]] -> Bool
f [[Int]]
b Bool -> Bool -> Bool
|| [[Int]] -> Bool
f ([[Int]] -> [[Int]]
forall a. [[a]] -> [[a]]
transpose [[Int]]
b)
where f :: [[Int]] -> Bool
f = ([Int] -> Bool) -> [[Int]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (-Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
==))