advent-of-code/2017/20/day20.hs
2024-11-12 21:46:18 +01:00

70 lines
1.8 KiB
Haskell

#!/usr/bin/env stack
-- stack --resolver lts-9.20 script
{-# LANGUAGE OverloadedStrings #-}
import Data.Attoparsec.Text hiding (take)
import Data.Text (Text)
import qualified Data.Text as T
import Data.List (minimumBy, (\\))
import Data.Function (on)
data Point a =
Point { position :: (a,a,a)
, velocity :: (a,a,a)
, acceleration :: (a,a,a)
}
deriving (Show, Eq)
parseVector :: Text -> Parser (Int,Int,Int)
parseVector id = do
string id
string "=<"
x <- signed decimal
string ","
y <- signed decimal
string ","
z <- signed decimal
string ">"
return (x,y,z)
parsePoint :: Parser (Point Int)
parsePoint = do
pos <- parseVector "p"
string ","
skipSpace
vel <- parseVector "v"
string ","
skipSpace
acc <- parseVector "a"
return $ Point pos vel acc
update :: Num a => Point a -> Point a
update (Point (posx,posy,posz) (velx,vely,velz) (accx,accy,accz)) =
Point (posx',posy',posz') (velx',vely',velz') (accx,accy,accz)
where velx' = velx + accx
vely' = vely + accy
velz' = velz + accz
posx' = posx + velx'
posy' = posy + vely'
posz' = posz + velz'
removeCollisions :: Eq a => [Point a] -> [Point a]
removeCollisions [] = []
removeCollisions (p:ps) = case filter (\x -> position x == position p) ps of
[] -> p : removeCollisions ps
xs -> removeCollisions $ ps \\ xs
distance :: Num a => Point a -> a
distance (Point (x,y,z) _ _) = abs x + abs y + abs z
closestZero :: [Point Int] -> Integer
closestZero = fst . minimumBy (compare `on` (distance . snd)) . zip [0..]
main :: IO ()
main = do
contents <- T.lines . T.pack <$> getContents
let Right points = mapM (parseOnly parsePoint) contents
-- mapM_ print points
print . take 1000 . map closestZero $ iterate (map update) points
print . take 200 . map length $ iterate (removeCollisions . map update) points