f52cd41da1
Star 2 is the most scuffed and probably incorrect thing ever but it produced the right answer for my input and that's good enough for me.
41 lines
1.1 KiB
Haskell
41 lines
1.1 KiB
Haskell
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"
|