KJ5F447OCICK2TGPMQLG5BMYKKAXQYK6SV5ZAKE6YPKH77I44JEAC U 1L 1U 2R 1U 2R 2L 1R 1L 1D 1L 2D 2U 1R 2D 1L 1D 2U 2R 2D 1R 1D 1U 2D 2U 1R 1L 1D 2R 2D 1R 1D 2L 1D 2R 1U 2R 1L 1U 2R 1L 2U 1R 2D 2R 2D 1L 2U 1R 1L 1U 2L 1U 2R 2D 1U 2D 1R 1D 2L 2U 2L 1R 1D 1U 2R 1L 2U 2L 2U 1L 1D 1U 2D 1R 1L 1D 1L 2D 2L 2R 1U 2L 2U 2D 2L 2D 2U 2R 2U 2R 1D 2R 2L 2D 1U 1L 2R 1U 1L 1D 2U 2D 2L 1R 1L 1U 1D 2U 1D 1R 2U 2R 2D 1U 1L 3D 3R 2L 2R 2L 2D 2L 3D 1L 3R 3L 3U 3D 3U 2L 2D 1U 2R 1D 1R 2L 2U 1R 3D 1R 2L 1U 2D 1U 2R 2U 1L 2U 2L 1D 1L 2D 3L 3D 1R 3U 3R 3D 1L 1R 3L 3D 2U 2L 3D 1L 1U 3L 1D 3U 1R 1L 3R 2U 3L 3R 1L 1D 3L 2D 1U 3D 1L 3U 2R 3U 2L 1D 2U 3D 2R 1U 3R 2L 3D 1R 1L 2D 1U 1L 3D 2U 2R 1L 3R 3U 1L 2D 2L 1U 3D 2U 1R 3L 2R 2L 2R 1D 1U 2L 2R 3L 3U 4R 3D 3R 1D 4R 1D 4R 1D 1R 3L 4D 1L 1U 1D 3U 4D 2L 3R 1D 3U 4D 4L 2R 3U 2L 1D 2U 2L 2R 2D 4R 4L 1R 3U 2D 1U 3L 2D 4U 1L 1D 1U 3R 4L 3R 2U 2R 1U 3D 1U 3L 2U 2L 3D 1R 3L 1U 4R 1L 2R 1D 2R 4L 1D 1L 3U 3D 2U 4L 1R 4L 3D 1U 2L 4D 2L 3R 3L 3D 2U 2L 4D 4U 3L 2R 1U 4D 3L 4D 2L 3D 2L 2U 4D 4R 4D 2L 1U 4D 4L 1R 3L 1D 1L 3D 3R 4L 1R 3U 3R 4L 1U 3R 2U 1L 5R 5D 2R 1U 5L 2R 1U 3D 1U 4L 2U 4L 2R 3U 2R 2U 1L 3U 2D 5R 3U 1R 2U 4L 1D 5R 4U 3D 1U 1R 2U 4R 1L 3D 4U 2R 1L 1R 3L 5R 3L 5D 1R 3D 4U 2D 3L 3D 2L 1R 1D 4L 5U 5D 1L 3R 5D 5U 2L 5U 1L 4D 5R 5U 4D 2L 1D 3L 5R 3D 3L 2U 5R 1L 5D 5R 3L 1U 3D 5R 1U 1R 4L 2U 3R 2D 5L 1U 1L 3R 3D 5U 5D 4R 2L 1U 3L 2R 1L 1R 3D 3U 1L 4D 2U 4L 6D 6U 2R 3U 1D 5L 1D 6U 2R 2L 1R 4D 4L 1U 4L 5R 5L 2U 5R 5U 1D 3L 5D 1R 5L 6U 3D 3U 6R 4L 6R 5D 5R 3L 5D 1L 2R 1L 4U 5R 2U 3D 1L 4R 3L 1R 3U 3R 3L 2D 2L 1R 4D 1L 6D 1R 1U 6L 5R 3L 3D 5L 1D 6R 2D 3U 6D 2U 5L 5D 1R 4D 2U 3D 5L 2D 2U 4R 2L 2D 5L 2R 2D 5R 6D 5L 1U 2R 1D 4L 2R 1D 4L 2R 1U 5R 1L 6U 4R 6U 3L 5U 2R 5D 2U 6D 2U 6L 6U 6R 2U 4D 3U 6L 7R 7L 7R 4L 7R 1L 4R 4L 2D 5U 4D 2R 1L 5U 2R 2U 3L 6U 4D 3U 5R 1U 3L 2D 6L 6U 3L 1D 1U 1L 1D 7R 1U 7R 3D 7R 6L 1R 5L 1D 6L 1D 4L 1R 3D 5U 4D 4U 1D 6L 4D 7R 4L 2U 5R 1D 2L 3R 6L 1D 4R 7U 4D 7L 3U 4D 2R 6D 3R 2L 4D 2R 1L 5U 1R 1U 3R 6D 6R 5L 5R 1U 5L 5D 6L 1D 1L 5U 4D 3R 6U 2R 3D 1L 4R 3L 7R 3U 1D 5L 6R 7D 3L 7D 5L 5D 4L 1D 7L 7R 5L 3D 4L 6R 6U 1R 3D 1L 4U 7L 2R 8D 8R 3L 7D 2R 1L 4U 4L 3D 2L 4U 1R 3L 1D 7R 2L 4U 3L 2U 6L 4R 2D 2R 4U 3D 5U 7R 2L 3D 4U 5L 5U 5D 8R 3L 7U 1L 8U 2D 3U 1L 5D 8L 2D 4U 3R 4U 1R 5L 8R 7U 7L 5U 6D 7U 1R 3U 8D 6L 5R 5L 2U 3D 3R 5D 7R 2D 8L 3U 3R 7D 5U 7L 7U 1R 1L 6R 3L 4U 2R 1L 3U 6R 6D 5U 2D 7U 5R 5D 2R 5D 7U 8D 6U 8R 4D 2U 1L 3U 5D 7L 4R 1U 7D 1U 6D 3L 6U 9L 9U 3L 8D 9U 7D 3U 8L 6D 8U 3D 2L 7U 2L 2R 8D 1L 2R 5U 8R 7L 9R 9U 3D 9L 2D 6L 2R 3D 2U 9D 6U 7D 8U 9R 4D 6U 6L 6D 6L 4U 1D 3R 3D 1R 1D 9U 6R 1U 4D 9L 5U 4D 5U 8L 2D 5L 2R 4D 7U 3L 5R 6D 3U 5L 4U 4D 8R 4D 5L 1D 2U 6D 4L 6U 4L 9R 1D 2L 5U 6R 4U 9D 6R 8U 6L 9R 4D 3R 3U 7L 3R 1L 8U 7D 4L 8U 5D 4R 7U 5L 5D 6U 4R 6D 4U 10L 10U 8L 9D 2U 1L 1D 7U 6R 5D 7R 7L 6R 1D 5R 6L 2R 9U 6L 2R 8D 5L 7R 10L 4R 6D 1U 1L 3D 3R 7U 1L 10D 3L 1U 3D 2U 9D 6R 8D 6L 2U 8D 10U 8L 4D 2U 1R 3L 7U 9R 9U 7L 9U 1D 9U 6R 7L 5R 7U 6D 2L 5U 7D 3L 1R 3L 1D 10L 10D 6U 7L 1R 2U 2L 9R 9U 5R 2D 10U 10D 6L 8U 4L 6U 8D 8U 1L 4D 10U 6D 6L 10U 1D 3L 10R 2U 1D 1L 8D 10L 8D 4L 1D 3R 4D 1R 8D 9U 6D 3U 3L 8U 4R 10D 9U 4R 6L 6D 1R 8D 5L 10D 7U 3L 1D 5U 8D 3R 11U 2L 10D 1R 9U 5R 11U 1D 5U 8R 10U 6L 6R 6U 10R 1L 6R 8L 6D 1L 5U 5R 11U 4R 9U 10R 9L 3U 6R 7L 10U 10L 9R 4U 4R 1U 6L 9R 5L 9D 10U 10R 3D 11R 10L 2R 11L 6U 1R 8D 1U 4R 5D 4L 5U 10R 6D 6U 5D 2L 2D 11R 3U 11L 11U 1R 9U 1D 2U 5R 11D 8L 9D 6L 8U 7L 9U 11D 3L 1U 11L 5D 7L 1U 10L 10D 8R 7D 8U 11R 12L 10U 12D 5R 7U 11D 12U 7L 12D 7L 10U 5D 4R 5D 2R 3U 3L 12D 9L 8D 10R 9U 10R 5L 4U 1D 5L 8U 3R 11L 4D 6L 11R 11U 2R 2D 1L 7U 12L 12R 8U 12L 8U 6R 10D 2L 7U 10L 9D 12U 4R 7U 10L 10R 3U 2L 6U 12D 4R 7L 5R 7D 9U 1D 2L 12R 11D 2R 4D 5R 8L 2R 8L 8U 8L 1U 2R 1D 1U 6L 10R 12D 3U 1D 10U 1R 2U 12R 8U 11R 11D 9L 4R 11L 12U 7L 1U 10R 9L 3U 12L 12D 6R 10D 11R 3D 1U 10D 3R 10D 4R 8L 2R 6U 8R 10U 5L 9R 2D 10U 1D 7R 1D 13R 12D 10R 11L 11U 13L 2D 7U 10D 2R 12U 13L 8D 10R 9D 6U 9L 3R 5L 4U 10R 9U 9D 8R 12L 9D 11U 8R 8D 3U 9D 7U 8R 1U 8L 12U 13L 8U 4D 7U 12L 8D 11U 13L 8U 9L 1R 13L 10R 1L 4R 9L 8R 13L 5U 9D 10L 2R 10L 5D 1L 2D 6U 4L 3U 11L 3R 7U 5D 10U 3D 13U 11R 1U 11R 4L 3U 11R 11L 12R 13U 10R 7L 3U 3R 10U 4R 4L 10R 10D 8L 11D 8R 8U 2R 2U 13L 3D 1L 11R 7U 1L 6U 8R 4L 12U 1L 4U 14D 6R 10L 12D 6R 5U 6L 4D 4R 12U 6R 1U 4L 3U 1L 4D 1U 8L 9D 13U 12R 2D 12R 4U 8R 14U 3L 1D 1U 10L 6U 2L 8D 5R 7U 10R 2U 2R 2L 7U 4R 3U 3L 8D 13R 12L 8D 11U 7L 13D 11U 13D 2L 1R 4L 8R 11L 4R 4L 2D 3R 10D 14R 8L 6D 2R 4L 11D 5U 9L 9D 8R 3U 11R 5U 6L 2D 7R 6D 13R 6U 14L 14R 9D 8U 3R 11D 13R 14L 3U 6D 7R 13L 7R 12D 12R 12U 12R 8L 1U 7R 10U 7L 2D 12U 8D 14U 6D 15R 2U 6L 14U 15R 10U 4R 8D 13R 5D 15U 9R 2U 15R 3U 6D 14L 6D 13R 13L 7D 15U 12L 4R 7D 12U 15D 12R 14U 6L 9D 8L 4R 13L 13D 3L 12D 12U 5D 15L 1U 14L 7U 4L 11U 11L 12R 6D 1L 1U 6R 9U 10L 12R 6U 15D 5L 9D 5L 13U 11D 12R 3U 2R 5D 7L 9D 8R 8L 11D 7R 3D 14L 1R 15L 1U 2L 9R 7U 2R 13U 6R 3L 6R 15L 2D 15L 2R 14L 12R 14D 6L 4R 1L 2U 10D 4U 8R 3D 8U 12L 3R 12L 15R 8L 2D 11U 3L 1D 12L 8U 9L 13U 2L 13U 7L 6D 12U 15L 7U 1D 6R 15L 3U 10R 1U 4R 2U 3R 3L 13R 16D 1L 2U 9L 3D 6L 15D 11L 7U 11L 3U 1L 15R 5U 14L 8R 16D 8U 13R 4U 6L 4R 12L 12U 13D 5R 5L 13D 15R 10D 8U 12R 6L 5D 3U 4L 6R 3L 6D 9U 4L 5R 3D 16R 2U 16L 9U 12R 5L 14D 14R 15D 6L 3D 6U 9D 11L 4D 2L 9D 16L 7R 1L 16D 16U 16R 1U 13D 8R 11L 2R 13D 7L 14R 7U 8R 5L 13R 3U 13R 14U 15R 2D 5R 16U 15D 10U 4L 16U 3D 8U 17L 17R 17U 6D 16U 3R 1L 16U 6R 17L 15D 16R 11D 17L 10R 11U 2D 11L 3R 12U 15R 10D 14U 2R 12D 1U 13D 15U 16L 3U 10D 16U 4D 3R 5U 12R 17D 5R 9U 13R 12L 4D 8U 1D 16R 7D 9U 14D 5L 5U 4L 5R 8L 3D 5L 3R 12U 7R 6D 2R 4D 11L 15R 2U 9L 12R 17L 13U 7R 1D 16U 9R 17D 2L 17D 10R 16L 9D 5R 7D 14L 10U 12L 14R 7D 6R 10D 9R 2L 1R 3U 3D 11L 16D 6R 12U 9D 3R 11D 16L 4R 5L 11R 8D 14R 13U 8D 16L 5R 12U 9D 18L 10R 16L 18D 7L 6U 6R 10L 9R 3D 16R 5D 5R 6D 15U 15L 14D 11R 12D 7R 18D 10U 1D 1U 6D 7U 12D 3L 7U 15L 8R 11L 14D 5U 12R 8D 2U 7D 12L 15D 2U 14D 11U 2D 18R 16U 2D 1R 16D 15R 17D 13L 13U 10L 11U 6R 5D 14R 7L 5R 14D 15R 4L 9D 11L 4R 9U 12L 5D 10R 1D 5R 1L 16D 12L 8U 1D 9U 14L 3R 11D 4L 5R 17D 1L 12R 4L 15R 18U 7D 4R 3U 15R 10L 10U 16R 15L 12D 11R 13D 2R 12U 17R 14L 8U 1L 16D 11R 13D 19U 5D 19L 10R 18D 8R 1L 10D 6U 1L 14R 13L 14U 9D 6L 19U 18L 6R 13D 3U 8R 17U 14L 10R 1L 9R 3U 14R 6L 5D 8R 15L 12R 13U 4R 1L 10U 11L 3U 8R 16U 1D 3U 8L 1D 1L 9D 2U 5L 8R 1U 6L 1R 13U 10D 14U 2L 7R 9U 1R 2L 5U 17R 19L 18U 19D 18L 6R 15U 5R 17L 9U 3L 9U 10L 10R 5D 14U 14R 13U 16D 8L 1D 15R 10D 15U 9D 18L 8R 8L 3U 6L 12R 8D 15L 17U 11R 1D 2R 1U 1L 10D 11U 6L 10U 5R 14
R 5U 8L 8D 3R 17D 10L 25U 20
module Main whereimport Data.Bifunctor (bimap, first, second)import Data.Listimport Data.Charimport Control.Monad.Stateimport Data.Functor.Identityimport Aocmain :: IO ()main = docontent <- lines <$> input 9let moves = parse contentprint $ part1 movesprint $ part2 moveswherepart1 f = length . nub . scanl addPos (0, 0) $ evalState (state headMoves f) Overlappedpart2 f = length . nub . scanl addPos (0, 0) $ evalState (state headMoves2 f) (replicate 9 Overlapped)addPos (x, y) move = (x + (fst $ tailToPos move), y + (snd $ tailToPos move))state f = sequence . map fdata TailMovement = TailMove Direction| TailStillderiving Showdata RelativePosition = Relative Direction| Overlappedderiving Showdata Direction = NorthWest| North| NorthEast| East| SouthEast| South| SouthWest| Westderiving (Show, Eq, Enum, Bounded)type RelativeState = RelativePositiontailToPos :: TailMovement -> (Int, Int)tailToPos TailStill = (0, 0)tailToPos (TailMove NorthWest) = (-1, 1)tailToPos (TailMove North) = (0, 1)tailToPos (TailMove NorthEast) = (1, 1)tailToPos (TailMove East) = (1, 0)tailToPos (TailMove SouthEast) = (1, -1)tailToPos (TailMove South) = (0, -1)tailToPos (TailMove SouthWest) = (-1, -1)tailToPos (TailMove West) = (-1, 0)compassU :: Direction -> [Direction]compassU a = go 4 ((fromEnum a + 2) `mod` 8)wherego :: Int -> Int -> [Direction]go 0 n = [toEnum n]go i n = toEnum n : go (i - 1) ((n + 1) `mod` 8)compassOpposite :: Direction -> DirectioncompassOpposite = toEnum . flip mod 8 . (+4) . fromEnumside :: Direction -> [Direction]side a = [toEnum ((fromEnum a - 1) `mod` 8), a, toEnum ((fromEnum a + 1) `mod` 8)]tailMove :: RelativePosition -> Direction -> (TailMovement, RelativePosition)tailMove Overlapped b = (TailStill, Relative b)tailMove (Relative a) b| even $ fromEnum b = if a `elem` (compassU $ compassOpposite b)then (TailMove . moveDiagLeft $ oppU b , dleft $ oppU b)else (TailStill, diagRelLeft . side . compassOpposite $ b)| a `elem` compassSide = (TailMove a, Relative b)| otherwise = (TailStill, left $ compassU b)whereoppU = compassU . compassOppositemoveDiagLeft (x:xs) = if x == a then toEnum ((fromEnum a + 1) `mod` 8) else moveDiagMid xsmoveDiagMid (x:y:z:xs) = if a `elem` [x, y, z] then y else moveDiagRight xsmoveDiagRight (x:[]) = toEnum ((fromEnum a - 1) `mod` 8)diagRelLeft (x:xs) = if x == a then Relative . toEnum $ ((fromEnum a - 2) `mod` 8) else diagRelMid xsdiagRelMid (x:xs) = if x == a then Overlapped else diagRelRight xsdiagRelRight (x:[]) = Relative . toEnum $ (fromEnum a + 2) `mod` 8compassSide = [toEnum (number - 1), b, toEnum ((number + 1) `mod` 8)]number = fromEnum bdleft (x:xs) = if x == a then Relative . toEnum $ (fromEnum a + 1) `mod` 8 else dmiddle xsdmiddle (x:y:z:xs) = if a `elem` [x, y, z] then Relative a else dright xsdright (x:[]) = Relative . toEnum $ (fromEnum a - 1) `mod` 8left (x:y:xs) = if x == a || y == a then Relative . toEnum $ (fromEnum a - 1) `mod` 8 else middle xsmiddle (x:xs) = if x == a then Overlapped else right xsright (x:y:[]) = Relative . toEnum $ (fromEnum a + 1) `mod` 8headMoves :: Direction -> StateT RelativeState Identity TailMovementheadMoves dir = dorel <- getlet (tail, newRel) = tailMove rel dirput newRelpure tailheadMoves2 :: Direction -> StateT [RelativeState] Identity TailMovementheadMoves2 dir = dorel <- getlet hd = head rellet firstMove = tailMove hd dirlet snake = scanl (\b a -> bwah (fst b) a) firstMove (tail rel)put . map snd $ snakepure . fst . last $ snakewherebwah :: TailMovement -> RelativePosition -> (TailMovement, RelativePosition)bwah (TailMove b) a = tailMove a bbwah TailStill a = (TailStill, a)parse :: [String] -> [Direction]parse = concatMap (uncurry movement . bimap direction (read . drop 1) . break isSpace)wheremovement :: Direction -> Int -> [Direction]movement dir count = replicate count dirdirection "R" = Eastdirection "L" = Westdirection "U" = Northdirection "D" = Southdirection _ = error "Malformed input"