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
90
91
92
93
94
95
96
97
|
import Data.Maybe (fromMaybe)
import Text.Parsec
import Text.Parsec.Char
data Vec = Vec Int Int deriving 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) }
within :: (Int,Int) -> (Int,Int) -> Robot -> Bool
within (x0,x1) (y0,y1) (Robot (Vec x y) _) =
x >= x0 && x < x1 && y >= y0 && y < y1
score :: Conf -> [Robot] -> Int
score (Conf w h) rs =
let leftHalf = w `div` 2
rightHalf = leftHalf + 1
topHalf = h `div` 2
botHalf = topHalf + 1
q1 = filter (within (0,leftHalf) (0,topHalf)) rs
q2 = filter (within (rightHalf,w) (0,topHalf)) rs
q3 = filter (within (0,leftHalf) (botHalf,h)) rs
q4 = filter (within (rightHalf,w) (botHalf,h)) rs
in product $ map length [q1,q2,q3,q4]
main :: IO ()
main = do
input <- getContents
let conf = Conf 101 103
print
. score conf
. (!! 100)
. iterate (map (update conf))
. doParse
$ input
|