diff options
Diffstat (limited to '14-2.hs')
-rw-r--r-- | 14-2.hs | 89 |
1 files changed, 89 insertions, 0 deletions
@@ -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. |