blob: a164f8b5a9d8554652df2e1b3dce878a9ec40f52 (
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
|
import Control.Monad (unless)
import Control.Monad.Writer
import Data.List (nub)
type Map = [[Tile]]
data Tile = Free | Obstacle deriving (Eq)
data Coords = Coords Int Int deriving (Eq, Show)
type Vel = Coords
width, height :: [[a]] -> Int
width = length . head
height = length
map2 :: (a -> b) -> [[a]] -> [[b]]
map2 = map . map
sub :: Map -> Coords -> Tile
sub m c@(Coords x y)
| outOfBounds m c = Free
| otherwise = m !! y !! x
parseLines :: [[Char]] -> Map
parseLines =
let p c = case c of
'#' -> Obstacle
_ -> Free
in map2 p
startingPosition :: [[Char]] -> Coords
startingPosition = head . coords . map2 (== '^')
where
coords :: [[Bool]] -> [Coords]
coords xs = [ Coords x y | x <- [0 .. width xs - 1]
, y <- [0 .. height xs - 1]
, xs !! y !! x
]
move :: Vel -> Coords -> Coords
move (Coords vx vy) (Coords px py) = Coords (px + vx) (py + vy)
checkAhead :: Map -> Vel -> Coords -> Bool
checkAhead m = (((== Free) . sub m) .) . move
turn :: Vel -> Coords -> (Coords, Vel)
turn v p = let rot (Coords x y) = Coords (-y) x
v' = rot v
in (move v' p, v')
step :: Map -> Vel -> Coords -> (Coords, Vel)
step m v p = if checkAhead m v p
then (move v p, v)
else turn v p
outOfBounds :: Map -> Coords -> Bool
outOfBounds m (Coords x y) = x < 0 || x >= w || y < 0 || y >= h
where
w = width m
h = height m
run :: Map -> Vel -> Coords -> Writer [Coords] ()
run m v p = unless (outOfBounds m p) $ do
tell [p]
let (p', v') = step m v p
in run m v' p'
main :: IO ()
main = do
ls <- lines <$> getContents
let m = parseLines ls
let p = startingPosition ls
let v = Coords 0 (-1)
print . length . nub . execWriter $ run m v p
|