Advent of Code solutions
at main 74 lines 2.5 kB view raw
1import Control.Monad (guard) 2import Control.Monad.State 3import Data.Bits 4import Data.Bool 5import Data.Function ((&)) 6import Data.List (find, foldl1, nub, sort, sortBy, sum) 7import Data.Map (Map, insert) 8import qualified Data.Map as Map 9import Data.Ord (comparing) 10import Text.Parsec (between, char, digit, many, many1, parse, sepBy1, sepEndBy, (<|>)) 11 12integer = read <$> many digit 13 14machine = do 15 _ :: [Char] <- between (char '[') (char ']') $ many1 (char '.' <|> char '#') 16 char ' ' 17 buttons :: [[Int]] <- (between (char '(') (char ')') $ integer `sepBy1` char ',') `sepEndBy` char ' ' 18 joltage :: [Int] <- between (char '{') (char '}') $ integer `sepBy1` char ',' 19 return $ (joltage, buttons) 20 21targetState '.' = False 22targetState '#' = True 23 24buttonBits len button = foldl setBit 0 $ map (\n -> len - n - 1) button 25 26decrAt 0 (m : ms) = m - 1 : ms 27decrAt i (m : ms) = m : decrAt (i - 1) ms 28 29applyButton target [] = target 30applyButton target (i : rest) = applyButton (decrAt i target) rest 31 32choose :: Int -> [a] -> [[a]] 33choose 0 _ = [[]] 34choose n [] = [] 35choose n (x : xs) = ((x :) <$> choose (n - 1) xs) ++ choose n xs 36 37solveBits :: [[Int]] -> Int -> Int -> [[[Int]]] 38solveBits buttons len target = 39 [option | n <- [0 .. length buttons], option <- choose n buttons, target == (foldl xor 0 $ fmap (buttonBits len) option)] 40 41solve buttons joltage = evalState (solve_ joltage) Map.empty 42 where 43 solve_ :: [Int] -> State (Map [Int] Int) Int 44 solve_ joltage = do 45 cached <- gets (Map.lookup joltage) 46 case cached of 47 Nothing -> do 48 ans <- compute joltage 49 modify $ insert joltage ans 50 return ans 51 Just answer -> return answer 52 compute :: [Int] -> State (Map [Int] Int) Int 53 compute joltage = 54 if all (== 0) joltage 55 then return 0 56 else 57 joltage 58 & fmap (\n -> n `mod` 2) 59 & foldl (\joltage bit -> bit .|. joltage `shift` 1) 0 60 & solveBits buttons (length joltage) 61 & fmap (\sol -> (foldl applyButton joltage sol, length sol)) 62 & filter (\(remaining, _) -> all (>= 0) remaining) 63 & mapM 64 ( \(remaining, score) -> do 65 sub <- solve_ (fmap (`div` 2) remaining) 66 return $ sub * 2 + score 67 ) 68 & fmap (foldl min 10000000) 69 70answer input = sum $ fmap (\(j, b) -> solve b j) machines 71 where 72 Right machines = parse (machine `sepEndBy` char '\n') "" input 73 74main = getContents >>= print . answer