import Control.Monad import Data.Bits hiding (rotate) import Data.Char import Data.List import Numeric strip :: String -> String strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse rotate :: Int -> [a] -> [a] rotate num l = take (length l) (drop num (cycle l)) blocks :: Int -> [a] -> [[a]] blocks _ [] = [] blocks n l = let (pre, post) = splitAt n l in pre : blocks n post pad :: Int -> a -> [a] -> [a] pad len x list = replicate (len - length list) x ++ list tie' :: [a] -> [Int] -> Int -> [a] tie' chain [] _ = chain tie' chain (len : lens) skip = let (sub, rest) = splitAt len chain in tie' (rotate skip (rest ++ reverse sub)) lens (skip + 1) tie :: [a] -> [Int] -> [a] tie chain lens = let chainlen = length chain numlens = length lens backnum = chainlen - (sum lens + numlens * (numlens - 1) `div` 2) `mod` chainlen in rotate backnum (tie' chain lens 0) knotHash :: [Int] -> [Int] knotHash input = let chainlen = 256 lenlist = input ++ [17, 31, 73, 47, 23] sparse = tie [0..chainlen-1] (take (64 * length lenlist) (cycle lenlist)) in map (foldl1 xor) (blocks 16 sparse) toHex :: [Int] -> String toHex = concat . map (pad 2 '0' . flip showHex "") fromStr :: String -> [Int] fromStr = map ord . strip bytebits :: Int -> [Int] bytebits n = map (fromEnum . testBit n) [7,6..0] setAt :: Int -> a -> [a] -> [a] setAt i v l = let (pre, _ : post) = splitAt i l in pre ++ v : post setAt2 :: Int -> Int -> a -> [[a]] -> [[a]] setAt2 x y v ch = let (pre, r : post) = splitAt y ch in pre ++ setAt x v r : post floodfill :: [[Int]] -> [[Int]] floodfill topchart = go 0 0 2 topchart where w = length (head topchart) h = length topchart go :: Int -> Int -> Int -> [[Int]] -> [[Int]] go x y _ chart | x < 0 || y < 0 || x >= w || y >= h = chart go x y ctr chart = case chart !! y !! x of 1 -> next x y (ctr+1) $ fill x y ctr chart _ -> next x y ctr chart fill :: Int -> Int -> Int -> [[Int]] -> [[Int]] fill x y _ chart | x < 0 || y < 0 || x >= w || y >= h = chart fill x y ctr chart = case chart !! y !! x of 1 -> fill (x-1) y ctr $ fill x (y-1) ctr $ fill (x+1) y ctr $ fill x (y+1) ctr $ setAt2 x y ctr chart _ -> chart next :: Int -> Int -> Int -> [[Int]] -> [[Int]] next x y ctr chart = if x == w-1 then if y == h-1 then chart else go 0 (y+1) ctr chart else go (x+1) y ctr chart main :: IO () main = do prefix <- liftM strip (readFile "14.in") let hashes = map (knotHash . fromStr) [prefix ++ '-' : show i | i <- [0..127]] let chart = map (concatMap bytebits) hashes -- putStrLn (intercalate "\n" $ map (map (\b -> ".#" !! fromEnum b)) chart) print $ sum (map sum chart) let chart' = floodfill chart print $ maximum (map maximum chart') - 1