X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=advent12%2Fsrc%2Fadvent12.hs;h=efd693b8ba578b2b25775a1148e89e845a642d09;hb=0687ede77cf156e00b9c2cc1a5e49c633b8ba816;hp=b847d28de03b194954589d30b0e26f14d19b4565;hpb=64e7414bf1a3d2391383c4d5c55180d2c7950c9d;p=advent-of-code-19.git diff --git a/advent12/src/advent12.hs b/advent12/src/advent12.hs index b847d28..efd693b 100644 --- a/advent12/src/advent12.hs +++ b/advent12/src/advent12.hs @@ -8,62 +8,121 @@ import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import qualified Control.Applicative as CA -import Linear (V3(..), (^+^), (^-^)) - -import qualified Data.Set as S - --- import Data.List (foldl') --- import Data.Set ((\\)) --- import qualified Data.Map.Strict as M --- import Data.Map.Strict ((!)) - - -type Vec = V3 Integer -data Planet = Planet { _pos :: Vec, _vel :: Vec} deriving (Show, Eq, Ord) -type Planets = S.Set Planet +import Linear (V3(..), V1(..), (^+^), (^-^)) + +import qualified Data.Vector as V + +class (Ord a) => NVec a where + (^+^^) :: a -> a -> a + (^-^^) :: a -> a -> a + nvZero :: a + nvSignum :: a -> a + nvAbsSum :: a -> Integer +instance NVec (V1 Integer) where + x ^+^^ y = x ^+^ y + x ^-^^ y = x ^-^ y + nvZero = V1 0 + nvSignum (V1 x) = V1 (signum x) + nvAbsSum (V1 x) = abs x +instance NVec (V3 Integer) where + x ^+^^ y = x ^+^ y + x ^-^^ y = x ^-^ y + nvZero = V3 0 0 0 + nvSignum (V3 x y z) = V3 (signum x) (signum y) (signum z) + nvAbsSum (V3 x y z) = (abs x) + (abs y) + (abs z) + + +data Planet a = Planet { _pos :: a , _vel :: a} deriving (Show, Eq, Ord) +type Planets a = V.Vector (Planet a) main :: IO () main = do - text <- TIO.readFile "data/advent12a.txt" + text <- TIO.readFile "data/advent12.txt" let planetsT = successfulParse text let planets = enplanet planetsT - print planets + -- print planets print $ part1 planets + print $ part2 planets +part1 :: Planets (V3 Integer) -> Integer +part1 planets = systemEnergy $ head $ drop 1000 $ simulate planets -part1 planets = take 12 $ simulate planets +part2 :: Planets (V3 Integer) -> Integer +part2 planets = period + where planetDimensions = unzipPlanets planets + simCounts = map countSimulate planetDimensions + period = foldl lcm 1 simCounts -enplanet = S.fromList . map (\p -> Planet {_pos = p, _vel = (V3 0 0 0)} ) +enplanet :: (NVec a) => [a] -> Planets a +enplanet = V.fromList . map (\p -> Planet {_pos = p, _vel = nvZero} ) -_x (V3 x _ _) = x -_y (V3 _ y _) = y -_z (V3 _ _ z) = z +unzipPlanets :: V.Vector (Planet (V3 Integer)) -> [V.Vector (Planet (V1 Integer))] +unzipPlanets planets = dimensionSlice $ V.map unzipPlanet planets -gravity (V3 x y z) = V3 (signum x) (signum y) (signum z) +unzipPlanet :: Planet (V3 Integer) -> [Planet (V1 Integer)] +unzipPlanet planet = map mkPlanet posVecs + where posVecs = unzipVec $ _pos planet + mkPlanet p = Planet {_pos = p, _vel = nvZero} +unzipVec :: V3 Integer -> [V1 Integer] +unzipVec (V3 x y z) = [V1 x, V1 y, V1 z] +dimensionSlice :: (NVec a) => V.Vector [Planet a] -> [Planets a] +dimensionSlice slicedPlanets = [sliceDim d | d <- [0..2]] + where sliceDim d = V.map (!!d) slicedPlanets + + + +simulate :: (NVec a) => Planets a -> [Planets a] simulate = iterate simulationStep +countSimulate :: (NVec a) => Planets a -> Integer +countSimulate planets0 = go (simulationStep planets0) 1 + where go planets n + | planets0 == planets = n + | otherwise = go (simulationStep planets) (n + 1) + + +simulationStep :: (NVec a) => Planets a -> Planets a simulationStep planets = planets'' where planets' = applyGravity planets planets'' = applyVelocity planets' -applyGravity planets = S.map (applyGravityHere planets) planets +gravity :: (NVec a) => a -> a +gravity v = nvSignum v + +applyGravity :: (NVec a) => Planets a -> Planets a +applyGravity planets = V.map (applyGravityHere planets) planets -applyGravityHere planets here = S.foldl' updateGravity here planets +applyGravityHere :: (NVec a) => Planets a -> Planet a -> Planet a +applyGravityHere planets here = V.foldl' updateGravity here planets +updateGravity :: (NVec a) => Planet a -> Planet a -> Planet a updateGravity here there = here { _vel = vel'} where vel = _vel here - vel' = vel ^+^ gravity ((_pos there) ^-^ (_pos here)) + vel' = vel ^+^^ gravity ((_pos there) ^-^^ (_pos here)) + +applyVelocity :: (NVec a) => Planets a -> Planets a +applyVelocity = V.map applyVelocityHere + +applyVelocityHere :: (NVec a) => Planet a -> Planet a +applyVelocityHere here = here {_pos = (_pos here) ^+^^ (_vel here)} + + + +-- absSum (Vec1 (V1 x)) = (abs x) +-- absSum (Vec3 (V3 x y z)) = (abs x) + (abs y) + (abs z) -applyVelocity = S.map applyVelocityHere +potentalEnergy planet = nvAbsSum $ _pos planet +kineticEnergy planet = nvAbsSum $ _vel planet +totalEnergy planet = (potentalEnergy planet) * (kineticEnergy planet) -applyVelocityHere here = here {_pos = (_pos here) ^+^ (_vel here)} +systemEnergy = (V.foldl' (+) 0) . (V.map totalEnergy) @@ -93,7 +152,8 @@ coordsP = envector <$> (coordP `sepBy` commaP) coordP = identifierP *> equalP *> signedInteger -successfulParse :: Text -> [Vec] +-- successfulParse :: Text -> [Vec] +successfulParse :: Text -> [V3 Integer] successfulParse input = case parse planetsP "input" input of Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err