bss03 icon

Advent of Code 2020 Day 12

bss03 | PRO | 12/12/20 12:37:49 PM UTC | 0 ⭐ | 13664 👁️ | Never ⏰ | []
Haskell |

3.58 KB

|

None

|

0 👍

/

0 👎

{-# language RecordWildCards #-}
 
import Control.Arrow ((&&&))
import Data.List (foldl')
import Data.Maybe (listToMaybe)
 
data Action = North | South | East | West | TurnLeft | TurnRight | Forward deriving (Eq, Show)
 
data Instruction = MkInstruction { action :: Action, value :: Int } deriving (Eq, Show)
 
parseLine :: String -> Maybe Instruction
parseLine [] = Nothing
parseLine (d:n) = MkInstruction <$> charAction d <*> fmap fst (listToMaybe $ reads n)
 
charAction :: Char -> Maybe Action
charAction 'N' = pure North
charAction 'S' = pure South
charAction 'E' = pure East
charAction 'W' = pure West
charAction 'L' = pure TurnLeft
charAction 'R' = pure TurnRight
charAction 'F' = pure Forward
charAction _ = Nothing
 
data Ship =
  MkShip
  { xPos :: Int
  , yPos :: Int
  , xDir :: Int
  , yDir :: Int
  } deriving (Eq, Show)
 
initShip :: Ship
initShip = MkShip{ xPos = 0, yPos = 0, xDir = 1, yDir = 0 }
 
applyShipInstruction :: Instruction -> Ship -> Ship
applyShipInstruction MkInstruction{ action = North, value = delta } s = s{ yPos = yPos s + delta }
applyShipInstruction MkInstruction{ action = South, value = delta } s = s{ yPos = yPos s - delta }
applyShipInstruction MkInstruction{ action = East, value = delta } s = s{ xPos = xPos s + delta }
applyShipInstruction MkInstruction{ action = West, value = delta } s = s{ xPos = xPos s - delta }
applyShipInstruction MkInstruction{ action = TurnLeft, value = degrees } s =
  foldr ($) s $ replicate (degrees `quot` 90) oneLeft
 where oneLeft ss = ss{ xDir = negate $ yDir ss, yDir = xDir ss }
applyShipInstruction MkInstruction{ action = TurnRight, value = degrees } s =
  foldr ($) s $ replicate (degrees `quot` 90) oneRight
 where oneRight ss = ss{ xDir = yDir ss, yDir = negate $ xDir ss }
applyShipInstruction MkInstruction{ action = Forward, value = scale } s =
  s{ xPos = xPos s + scale * xDir s, yPos = yPos s + scale * yDir s }
 
shipManhattan :: Ship -> Int
shipManhattan MkShip{..} = abs xPos + abs yPos
 
part1 :: [Instruction] -> Int
part1 = shipManhattan . foldl' (flip applyShipInstruction) initShip
 
initWaypoint :: Waypoint
initWaypoint = MkWaypoint { xWay = 10, yWay = 1 }
 
data Waypoint = MkWaypoint { xWay :: Int, yWay :: Int } deriving (Eq, Show)
 
applyWaypointedInstruction :: Instruction -> (Ship, Waypoint) -> (Ship, Waypoint)
applyWaypointedInstruction MkInstruction{ action = North, value = delta } (s, w) =
  (s, w{ yWay = yWay w + delta })
applyWaypointedInstruction MkInstruction{ action = South, value = delta } (s, w) =
  (s, w{ yWay = yWay w - delta })
applyWaypointedInstruction MkInstruction{ action = East, value = delta } (s, w) =
  (s, w{ xWay = xWay w + delta })
applyWaypointedInstruction MkInstruction{ action = West, value = delta } (s, w) =
  (s, w{ xWay = xWay w - delta })
applyWaypointedInstruction MkInstruction{ action = TurnLeft, value = degrees } (s, w) =
  (s, foldr ($) w $ replicate (degrees `quot` 90) oneLeft)
 where oneLeft ww = ww{ xWay = negate $ yWay ww, yWay = xWay ww }
applyWaypointedInstruction MkInstruction{ action = TurnRight, value = degrees } (s, w) =
  (s, foldr ($) w $ replicate (degrees `quot` 90) oneRight)
 where oneRight ww = ww{ xWay = yWay ww, yWay = negate $ xWay ww }
applyWaypointedInstruction MkInstruction{ action = Forward, value = scale } (s, w) =
  (s{ xPos = xPos s + scale * xWay w, yPos = yPos s + scale * yWay w}, w)
 
part2 :: [Instruction] -> Int
part2 = shipManhattan . fst . foldl' (flip applyWaypointedInstruction) (initShip, initWaypoint)
 
interactive :: Show a => (String -> a) -> IO ()
interactive f = getContents >>= print . f
 
main :: IO ()
main = interactive (fmap (part1 &&& part2) . traverse parseLine . lines)
 

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎