diff --git a/src/AOC/Challenge/Day18.hs b/src/AOC/Challenge/Day18.hs index 15be7e9..733e81e 100644 --- a/src/AOC/Challenge/Day18.hs +++ b/src/AOC/Challenge/Day18.hs @@ -1,4 +1,4 @@ -{-# OPTIONS_GHC -Wno-unused-imports #-} +{-# OPTIONS_GHC -Wno-unused-imports #-} {-# OPTIONS_GHC -Wno-unused-top-binds #-} -- | @@ -20,65 +20,90 @@ -- types @_ :~> _@ with the actual types of inputs and outputs of the -- solution. You can delete the type signatures completely and GHC -- will recommend what should go in place of the underscores. +module AOC.Challenge.Day18 + ( day18a, + day18b, + ) +where -module AOC.Challenge.Day18 ( - day18a - , day18b - ) where - -import AOC.Prelude - -import qualified Data.Graph.Inductive as G -import qualified Data.IntMap as IM -import qualified Data.IntSet as IS -import qualified Data.List.NonEmpty as NE -import qualified Data.List.PointedList as PL -import qualified Data.List.PointedList.Circular as PLC -import qualified Data.Map as M -import qualified Data.OrdPSQ as PSQ -import qualified Data.Sequence as Seq -import qualified Data.Set as S -import qualified Data.Text as T -import qualified Data.Vector as V -import qualified Linear as L +import AOC.Prelude import Data.Bitraversable -import qualified Text.Megaparsec as P -import qualified Text.Megaparsec.Char as P -import qualified Text.Megaparsec.Char.Lexer as PP +import qualified Data.Graph.Inductive as G +import qualified Data.IntMap as IM +import qualified Data.IntSet as IS +import qualified Data.List.NonEmpty as NE +import qualified Data.List.PointedList as PL +import qualified Data.List.PointedList.Circular as PLC +import qualified Data.Map as M +import qualified Data.OrdPSQ as PSQ +import qualified Data.Sequence as Seq +import qualified Data.Set as S +import qualified Data.Text as T +import qualified Data.Vector as V +import qualified Linear as L import Numeric.Lens (hex) - --- R 5 (#4f4602) - -parseLineA :: String -> Maybe (Dir, Int) -parseLineA = bitraverse (parseDir . head) readMaybe - <=< listTup . take 2 . words +import qualified Text.Megaparsec as P +import qualified Text.Megaparsec.Char as P +import qualified Text.Megaparsec.Char.Lexer as PP shoelace :: NonEmpty Point -> Int --- shoelace (z:|zs) = (`div` 2) . abs . sum $ traceShow (zip (z:zs) (zs)) $ zipWith go (z:zs) (zs ++ [z]) -shoelace (z:|zs) = (`div` 2) . abs . sum $ zipWith go (z:zs) (zs ++ [z]) +shoelace (z :| zs) = (`div` 2) . abs . sum $ zipWith go (z : zs) (zs ++ [z]) where - latterPart = zs ++ [z] go (V2 x y) (V2 x' y') = x * y' - y * x' -day18a :: _ :~> _ -day18a = MkSol - { sParse = traverse parseLineA . lines - , sShow = show - , sSolve = NE.nonEmpty . flip evalState (0, Nothing) . traverse (uncurry go) - -- , sSolve = fmap shoelace . NE.nonEmpty . scanl' go 0 - } +-- | Maps to possible startpoints and possible endpoints +mkSegments :: Bool -> [(Dir, Int)] -> [V2 (Set Point)] +mkSegments clockwise = snd . mapAccumL go 0 where - go :: Dir -> Int -> State (Point, Maybe Dir) [Point] - go d i = state \(p, lastDir) -> - let p' = p + i *^ dirPoint' d - in undefined - -- go p (d, i) = p + i *^ dirPoint' d + go p (d, i) = (p', S.fromList . map (buffer d) . consecs <$> V2 p p') + where + p' = p + i *^ dirPoint' d + consecs q = map (\j -> q + j *^ dirPoint' d) [-1,0,1] + buffer + | clockwise = \case + North -> id + East -> id + South -> (+ V2 1 0) + West -> (+ V2 0 1) + | otherwise = \case + North -> (+ V2 1 0) + East -> (+ V2 1 0) + South -> id + West -> id + +-- | Pick the matching points consecutively +joinSegments :: [V2 (Set Point)] -> Maybe [Point] +joinSegments xs = zipWithM go xs (drop 1 xs) + where + go :: V2 (Set Point) -> V2 (Set Point) -> Maybe Point + go (V2 _ a) (V2 b _) = S.lookupMin (a `S.intersection` b) + +day18 :: (String -> Maybe (Dir, Int)) -> [(Dir, Int)] :~> Int +day18 p = + MkSol + { sParse = traverse p . lines, + sShow = show, + sSolve = \xs -> maximumMay + [ shoelace (0 :| border) + | Just border <- joinSegments . (`mkSegments` xs) <$> [False, True] + ] + } + +parseLineA :: String -> Maybe (Dir, Int) +parseLineA = + bitraverse (parseDir . head) readMaybe + <=< listTup + . take 2 + . words + +day18a :: [(Dir, Int)] :~> Int +day18a = day18 parseLineA parseLineB :: String -> Maybe (Dir, Int) parseLineB = splitUp . filter isHexDigit <=< (!? 2) . words where splitUp xs = do - y:ys <- pure $ reverse xs + y : ys <- pure $ reverse xs d <- case y of '0' -> pure East '1' -> pure South @@ -88,11 +113,5 @@ parseLineB = splitUp . filter isHexDigit <=< (!? 2) . words i <- preview (reversed . hex) ys pure (d, i) -day18b :: _ :~> _ -day18b = MkSol - { sParse = traverse parseLineB . lines - , sShow = show - , sSolve = fmap shoelace . NE.nonEmpty . scanl' go 0 - } - where - go p (d, i) = p + i *^ dirPoint d +day18b :: [(Dir, Int)] :~> Int +day18b = day18 parseLineB