this repo has no description
1module Lib
2 ( parseGrid
3 , initCarrier
4 , doBurst
5 , getCount
6 ) where
7
8import qualified Data.Map.Strict as M
9import Data.List (foldl')
10
11data Dir = N | E | S | W deriving (Show)
12
13data Carrier = Carrier (Int, Int) Dir Int deriving (Show)
14
15type Grid = M.Map (Int, Int) Int
16
17parseGrid :: [String] -> Grid
18parseGrid strs =
19 let coords = [ (x, y) | x <- [0..length strs - 1], y <- [0..length strs - 1] ]
20 in foldl' (\m c@(x, y) -> let v = if strs!!y!!x == '#' then 1 else 0
21 in M.insert c v m
22 ) M.empty coords
23
24startingPos :: Grid -> (Int, Int)
25startingPos grid = case M.lookupMax grid of
26 Just ((x, y), _) -> ((div x 2), (div y 2))
27 Nothing -> (0, 0)
28
29initCarrier :: Grid -> Carrier
30initCarrier g = Carrier (startingPos g) N 0
31
32doBurst :: (Grid, Carrier) -> (Grid, Carrier)
33doBurst (grid, c@(Carrier pos _ _)) =
34 case M.lookup pos grid of
35 Just v -> case v of
36 0 -> (M.adjust (\_ -> updateNodeState v) pos grid, move . turnLeft $ c)
37 1 -> (M.adjust (\_ -> updateNodeState v) pos grid, move . turnRight $ c)
38 2 -> (M.adjust (\_ -> updateNodeState v) pos grid, increaseCount . move $ c)
39 _ -> (M.adjust (\_ -> updateNodeState v) pos grid, move . turnRight . turnRight $ c)
40 Nothing -> (M.insert pos (updateNodeState 0) grid, move . turnLeft $ c)
41
42increaseCount :: Carrier -> Carrier
43increaseCount (Carrier pos dir count) = Carrier pos dir (count + 1)
44
45updateNodeState :: Int -> Int
46updateNodeState 0 = 2 -- Cleaned -> Weakened
47updateNodeState 2 = 1 -- Weakened -> Infected
48updateNodeState 1 = 3 -- Infected -> Flagged
49updateNodeState 3 = 0 -- Flagged -> Cleaned
50updateNodeState _ = 0 -- ??? -> Cleaned
51
52getCount :: Carrier -> Int
53getCount (Carrier _ _ c) = c
54
55move :: Carrier -> Carrier
56move (Carrier (x, y) N count) = Carrier (x, y - 1) N count
57move (Carrier (x, y) W count) = Carrier (x + 1, y) W count
58move (Carrier (x, y) S count) = Carrier (x, y + 1) S count
59move (Carrier (x, y) E count) = Carrier (x - 1, y) E count
60
61turnRight :: Carrier -> Carrier
62turnRight (Carrier pos N count) = Carrier pos W count
63turnRight (Carrier pos W count) = Carrier pos S count
64turnRight (Carrier pos S count) = Carrier pos E count
65turnRight (Carrier pos E count) = Carrier pos N count
66
67turnLeft :: Carrier -> Carrier
68turnLeft (Carrier pos N count) = Carrier pos E count
69turnLeft (Carrier pos E count) = Carrier pos S count
70turnLeft (Carrier pos S count) = Carrier pos W count
71turnLeft (Carrier pos W count) = Carrier pos N count
72
73
74 -- if current infected, turn right, otherwise turn left
75 -- if infected