diff --git a/2023/13/Main1.hs b/2023/13/Main1.hs new file mode 100644 index 0000000..3ef8eee --- /dev/null +++ b/2023/13/Main1.hs @@ -0,0 +1,33 @@ +import Data.List.Split (splitOn) +import Data.List (foldl', transpose) +import qualified Data.Vector.Unboxed as VU +import Data.Vector.Unboxed (Vector) + +hashChar :: Char -> Int +hashChar '#' = 1 +hashChar '.' = 0 + +lineToInt :: String -> Int +lineToInt = foldl' (\x y -> 2 * x + hashChar y) 0 + +matchesAt :: Vector Int -> Int -> Bool +matchesAt v i = VU.reverse rightSide == leftSide + where + nMirrored = min i $ VU.length v - i + + leftSide = VU.slice (i - nMirrored) nMirrored v + + rightSide = VU.slice i nMirrored v + +findMatches :: Vector Int -> [Int] +findMatches v = filter (matchesAt v) [1 .. VU.length v - 1] + +solveDirection :: [String] -> Int +solveDirection = sum . findMatches . VU.fromList . map lineToInt + +solve :: [String] -> Int +solve l = 100 * solveDirection l + (solveDirection . transpose) l + +main :: IO () +main = print . sum . map (solve . lines) . splitOn "\n\n" + =<< readFile "data.txt" diff --git a/2023/13/Main2.hs b/2023/13/Main2.hs new file mode 100644 index 0000000..9c17421 --- /dev/null +++ b/2023/13/Main2.hs @@ -0,0 +1,40 @@ +import Data.Bits ((.&.), countTrailingZeros, xor) +import Data.List.Split (splitOn) +import Data.List (foldl', transpose) +import qualified Data.Vector.Unboxed as VU +import Data.Vector.Unboxed (Vector) + +isPowTwo :: Int -> Bool +isPowTwo n = n .&. (n - 1) == 0 + +hashChar :: Char -> Int +hashChar '#' = 1 +hashChar '.' = 0 + +lineToInt :: String -> Int +lineToInt = foldl' (\x y -> 2 * x + hashChar y) 0 + +matchesAt :: Vector Int -> Int -> Bool +matchesAt v i = VU.length differences == 1 && isPowTwo (VU.head differences) + where + nMirrored = min i $ VU.length v - i + + leftSide = VU.slice (i - nMirrored) nMirrored v + + rightSide = VU.slice i nMirrored v + + differences = VU.filter (/= 0) + $ VU.zipWith xor (VU.reverse rightSide) leftSide + +findMatches :: Vector Int -> [Int] +findMatches v = filter (matchesAt v) [1 .. VU.length v - 1] + +solveDirection :: [String] -> Int +solveDirection = last . (0:) . findMatches . VU.fromList . map lineToInt + +solve :: [String] -> Int +solve l = 100 * solveDirection l + (solveDirection . transpose) l + +main :: IO () +main = print . sum . map (solve . lines) . splitOn "\n\n" + =<< readFile "data.txt"