import Data.List import Data.List.Split import Linear.V3 main :: IO () main = do moons <- parseContent <$> readFile "input" let velocity = replicate 4 [0, 0, 0] print $ part1 (toV3 moons, toV3 velocity) print $ part2 (moons, velocity) parseContent :: String -> [[Int]] parseContent = map (map read . splitOn ",") . lines . removeJunk where removeJunk xs = [x | x <- xs, x `notElem` " <>xyz="] --I’m sure there is a better way to do this toV3 :: [[Int]] -> [V3 Int] toV3 = map (\[x, y, z] -> V3 x y z) part1 :: ([V3 Int], [V3 Int]) -> Int part1 input = energy $ iterate step input !! 1000 where energy (x, y) = sum $ zipWith (*) (geten x) (geten y) geten = map (sum . abs) step :: (Num a, Eq a) => ([a], [a]) -> ([a], [a]) step (moons, vel) = (zipWith (+) moons newVel, newVel) where dVel = gravity moons newVel = zipWith (+) vel dVel gravity xs = [sum [signum $ x - y | x <- xs, y /= x] | y <- xs] part2 :: (Num a, Eq a) => ([[a]], [[a]]) -> Int part2 (moons, vel) = foldr1 lcm periods where m = transpose moons v = transpose vel periods = zipWith (curry findPeriod') m v findPeriod' x = findPeriod x x 1 findPeriod :: (Num a, Eq a) => ([a], [a]) -> ([a], [a]) -> Int -> Int findPeriod x a n = if x' == a then n else findPeriod x' a (n + 1) where x' = step x