{-# Language QuasiQuotes, ImportQualifiedPost #-}
{-|
Module      : Main
Description : Day 3 solution
Copyright   : (c) Eric Mertens, 2018
License     : ISC
Maintainer  : emertens@gmail.com

<https://adventofcode.com/2018/day/3>

Given a bunch of 2D regions find regions that do and do not overlap.

-}
module Main (main) where

import Advent (format, pickOne)
import Advent.Box (Box(Dim, Pt), size, unionBoxes, intersectBox)
import Data.List (tails)
import Data.Maybe (isNothing)

-- | Print the answers to part 1 and 2 of day 3's task.
--
-- >>> :main
-- 115304
-- 275
main :: IO ()
IO ()
main =
 do [(Int, Int, Int, Int, Int)]
input <- [format|2018 3 (#%u %@ %u,%u: %ux%u%n)*|]
    let boxes :: [(Int, Box ('S ('S 'Z)))]
boxes = [(Int
i, Int -> Int -> Box ('S 'Z) -> Box ('S ('S 'Z))
forall (n :: Nat). Int -> Int -> Box n -> Box ('S n)
Dim Int
x (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
sx) (Int -> Int -> Box 'Z -> Box ('S 'Z)
forall (n :: Nat). Int -> Int -> Box n -> Box ('S n)
Dim Int
y (Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
sy) Box 'Z
Pt)) | (Int
i,Int
x,Int
y,Int
sx,Int
sy) <- [(Int, Int, Int, Int, Int)]
input]
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Box ('S ('S 'Z))] -> Int
forall (n :: Nat). [Box n] -> Int
part1 (((Int, Box ('S ('S 'Z))) -> Box ('S ('S 'Z)))
-> [(Int, Box ('S ('S 'Z)))] -> [Box ('S ('S 'Z))]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Box ('S ('S 'Z))) -> Box ('S ('S 'Z))
forall a b. (a, b) -> b
snd [(Int, Box ('S ('S 'Z)))]
boxes))
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([(Int, Box ('S ('S 'Z)))] -> Int
forall i (n :: Nat). [(i, Box n)] -> i
part2 [(Int, Box ('S ('S 'Z)))]
boxes)

-- | Determine the size of the region covered by more than one patch
part1 :: [Box n] -> Int
part1 :: forall (n :: Nat). [Box n] -> Int
part1 [Box n]
boxes =
  [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Box n -> Int) -> [Box n] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Box n -> Int
forall (n :: Nat). Box n -> Int
size ([Box n] -> [Box n]
forall (a :: Nat). [Box a] -> [Box a]
unionBoxes
  [Box n
q | Box n
p:[Box n]
ps <- [Box n] -> [[Box n]]
forall a. [a] -> [[a]]
tails [Box n]
boxes, Just Box n
q <- (Box n -> Maybe (Box n)) -> [Box n] -> [Maybe (Box n)]
forall a b. (a -> b) -> [a] -> [b]
map (Box n -> Box n -> Maybe (Box n)
forall (n :: Nat). Box n -> Box n -> Maybe (Box n)
intersectBox Box n
p) [Box n]
ps]))

-- | Determine identifier of patch with no overlaps.
part2 :: [(i, Box n)] -> i
part2 :: forall i (n :: Nat). [(i, Box n)] -> i
part2 [(i, Box n)]
boxes =
  [i] -> i
forall a. HasCallStack => [a] -> a
head [i
i | ((i
i,Box n
p),[(i, Box n)]
ps) <- [(i, Box n)] -> [((i, Box n), [(i, Box n)])]
forall a. [a] -> [(a, [a])]
pickOne [(i, Box n)]
boxes, ((i, Box n) -> Bool) -> [(i, Box n)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Maybe (Box n) -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe (Box n) -> Bool)
-> ((i, Box n) -> Maybe (Box n)) -> (i, Box n) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Box n -> Box n -> Maybe (Box n)
forall (n :: Nat). Box n -> Box n -> Maybe (Box n)
intersectBox Box n
p (Box n -> Maybe (Box n))
-> ((i, Box n) -> Box n) -> (i, Box n) -> Maybe (Box n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (i, Box n) -> Box n
forall a b. (a, b) -> b
snd) [(i, Box n)]
ps]