summaryrefslogtreecommitdiff
path: root/14-2.hs
diff options
context:
space:
mode:
authorLaura Orvokki Kursula <lav@vampires.gay>2024-12-14 19:12:42 +0100
committerLaura Orvokki Kursula <lav@vampires.gay>2024-12-14 19:13:23 +0100
commit04ffb7098bb5e3434880f9438a2c12adbc479a24 (patch)
treec0b7b31fcc36dafb1bbec0d4136324ebd7772153 /14-2.hs
parentdd36c9e670d46387ce401179301ec2232fbb2130 (diff)
downloadaoc2024-04ffb7098bb5e3434880f9438a2c12adbc479a24.tar.gz
aoc2024-04ffb7098bb5e3434880f9438a2c12adbc479a24.zip
14-2
Diffstat (limited to '14-2.hs')
-rw-r--r--14-2.hs89
1 files changed, 89 insertions, 0 deletions
diff --git a/14-2.hs b/14-2.hs
new file mode 100644
index 0000000..b37f337
--- /dev/null
+++ b/14-2.hs
@@ -0,0 +1,89 @@
+import Data.List (sortBy,minimumBy)
+import Data.Maybe (fromMaybe)
+import Text.Parsec
+
+data Vec = Vec { x :: Int, y :: Int } deriving (Eq,Show)
+
+data Robot = Robot { pos :: Vec, vel :: Vec } deriving Show
+
+data Conf = Conf { width :: Int, height :: Int}
+
+doParse :: String -> [Robot]
+doParse s = case parse inputp "" s of
+ Left e -> error $ show e
+ Right xs -> xs
+
+inputp :: Parsec String () [Robot]
+inputp = sepBy robotp newline
+
+robotp :: Parsec String () Robot
+robotp = Robot
+ <$> posp
+ <* char ' '
+ <*> velp
+
+posp :: Parsec String () Vec
+posp = Vec
+ <$ string "p="
+ <*> number
+ <* char ','
+ <*> number
+
+velp :: Parsec String () Vec
+velp = Vec
+ <$ string "v="
+ <*> number
+ <* char ','
+ <*> number
+
+number :: Parsec String () Int
+number = ((read .) . (:)) . fromMaybe '0'
+ <$> optionMaybe (char '-')
+ <*> many1 digit
+
+update :: Conf -> Robot -> Robot
+update c (Robot (Vec x y) v@(Vec vx vy)) =
+ wrap c $ Robot (Vec (x+vx) (y+vy)) v
+
+wrap :: Conf -> Robot -> Robot
+wrap c = wrapH c . wrapV c
+
+wrapH :: Conf -> Robot -> Robot
+wrapH c r | tooLeft c r = wrapRight c r
+ | tooRight c r = wrapLeft c r
+ | otherwise = r
+ where
+ tooLeft _ (Robot (Vec x _) _) = x < 0
+ tooRight (Conf w _) (Robot (Vec x _) _) = x >= w
+
+ wrapRight (Conf w _) r@(Robot (Vec x y) _) = r { pos = Vec (x+w) y }
+ wrapLeft (Conf w _) r@(Robot (Vec x y) _) = r { pos = Vec (x-w) y }
+
+wrapV :: Conf -> Robot -> Robot
+wrapV c r | tooHigh c r = wrapDown c r
+ | tooLow c r = wrapUp c r
+ | otherwise = r
+ where
+ tooHigh _ (Robot (Vec _ y) _) = y < 0
+ tooLow (Conf _ h) (Robot (Vec _ y) _) = y >= h
+
+ wrapDown (Conf _ h) r@(Robot (Vec x y) _) = r { pos = Vec x (y+h) }
+ wrapUp (Conf _ h) r@(Robot (Vec x y) _) = r { pos = Vec x (y-h) }
+
+render :: Conf -> [Robot] -> String
+render (Conf w h) rs =
+ unlines [ [ f $ Vec x y | x <- [0..w-1] ] | y <- [0..h-1] ]
+ where
+ f :: Vec -> Char
+ f p | not $ any ((== p) . pos) rs = ' '
+ | otherwise = '#'
+
+main :: IO ()
+main = do
+ input <- getContents
+ let conf = Conf 101 103
+ let frames = iterate (map $ update conf) . doParse $ input
+ putStr $ unlines [ show n <> "\n" <> render conf (frames !! n)
+ | n <- [ 103*i + 50 | i <- [0..101] ] ]
+ -- Scroll through the output to find the tree. Note that the +50
+ -- is input-dependent.