adventofcode/2022/day09.hs

73 lines
2.1 KiB
Haskell

import Control.Monad.Trans.State as St
import Data.Set as S
type Coord = (Int, Int)
data Command = U | D | L | R
parseCommand :: String -> [Command]
parseCommand ('U' : ' ': xs) = replicate (read xs) U
parseCommand ('D' : ' ': xs) = replicate (read xs) D
parseCommand ('L' : ' ': xs) = replicate (read xs) L
parseCommand ('R' : ' ': xs) = replicate (read xs) R
touching :: Coord -> Coord -> Bool
touching (hx, hy) (tx, ty) = hx >= tx -1 && hx <= tx+1 && hy >= ty-1 && hy <= ty+1
updateTail :: Coord -> Coord -> Coord
updateTail (hx, hy) (tx, ty)
| touching (hx, hy) (tx, ty) = (tx, ty)
| hx == tx && hy > ty+1 = (tx, ty+1)
| hx == tx && hy < ty-1 = (tx, ty-1)
| hy == ty && hx > tx+1 = (tx+1, ty)
| hy == ty && hx < tx-1 = (tx-1, ty)
| hx > tx && hy > ty = (tx+1, ty+1)
| hx > tx && hy < ty = (tx+1, ty-1)
| hx < tx && hy > ty = (tx-1, ty+1)
| hx < tx && hy < ty = (tx-1, ty-1)
updateHead :: Command -> Coord -> Coord
updateHead U (x,y) = (x, y-1)
updateHead D (x,y) = (x, y+1)
updateHead L (x,y) = (x-1, y)
updateHead R (x,y) = (x+1, y)
data Coords = CS {h :: Coord, t :: Coord}
type Cs a = St.State Coords a
execute :: Command -> Cs Coord
execute cmd = do
st <- St.get
let head = updateHead cmd (h st)
let tail = updateTail head (t st)
St.put $ CS head tail
pure tail
type Coords2 = [Coord]
type Cs2 a = St.State Coords2 a
initCoords2 :: Coords2
initCoords2 = replicate 10 (0,0)
updateTails :: Coord -> [Coord] -> [Coord]
updateTails head [] = []
updateTails head (t:ts) = let tail = updateTail head t in tail : updateTails tail ts
execute' :: Command -> Cs2 Coord
execute' cmd = do
st <- St.get
let head = updateHead cmd (Prelude.head st)
let tails = updateTails head (Prelude.tail st)
St.put $ head : tails
pure $ last tails
main :: IO ()
main = do
x <- concatMap parseCommand . lines <$> getContents
putStr "part 1: "
let visited = S.fromList $ St.evalState (mapM execute x) (CS (0,0) (0,0))
print $ S.size visited
putStr "part 2: "
let visited2 = S.fromList $ St.evalState (mapM execute' x) initCoords2
print $ S.size visited2