From 8cfb87d1d061a7b6248aa6f003f9220050c04937 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sun, 10 Dec 2023 19:06:11 +0100 Subject: 2023-10 in haskell --- 2023/10-Pipe_Maze/first.hs | 124 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 2023/10-Pipe_Maze/first.hs (limited to '2023/10-Pipe_Maze/first.hs') diff --git a/2023/10-Pipe_Maze/first.hs b/2023/10-Pipe_Maze/first.hs new file mode 100644 index 0000000..eedc329 --- /dev/null +++ b/2023/10-Pipe_Maze/first.hs @@ -0,0 +1,124 @@ +-- requires cabal install --lib megaparsec parser-combinators +module Main (main) where + +import Control.Applicative.Permutations +import Control.Monad (void, when) +import Data.Char qualified as C +import Data.Either +import Data.Functor +import Data.List qualified as L +import Data.Map qualified as M +import Data.Maybe +import Data.Set qualified as S +import Data.Vector qualified as V +import Data.Void (Void) +import Text.Megaparsec +import Text.Megaparsec.Char + +import Debug.Trace + +exampleExpectedOutput = 4 + +data Direction = N | S | E | W deriving (Eq, Show) +data Tile = NS | NE | NW | EW | ES | WS | Floor | Start deriving (Eq, Show) +type Line = V.Vector Tile +type Input = V.Vector Line + +type Parser = Parsec Void String + +parseTile :: Parser Tile +parseTile = char '|' $> NS + <|> char 'L' $> NE + <|> char 'J' $> NW + <|> char '-' $> EW + <|> char 'F' $> ES + <|> char '7' $> WS + <|> char '.' $> Floor + <|> char 'S' $> Start + +parseLine :: Parser Line +parseLine = do + line <- some parseTile <* eol + return $ V.generate (length line) (line !!) + +parseInput' :: Parser Input +parseInput' = do + line <- some parseLine <* eof + return $ V.generate (length line) (line !!) + +parseInput :: String -> IO Input +parseInput filename = do + input <- readFile filename + case runParser parseInput' filename input of + Left bundle -> error $ errorBundlePretty bundle + Right input' -> return input' + +compatible :: Tile -> Direction -> Bool +compatible NS N = True +compatible NS S = True +compatible NE N = True +compatible NE E = True +compatible NW N = True +compatible NW W = True +compatible EW E = True +compatible EW W = True +compatible ES E = True +compatible ES S = True +compatible WS W = True +compatible WS S = True +compatible _ _ = False + +type Position = (Int, Int) +type Heading = (Position, Direction) + +compute :: Input -> Int +compute input = walk start 0 `div` 2 + where + walk :: Heading -> Int -> Int + walk h i | tile (fst h) == Just Start = i+1 + | otherwise = walk h' (i+1) + where + h' = step h + step :: Heading -> Heading + step (p@(x, y), N) | tile p == Just NS = ((x, y-1), N) + | tile p == Just ES = ((x+1, y), E) + | tile p == Just WS = ((x-1, y), W) + step (p@(x, y), S) | tile p == Just NS = ((x, y+1), S) + | tile p == Just NE = ((x+1, y), E) + | tile p == Just NW = ((x-1, y), W) + step (p@(x, y), E) | tile p == Just NW = ((x, y-1), N) + | tile p == Just EW = ((x+1, y), E) + | tile p == Just WS = ((x, y+1), S) + step (p@(x, y), W) | tile p == Just NE = ((x, y-1), N) + | tile p == Just EW = ((x-1, y), W) + | tile p == Just ES = ((x, y+1), S) + start = head $ catMaybes [startn, starte, starts, startw] + startn = nearStart (sx, sy-1) N + starts = nearStart (sx, sy+1) S + starte = nearStart (sx+1, sy) E + startw = nearStart (sx-1, sy) W + nearStart :: Position -> Direction -> Maybe Heading + nearStart p d = case tile p of + Just t -> if compatible t d then Just (p, d) else Nothing + Nothing -> Nothing + (sx, sy) = (x, y) -- start + where + hasNoStart :: Line -> Bool + hasNoStart = V.all (/= Start) + y = length $ V.takeWhile hasNoStart input + x = length $ V.takeWhile (/= Start) (input V.! y) + tile :: Position -> Maybe Tile + tile (x, y) = case input V.!? y of + Just line -> line V.!? x + Nothing -> Nothing + +main :: IO () +main = do + example <- parseInput "example" + let exampleOutput = compute example + when (exampleOutput /= exampleExpectedOutput) (error $ "example failed: got " ++ show exampleOutput ++ " instead of " ++ show exampleExpectedOutput) + example2 <- parseInput "example2" + let exampleOutput2 = compute example2 + when (exampleOutput2 /= 8) (error $ "example failed: got " ++ show exampleOutput2 ++ " instead of " ++ show 8) + input <- parseInput "input" + print $ compute input -- cgit v1.2.3