import Data.Char import Data.List import Data.Maybe import Debug.Trace import qualified Crypto.Hash.MD5 as MD5 import qualified Data.ByteString.Char8 as BS import qualified Data.Map.Strict as Map b2i :: Bool -> Int b2i False = 0 b2i True = 1 contains :: (Eq a) => [a] -> a -> Bool contains l i = isJust $ find (==i) l isVowel :: Char -> Bool isVowel = contains "aeiou" maptup2 :: (a -> b) -> (a,a) -> (b,b) maptup2 f (a,b) = (f a,f b) convHex :: String -> String convHex "" = "" convHex (x:xs) = toHexDigit a : toHexDigit b : convHex xs where n = ord x (a,b) = divMod n 16 toHexDigit n = "0123456789abcdef" !! n day4_mine :: MD5.Ctx -> Int day4_mine ctx = day4_mine' ctx 1 day4_mine' :: MD5.Ctx -> Int -> Int day4_mine' ctx n = if take 6 (convHex $ BS.unpack $ MD5.finalize $ MD5.update ctx $ BS.pack $ show n) == "000000" then n else day4_mine' ctx (n+1) day4 :: IO () day4 = do let prefix = "bgvyzdsv" :: String let ctx = MD5.update MD5.init (BS.pack prefix) putStrLn $ show $ day4_mine ctx day5_count :: String -> (Int,Bool,Bool) day5_count "" = (0,False,False) day5_count s = day5_count' (tail s) (head s) (b2i (isVowel (head s)),False,False) day5_count' :: String -> Char -> (Int,Bool,Bool) -> (Int,Bool,Bool) day5_count' "" last t = t day5_count' (x:xs) last (v,d,f) = day5_count' xs x (v + (b2i $ isVowel x),d||x==last,f||contains ["ab","cd","pq","xy"] [last,x]) day5_check :: (Int,Bool,Bool) -> Bool day5_check (v,d,f) = v>=3&&d&¬ f day5_count2 :: String -> (Map.Map (Char,Char) Int,Bool,Bool) day5_count2 s | length s < 2 = (Map.empty,False,False) day5_count2 (a:b:cs) = day5_count2' a b (a,b) cs (Map.insert (a,b) 1 Map.empty,False,False) day5_count2' :: Char -> Char -> (Char,Char) -> String -> (Map.Map (Char,Char) Int,Bool,Bool) -> (Map.Map (Char,Char) Int,Bool,Bool) day5_count2' a b _ "" tup = tup day5_count2' a b lastp (c:cs) (m,t,y) = day5_count2' b c (if lastp==(b,c) then ('\0','\0') else (b,c)) cs (if lastp==(b,c) then m else Map.insertWith (+) (b,c) 1 m,t||a==c,y||(lastp/=(b,c) && (isJust $ Map.lookup (b,c) m))) day5_check2 :: (Map.Map (Char,Char) Int,Bool,Bool) -> Bool day5_check2 (_,t,y) = t && y day5 :: IO () day5 = do input <- readFile "input.txt" let strings = lines input putStrLn $ show $ sum [b2i $ day5_check2 $ day5_count2 s | s <- strings] type Lighttype = Int lightfuncs :: [Lighttype -> Lighttype] lightfuncs = [succ,\x -> max 0 $ pred x,\x -> x+2] -- part 2 --lightfuncs = [\_ -> 1,\_ -> 0,\x -> 1-x] -- part 1 day6_spl :: String -> (Int,Int) day6_spl s = (read $ take i s,read $ drop (i+1) s) :: (Int,Int) where i = fromJust $ findIndex (==',') s --day6_set :: [[Lighttype]] -> (Lighttype -> Lighttype) -> (Int,Int) -> (Int,Int) -> [[Lighttype]] --day6_set m f a b = trace (show m ++ " " ++ show a ++ " " ++ show b) $ traceShowId $ day6_set' m f a b day6_set :: [[Lighttype]] -> (Lighttype -> Lighttype) -> (Int,Int) -> (Int,Int) -> [[Lighttype]] day6_set m f a@(ax,ay) b@(bx,by) | ax==bx||ay==by = m | ay>by = day6_set m f b a | ax>bx = day6_set m f (bx,ay) (ax,by) | ay>0 = take ay m ++ day6_set (drop ay m) f (ax,0) (bx,by-ay) | by0 = let splitted = map (splitAt ax) m in map (uncurry (++)) $ zip (map fst splitted) (day6_set (map snd splitted) f (0,ay) (bx-ax,by)) | bx map f row) m day6_exec :: [[Lighttype]] -> [String] -> [[Lighttype]] day6_exec m l -- = -- fixing sublime syntax highlighting | take 2 l == ["turn","on"] = day6_set m (lightfuncs!!0) (day6_spl (l!!2)) (maptup2 succ $ day6_spl (l!!4)) | take 2 l == ["turn","off"] = day6_set m (lightfuncs!!1) (day6_spl (l!!2)) (maptup2 succ $ day6_spl (l!!4)) | l!!0 == "toggle" = day6_set m (lightfuncs!!2) (day6_spl (l!!1)) (maptup2 succ $ day6_spl (l!!3)) day6 :: IO () day6 = do let size = 1000 input <- readFile "input.txt" --let input = "turn on 0,0 through 3,2\ntoggle 1,1 through 3,3\n" --let input = "" --let input = "turn on 0,0 through 0,0" let wrd = [words l | l <- lines input] print $ sum $ [sum row | row <- foldl day6_exec (replicate size $ replicate size 0) wrd] main = day6