-
Notifications
You must be signed in to change notification settings - Fork 5
/
Day20.hs
64 lines (54 loc) · 1.82 KB
/
Day20.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
-- module AOC2017.Day20 (day20a, day20b) where
module AOC2017.Day20 where
import AOC2017.Types (Challenge)
import AOC2017.Util (scanlT)
import Data.Char (isDigit)
import Data.Foldable (toList)
import Data.List (find)
import Data.List.Split (splitOn)
import Data.Maybe (fromJust)
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Vector as V
import qualified Linear as L
type Point = L.V3 Int
data Particle a = P { _pAcc :: !a
, _pVel :: !a
, _pPos :: !a
}
deriving (Functor, Foldable, Traversable, Show, Eq, Ord)
type System = [Particle Point]
step :: Num a => Particle a -> Particle a
step = scanlT (+) 0
collide :: System -> System
collide s0 = filter ((`S.notMember` collisions) . _pPos) s0
where
collisions :: S.Set Point
collisions = M.keysSet . M.filter @Int (> 1)
. M.fromListWith (+)
. map ((,1) . _pPos)
$ toList s0
norm :: Point -> Int
norm = sum . fmap abs
day20a :: Challenge
day20a = show . V.minIndex . V.fromList
. (map . fmap) norm
. parse
day20b :: Challenge
day20b = show . length . fromJust . find stop
. iterate (collide . map step)
. parse
where
stop = (> 1000) . minimum . map (norm . _pPos)
parse :: String -> System
parse = map parseLine . lines
where
parseLine :: String -> Particle Point
parseLine (map(read.filter num).splitOn","->[pX,pY,pZ,vX,vY,vZ,aX,aY,aZ])
= P { _pAcc = L.V3 aX aY aZ
, _pVel = L.V3 vX vY vZ
, _pPos = L.V3 pX pY pZ
}
parseLine _ = error "No parse"
num :: Char -> Bool
num c = isDigit c || c == '-'