2019-12-12 11:33:10 +01:00
import Data.List.Split
import Data.List
import Data.Char as Char
import Linear.V3
main = do
moons <- map createMoon <$> map getList <$> map cleanString <$> lines <$> getContents
2019-12-12 13:28:20 +01:00
--let newMoons = calculateMoons moons 1000
--let ernergy = sum $ map getErnergy newMoons
let xAxis = getXAxis moons
let loopx = findLoop xAxis xAxis 0
let yAxis = getYAxis moons
let loopy = findLoop yAxis yAxis 0
let zAxis = getZAxis moons
let loopz = findLoop zAxis zAxis 0
let result = foldl1 lcm [ loopx , loopy , loopz ]
--mapM putStrLn ( map show newMoons )
--putStrLn ( show ernergy)
putStrLn ( show result )
2019-12-12 11:33:10 +01:00
data Moon = Moon { position :: V3 Int
, velocity :: V3 Int
} deriving Show
getList :: String -> [ Int ]
getList = map read . splitOn " , "
cleanString :: String -> String
cleanString xs = xs \\ " <>xyz=== "
createMoon :: [ Int ] -> Moon
createMoon [ x , y , z ] = Moon ( V3 x y z ) ( V3 0 0 0 )
stepGravity :: [ Moon ] -> [ Moon ]
stepGravity xs = map ( \ ( p , v ) -> Moon p v ) $ zip ( newPos ) newVel
where newVel = zipWith ( + ) ( getVel xs ) ( gravity $ getPos xs )
newPos = zipWith ( + ) ( getPos xs ) ( newVel )
2019-12-12 13:28:20 +01:00
gravity :: ( Num a , Eq a ) => [ a ] -> [ a ]
gravity xs = [ sum [ signum $ x - y | x <- xs , y /= x ] | y <- xs ]
calculateMoons :: [ Moon ] -> Int -> [ Moon ]
calculateMoons xs 0 = xs
calculateMoons xs n = calculateMoons ( stepGravity xs ) ( n - 1 )
findLoop :: ( [ Int ] , [ Int ] ) -> ( [ Int ] , [ Int ] ) -> Int -> Int
findLoop pos start c
| pos /= start || c == 0 = findLoop ( stepAxis pos ) start ( c + 1 )
| pos == start = c
stepAxis :: ( [ Int ] , [ Int ] ) -> ( [ Int ] , [ Int ] )
stepAxis ( pos , vel ) = ( newPos , newVel )
where newVel = zipWith ( + ) ( vel ) ( gravity pos )
newPos = zipWith ( + ) ( pos ) ( newVel )
2019-12-12 11:33:10 +01:00
getPos :: [ Moon ] -> [ V3 Int ]
getPos xs = map ( \ x -> position x ) xs
getVel :: [ Moon ] -> [ V3 Int ]
getVel xs = map ( \ x -> velocity x ) xs
getErnergy :: Moon -> Int
getErnergy ( Moon pos vel ) = ( sum $ abs pos ) * ( sum $ abs vel )
2019-12-12 13:28:20 +01:00
getXAxis :: [ Moon ] -> ( [ Int ] , [ Int ] )
getXAxis xs = ( pos , vel )
where pos = map ( \ x -> getX $ position x ) xs
vel = map ( \ x -> getX $ velocity x ) xs
getZAxis :: [ Moon ] -> ( [ Int ] , [ Int ] )
getZAxis xs = ( pos , vel )
where pos = map ( \ x -> getZ $ position x ) xs
vel = map ( \ x -> getZ $ velocity x ) xs
getYAxis :: [ Moon ] -> ( [ Int ] , [ Int ] )
getYAxis xs = ( pos , vel )
where pos = map ( \ x -> getY $ position x ) xs
vel = map ( \ x -> getY $ velocity x ) xs
getX :: V3 Int -> Int
getX ( V3 x y z ) = x
getY :: V3 Int -> Int
getY ( V3 x y z ) = y
getZ :: V3 Int -> Int
getZ ( V3 x y z ) = z