{-# Language GADTs, DataKinds, LambdaCase, BlockArguments, ImportQualifiedPost, QuasiQuotes #-}
module Main (main) where
import Advent (format, counts)
import Advent.Box (coverBoxes, Box(..))
import Advent.Coord3 (Coord3(..), origin)
import Advent.Nat (Nat(Z, S))
import Control.Monad ((>=>))
import Data.Either (partitionEithers)
import Data.List (transpose)
import Data.Map qualified as Map
import Data.Maybe (listToMaybe)
import Data.Set (Set)
import Data.Set qualified as Set
main :: IO ()
IO ()
main =
do [(Int, [(Int, Int, Int)])]
inp <- [format|2021 19 (--- scanner %u ---%n(%d,%d,%d%n)*)&%n|]
let coord :: (Int, Int, Int) -> Coord3
coord (Int
x,Int
y,Int
z) = Int -> Int -> Int -> Coord3
C3 Int
x Int
y Int
z
let scanners :: [[Coord3]]
scanners = [((Int, Int, Int) -> Coord3) -> [(Int, Int, Int)] -> [Coord3]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Int, Int) -> Coord3
coord [(Int, Int, Int)]
ps | (Int
_,[(Int, Int, Int)]
ps) <- [(Int, [(Int, Int, Int)])]
inp]
let ([Coord3]
offsets, [Set Coord3]
locations) = [(Coord3, Set Coord3)] -> ([Coord3], [Set Coord3])
forall a b. [(a, b)] -> ([a], [b])
unzip ([[Coord3]] -> [(Coord3, Set Coord3)]
start [[Coord3]]
scanners)
Int -> IO ()
forall a. Show a => a -> IO ()
print (Set Coord3 -> Int
forall a. Set a -> Int
Set.size ([Set Coord3] -> Set Coord3
forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
Set.unions [Set Coord3]
locations))
Int -> IO ()
forall a. Show a => a -> IO ()
print ([Coord3] -> Int
radius [Coord3]
offsets)
start ::
[[Coord3]] ->
[(Coord3, Set Coord3)]
start :: [[Coord3]] -> [(Coord3, Set Coord3)]
start ([Coord3]
x:[[Coord3]]
xs) = [[Coord3]] -> [(Coord3, Set Coord3)] -> [(Coord3, Set Coord3)]
assemble [[Coord3]]
xs [(Coord3
origin, [Coord3] -> Set Coord3
forall a. Ord a => [a] -> Set a
Set.fromList [Coord3]
x)]
start [] = []
assemble ::
[[Coord3]] ->
[(Coord3, Set Coord3)] ->
[(Coord3, Set Coord3)]
assemble :: [[Coord3]] -> [(Coord3, Set Coord3)] -> [(Coord3, Set Coord3)]
assemble [[Coord3]]
_ [] = []
assemble [[Coord3]]
remains (c :: (Coord3, Set Coord3)
c@(Coord3
_,Set Coord3
reference):[(Coord3, Set Coord3)]
cs) = (Coord3, Set Coord3)
c (Coord3, Set Coord3)
-> [(Coord3, Set Coord3)] -> [(Coord3, Set Coord3)]
forall a. a -> [a] -> [a]
: [[Coord3]] -> [(Coord3, Set Coord3)] -> [(Coord3, Set Coord3)]
assemble [[Coord3]]
remain' ([(Coord3, Set Coord3)]
new [(Coord3, Set Coord3)]
-> [(Coord3, Set Coord3)] -> [(Coord3, Set Coord3)]
forall a. [a] -> [a] -> [a]
++ [(Coord3, Set Coord3)]
cs)
where
([(Coord3, Set Coord3)]
new,[[Coord3]]
remain') = [Either (Coord3, Set Coord3) [Coord3]]
-> ([(Coord3, Set Coord3)], [[Coord3]])
forall a b. [Either a b] -> ([a], [b])
partitionEithers
[ Either (Coord3, Set Coord3) [Coord3]
-> ((Coord3, Set Coord3) -> Either (Coord3, Set Coord3) [Coord3])
-> Maybe (Coord3, Set Coord3)
-> Either (Coord3, Set Coord3) [Coord3]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Coord3] -> Either (Coord3, Set Coord3) [Coord3]
forall a b. b -> Either a b
Right [Coord3]
remain) (Coord3, Set Coord3) -> Either (Coord3, Set Coord3) [Coord3]
forall a b. a -> Either a b
Left (Set Coord3 -> [Coord3] -> Maybe (Coord3, Set Coord3)
match Set Coord3
reference [Coord3]
remain)
| [Coord3]
remain <- [[Coord3]]
remains
]
match ::
Set Coord3 ->
[Coord3] ->
Maybe (Coord3, Set Coord3)
match :: Set Coord3 -> [Coord3] -> Maybe (Coord3, Set Coord3)
match Set Coord3
xset [Coord3]
ys = [(Coord3, Set Coord3)] -> Maybe (Coord3, Set Coord3)
forall a. [a] -> Maybe a
listToMaybe
[(Coord3
offset, Set Coord3
yset')
| Set Coord3
yset <- [Coord3] -> Set Coord3
forall a. Ord a => [a] -> Set a
Set.fromList ([Coord3] -> Set Coord3) -> [[Coord3]] -> [Set Coord3]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Coord3] -> [[Coord3]]
reorient [Coord3]
ys
, Coord3
offset <- [Coord3] -> [Coord3]
prefilter ((-) (Coord3 -> Coord3 -> Coord3) -> [Coord3] -> [Coord3 -> Coord3]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Set Coord3 -> [Coord3]
forall a. Set a -> [a]
Set.toList Set Coord3
xset [Coord3 -> Coord3] -> [Coord3] -> [Coord3]
forall a b. [a -> b] -> [a] -> [b]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Set Coord3 -> [Coord3]
forall a. Set a -> [a]
Set.toList Set Coord3
yset)
, let yset' :: Set Coord3
yset' = (Coord3 -> Coord3) -> Set Coord3 -> Set Coord3
forall a b. (a -> b) -> Set a -> Set b
Set.mapMonotonic (Coord3
offset Coord3 -> Coord3 -> Coord3
forall a. Num a => a -> a -> a
+) Set Coord3
yset
, Int
12 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Set Coord3 -> Int
forall a. Set a -> Int
Set.size (Set Coord3 -> Set Coord3 -> Set Coord3
forall a. Ord a => Set a -> Set a -> Set a
Set.intersection Set Coord3
xset Set Coord3
yset')
]
prefilter :: [Coord3] -> [Coord3]
prefilter :: [Coord3] -> [Coord3]
prefilter = Map Coord3 Int -> [Coord3]
forall k a. Map k a -> [k]
Map.keys (Map Coord3 Int -> [Coord3])
-> ([Coord3] -> Map Coord3 Int) -> [Coord3] -> [Coord3]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Bool) -> Map Coord3 Int -> Map Coord3 Int
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
12) (Map Coord3 Int -> Map Coord3 Int)
-> ([Coord3] -> Map Coord3 Int) -> [Coord3] -> Map Coord3 Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coord3] -> Map Coord3 Int
forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> Map a Int
counts
reorient :: [Coord3] -> [[Coord3]]
reorient :: [Coord3] -> [[Coord3]]
reorient = [[Coord3]] -> [[Coord3]]
forall a. [[a]] -> [[a]]
transpose ([[Coord3]] -> [[Coord3]])
-> ([Coord3] -> [[Coord3]]) -> [Coord3] -> [[Coord3]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Coord3 -> [Coord3]) -> [Coord3] -> [[Coord3]]
forall a b. (a -> b) -> [a] -> [b]
map (Coord3 -> [Coord3]
rotations (Coord3 -> [Coord3]) -> (Coord3 -> [Coord3]) -> Coord3 -> [Coord3]
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Coord3 -> [Coord3]
faces)
faces :: Coord3 -> [Coord3]
faces :: Coord3 -> [Coord3]
faces (C3 Int
x Int
y Int
z) =
[
Int -> Int -> Int -> Coord3
C3 Int
x Int
y Int
z,
Int -> Int -> Int -> Coord3
C3 Int
y (-Int
x) Int
z,
Int -> Int -> Int -> Coord3
C3 (-Int
x) (-Int
y) Int
z,
Int -> Int -> Int -> Coord3
C3 (-Int
y) Int
x Int
z,
Int -> Int -> Int -> Coord3
C3 Int
y Int
z Int
x,
Int -> Int -> Int -> Coord3
C3 Int
y (-Int
z) (-Int
x)
]
rotations :: Coord3 -> [Coord3]
rotations :: Coord3 -> [Coord3]
rotations (C3 Int
x Int
y Int
z) =
[
Int -> Int -> Int -> Coord3
C3 Int
x Int
y Int
z,
Int -> Int -> Int -> Coord3
C3 Int
x (-Int
z) Int
y,
Int -> Int -> Int -> Coord3
C3 Int
x (-Int
y) (-Int
z),
Int -> Int -> Int -> Coord3
C3 Int
x Int
z (-Int
y)
]
radius :: [Coord3] -> Int
radius :: [Coord3] -> Int
radius = Box ('S ('S ('S ('S 'Z)))) -> Int
forall (n :: Nat). Box n -> Int
minCube (Box ('S ('S ('S ('S 'Z)))) -> Int)
-> ([Coord3] -> Box ('S ('S ('S ('S 'Z))))) -> [Coord3] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Box ('S ('S ('S ('S 'Z))))] -> Box ('S ('S ('S ('S 'Z))))
forall (n :: Nat). HasCallStack => [Box n] -> Box n
coverBoxes ([Box ('S ('S ('S ('S 'Z))))] -> Box ('S ('S ('S ('S 'Z)))))
-> ([Coord3] -> [Box ('S ('S ('S ('S 'Z))))])
-> [Coord3]
-> Box ('S ('S ('S ('S 'Z))))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Coord3 -> Box ('S ('S ('S ('S 'Z)))))
-> [Coord3] -> [Box ('S ('S ('S ('S 'Z))))]
forall a b. (a -> b) -> [a] -> [b]
map Coord3 -> Box ('S ('S ('S ('S 'Z))))
to4
minCube :: Box n -> Int
minCube :: forall (n :: Nat). Box n -> Int
minCube (Dim Int
a Int
b Box n
x) = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Int
bInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
a) (Box n -> Int
forall (n :: Nat). Box n -> Int
minCube Box n
x)
minCube Box n
Pt = Int
0
to4 :: Coord3 -> Box ('S ('S ('S ('S 'Z))))
to4 :: Coord3 -> Box ('S ('S ('S ('S 'Z))))
to4 (C3 Int
x Int
y Int
z) = Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
z Int -> Box ('S ('S ('S 'Z))) -> Box ('S ('S ('S ('S 'Z))))
forall {n :: Nat}. Int -> Box n -> Box ('S n)
# Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
z Int -> Box ('S ('S 'Z)) -> Box ('S ('S ('S 'Z)))
forall {n :: Nat}. Int -> Box n -> Box ('S n)
# Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
z Int -> Box ('S 'Z) -> Box ('S ('S 'Z))
forall {n :: Nat}. Int -> Box n -> Box ('S n)
# Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
z Int -> Box 'Z -> Box ('S 'Z)
forall {n :: Nat}. Int -> Box n -> Box ('S n)
# Box 'Z
Pt
where
Int
i # :: Int -> Box n -> Box ('S n)
# Box n
j = Int -> Int -> Box n -> Box ('S n)
forall (n :: Nat). Int -> Int -> Box n -> Box ('S n)
Dim Int
i Int
i Box n
j
infixr 5 #