{-# Language ImportQualifiedPost, BangPatterns #-}
module Main where
import Advent.Coord (Coord(..), turnLeft, turnRight, turnAround, north)
import Advent.Input (getInputMap)
import Data.Map (Map)
import Data.Map qualified as Map
main :: IO ()
IO ()
main =
do Map Coord Char
input <- Int -> Int -> IO (Map Coord Char)
getInputMap Int
2017 Int
22
let grid :: Map Coord Status
grid = (Char -> Maybe Status) -> Map Coord Char -> Map Coord Status
forall a b k. (a -> Maybe b) -> Map k a -> Map k b
Map.mapMaybe (\Char
x -> if Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'#' then Status -> Maybe Status
forall a. a -> Maybe a
Just Status
Infected else Maybe Status
forall a. Maybe a
Nothing) Map Coord Char
input
let C Int
my Int
mx = [Coord] -> Coord
forall a. HasCallStack => [a] -> a
last (Map Coord Char -> [Coord]
forall k a. Map k a -> [k]
Map.keys Map Coord Char
input)
let start :: Coord
start = Int -> Int -> Coord
C (Int
my Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) (Int
mx Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2)
Int -> IO ()
forall a. Show a => a -> IO ()
print ((Status -> Status)
-> Int -> Int -> Coord -> Coord -> Map Coord Status -> Int
go Status -> Status
rule1 Int
10000 Int
0 Coord
north Coord
start Map Coord Status
grid)
Int -> IO ()
forall a. Show a => a -> IO ()
print ((Status -> Status)
-> Int -> Int -> Coord -> Coord -> Map Coord Status -> Int
go Status -> Status
rule2 Int
10000000 Int
0 Coord
north Coord
start Map Coord Status
grid)
data Status = Clean | Weakened | Infected | Flagged deriving Status -> Status -> Bool
(Status -> Status -> Bool)
-> (Status -> Status -> Bool) -> Eq Status
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Status -> Status -> Bool
== :: Status -> Status -> Bool
$c/= :: Status -> Status -> Bool
/= :: Status -> Status -> Bool
Eq
rule1 :: Status -> Status
rule1 :: Status -> Status
rule1 Status
Clean = Status
Infected
rule1 Status
_ = Status
Clean
rule2 :: Status -> Status
rule2 :: Status -> Status
rule2 Status
Clean = Status
Weakened
rule2 Status
Weakened = Status
Infected
rule2 Status
Infected = Status
Flagged
rule2 Status
Flagged = Status
Clean
turnRule :: Status -> Coord -> Coord
turnRule :: Status -> Coord -> Coord
turnRule Status
Clean = Coord -> Coord
turnLeft
turnRule Status
Weakened = Coord -> Coord
forall a. a -> a
id
turnRule Status
Infected = Coord -> Coord
turnRight
turnRule Status
Flagged = Coord -> Coord
turnAround
go ::
(Status -> Status) ->
Int ->
Int ->
Coord ->
Coord ->
Map Coord Status ->
Int
go :: (Status -> Status)
-> Int -> Int -> Coord -> Coord -> Map Coord Status -> Int
go Status -> Status
rule !Int
n !Int
acc !Coord
dir !Coord
c !Map Coord Status
world
| Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int
acc
| Bool
otherwise = (Status -> Status)
-> Int -> Int -> Coord -> Coord -> Map Coord Status -> Int
go Status -> Status
rule (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int
acc' Coord
dir' Coord
c' Map Coord Status
world'
where
cell :: Status
cell = Status -> Coord -> Map Coord Status -> Status
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault Status
Clean Coord
c Map Coord Status
world
cell' :: Status
cell' = Status -> Status
rule Status
cell
world' :: Map Coord Status
world' = Coord -> Status -> Map Coord Status -> Map Coord Status
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Coord
c Status
cell' Map Coord Status
world
acc' :: Int
acc' | Status
cell' Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
== Status
Infected = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
acc
| Bool
otherwise = Int
acc
dir' :: Coord
dir' = Status -> Coord -> Coord
turnRule Status
cell Coord
dir
c' :: Coord
c' = Coord
c Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
dir'