aboutsummaryrefslogtreecommitdiffstats
path: root/day19/main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'day19/main.hs')
-rw-r--r--day19/main.hs121
1 files changed, 121 insertions, 0 deletions
diff --git a/day19/main.hs b/day19/main.hs
new file mode 100644
index 0000000..cf01624
--- /dev/null
+++ b/day19/main.hs
@@ -0,0 +1,121 @@
+{-# LANGUAGE TupleSections #-}
+
+module Main where
+
+import Control.Monad (join)
+import Data.Foldable (find)
+import Data.List (deleteBy, nub)
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import Data.Maybe (isJust)
+import Debug.Trace (trace, traceShow)
+import Utils
+
+type Point = (Int, Int, Int)
+
+type Scanner = (Int, [Point])
+
+cmap :: t -> [t -> b] -> [b]
+cmap x = map ($ x)
+
+dot (a, b, c) (d, e, f) = a * d + b * e + c * f
+
+mmulti (a, b, c) v = (dot a v, dot b v, dot c v)
+
+transforms v =
+ let x = mmulti ((1, 0, 0), (0, 0, -1), (0, 1, 0))
+ y = mmulti ((0, 0, 1), (0, 1, 0), (-1, 0, 0))
+ z = mmulti ((0, -1, 0), (1, 0, 0), (0, 0, 1))
+ in cmap
+ v
+ [ id,
+ x,
+ y,
+ z,
+ x . x,
+ x . y,
+ x . z,
+ y . x,
+ y . y,
+ z . y,
+ z . z,
+ x . x . x,
+ x . x . y,
+ x . x . z,
+ x . y . x,
+ x . y . y,
+ x . z . z,
+ y . x . x,
+ y . y . y,
+ z . z . z,
+ x . x . x . y,
+ x . x . y . x,
+ x . y . x . x,
+ x . y . y . y
+ ]
+
+transformBeacons :: [Point] -> [[Point]]
+transformBeacons beacons =
+ beacons $> map transforms .> transpose
+
+checkAssumedMatch beacons1 beacons2 (b1, b2) =
+ let delta = calculateDelta b1 b2
+ translatedBeacons2 = translateBeacons delta beacons2
+ matchingCommonBeacons = translatedBeacons2 $> filter (`elem` beacons1)
+ in if length matchingCommonBeacons >= 12
+ then Just (translatedBeacons2, delta)
+ else Nothing
+
+checkCompositeAndScannerTf :: Scanner -> Scanner -> Maybe (Int, [Point], Point)
+checkCompositeAndScannerTf (s1, beacons1) (s2, beacons2) =
+ let pairings = [(b1, b2) | b1 <- beacons1, b2 <- beacons2]
+ found = map (checkAssumedMatch beacons1 beacons2) pairings $> find isJust .> join
+ -- if found
+ composite = concat .> nub
+ in case found of
+ Just (newBeacons2, newScannerPos) -> Just (s2, composite [beacons1, newBeacons2], newScannerPos)
+ Nothing -> Nothing
+
+manhattanD (x, y, z) (x', y', z') = abs (x - x') + abs (y - y') + abs (z - z')
+
+calculateDelta :: Point -> Point -> Point
+calculateDelta (x, y, z) (x', y', z') = (x - x', y - y', z - z')
+
+translateBeacons :: Point -> [Point] -> [Point]
+translateBeacons (dx, dy, dz) =
+ map (\(x, y, z) -> (x + dx, y + dy, z + dz))
+
+check2CompositeAndScanner :: Scanner -> Scanner -> Maybe (Int, [Point], Point)
+check2CompositeAndScanner scanner1@(s1, beacons1) scanner2@(s2, beacons2) =
+ let beacons2Tfs = transformBeacons beacons2
+ found = beacons2Tfs $> map (\bs -> checkCompositeAndScannerTf scanner1 (s2, bs)) .> find isJust .> join
+ in found
+
+compute _ [] = error "empty scanners list"
+compute scannerPositions [composite] = Just (composite, scannerPositions)
+compute scannerPositions (scanner@(s, _) : others) =
+ let scannerPairs = others $> map (scanner,)
+ found = scannerPairs $> map (uncurry check2CompositeAndScanner) .> find isJust .> join
+ in case found of
+ Just (droppedS, compositeBeacons, newScannerPos) ->
+ let newOthers = filter (fst .> (/=) droppedS) others
+ newComposite = (s, compositeBeacons)
+ newScannerPositions = newScannerPos : scannerPositions
+ in compute newScannerPositions (newComposite : newOthers)
+ Nothing -> compute scannerPositions others
+
+main :: IO ()
+main = do
+ contents <- getContents
+ let scanners =
+ contents
+ $> lines
+ .> splitOn null
+ .> map (drop 1)
+ .> map (map (splitOn (== ',') .> map read .> \[x, y, z] -> (x, y, z)))
+ .> zip [0 ..]
+
+ let Just ((_, resultBeacons), resultScannerPositions) = compute [] scanners
+ length resultBeacons $> print
+ let scannerPairs = [(s1, s2) | s1 <- resultScannerPositions, s2 <- resultScannerPositions, s1 /= s2]
+ scannerPairs $> map (uncurry manhattanD) .> maximum .> print