summaryrefslogtreecommitdiff
path: root/14-2.hs
blob: b37f337e8c1b4ad5cbdef77def8a0719c77caf16 (plain)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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.