···1+import Data.List
2+3+main :: IO ()
4+main = do
5+ contents <- getContents
6+ let entries = fmap read (lines contents)
7+ case find (\x -> (2020 - x) `elem` entries) entries of
8+ Just answer -> print $ answer * (2020 - answer)
9+ Nothing -> return ()
+6
2020/1/p2.hs
···000000
···1+main :: IO ()
2+main = do
3+ contents <- getContents
4+ let entries = fmap read (lines contents)
5+ let (a, b, c) = head [(x, y, z) | x <- entries, y <- entries, x + y <= 2020, z <- entries, x + y + z == 2020]
6+ print $ a * b * c
···1+{-# LANGUAGE ViewPatterns #-}
2+import Data.List
3+import Data.Bits
4+5+split :: Eq a => [a] -> [a] -> [[a]]
6+split x ys = splitInner x [] ys
7+ where
8+ splitInner _ [] [] = []
9+ splitInner _ r [] = [reverse r]
10+ splitInner x r (stripPrefix x -> Just ys) = reverse r : splitInner x [] ys
11+ splitInner x r (y : ys) = splitInner x (y : r) ys
12+13+data Instruction
14+ = Mask [Maybe Int]
15+ | Set Int Int
16+17+parsebit :: Char -> Maybe Int
18+parsebit '1' = Just 1
19+parsebit '0' = Just 0
20+parsebit _ = Nothing
21+22+parse :: String -> Instruction
23+parse (stripPrefix "mask = " -> Just mask) = Mask (parsebit <$> mask)
24+parse (stripPrefix "mem[" -> Just rest) = Set loc val
25+ where [loc, val] = read <$> split "] = " rest
26+27+set :: Int -> Int -> [(Int, Int)] -> [(Int, Int)]
28+set loc val map = case findIndex ((==) loc . fst) map of
29+ Nothing -> (loc, val) : map
30+ Just n -> (loc, val) : take n map ++ drop (n + 1) map
31+32+apply :: [Maybe Int] -> Int -> Int
33+apply mask val = foldl' applyBit val ([0..] `zip` reverse mask)
34+ where applyBit :: Int -> (Int, Maybe Int) -> Int
35+ applyBit val (i, Nothing) = val
36+ applyBit val (i, Just 0) = val .&. complement (bit i)
37+ applyBit val (i, Just 1) = val .|. bit i
38+39+run :: [Instruction] -> [(Int, Int)]
40+run = run_ [] (replicate 36 Nothing)
41+ where
42+ run_ mem _ [] = mem
43+ run_ mem _ (Mask mask : is) = run_ mem mask is
44+ run_ mem mask (Set loc val : is) = run_ (set loc (apply mask val) mem) mask is
45+46+main :: IO ()
47+main = do
48+ instructions <- fmap parse . lines <$> getContents
49+ print $ sum $ snd <$> run instructions
···1+{-# LANGUAGE ViewPatterns #-}
2+import Data.Map (Map, insert, empty, elems)
3+import Data.List (stripPrefix, foldl', replicate)
4+import Data.Bits
5+6+split :: Eq a => [a] -> [a] -> [[a]]
7+split x ys = splitInner x [] ys
8+ where
9+ splitInner _ [] [] = []
10+ splitInner _ r [] = [reverse r]
11+ splitInner x r (stripPrefix x -> Just ys) = reverse r : splitInner x [] ys
12+ splitInner x r (y : ys) = splitInner x (y : r) ys
13+14+data Instruction
15+ = Mask [Maybe Int]
16+ | Set Int Int
17+18+parsebit :: Char -> Maybe Int
19+parsebit '1' = Just 1
20+parsebit '0' = Just 0
21+parsebit _ = Nothing
22+23+parse :: String -> Instruction
24+parse (stripPrefix "mask = " -> Just mask) = Mask (parsebit <$> mask)
25+parse (stripPrefix "mem[" -> Just rest) = Set loc val
26+ where [loc, val] = read <$> split "] = " rest
27+28+setAll :: [Int] -> Int -> Map Int Int -> Map Int Int
29+setAll locs val map = foldl' (flip (`insert` val)) map locs
30+31+apply :: [Maybe Int] -> Int -> [Int]
32+apply mask = applyBits 0 (reverse mask)
33+ where applyBits :: Int -> [Maybe Int] -> Int -> [Int]
34+ applyBits _ [] x = [x]
35+ applyBits i (Just 0 : ms) x = applyBits (i + 1) ms x
36+ applyBits i (Just 1 : ms) x = flip setBit i <$> applyBits (i + 1) ms x
37+ applyBits i (Nothing : ms) x = [flip setBit i, flip clearBit i] <*> applyBits (i + 1) ms x
38+39+run :: [Instruction] -> Map Int Int
40+run = run_ empty (replicate 36 Nothing)
41+ where
42+ run_ mem _ [] = mem
43+ run_ mem _ (Mask mask : is) = run_ mem mask is
44+ run_ mem mask (Set loc val : is) = run_ (setAll (apply mask loc) val mem) mask is
45+46+main :: IO ()
47+main = do
48+ instructions <- fmap parse . lines <$> getContents
49+ print $ sum $ elems $ run instructions
+29
2020/15/p1.hs
···00000000000000000000000000000
···1+import Control.Monad.State
2+import Data.Map (Map)
3+import Data.Map qualified as Map
4+import Text.Parsec
5+6+int :: Parsec String u Int
7+int = read <$> many digit
8+9+parseInput = int `sepBy` char ','
10+11+run :: Int -> [Int] -> Int
12+run n st = evalState (run_ n) (Map.fromList $ zip (init st) [1 ..])
13+ where
14+ run_ :: Int -> Control.Monad.State.State (Map Int Int) Int
15+ run_ n | n <= length st = return $ st !! (n - 1)
16+ run_ i = do
17+ prev <- run_ $ i - 1
18+ before <- gets (Map.lookup prev)
19+ let next = maybe 0 (i - 1 -) before
20+ in do
21+ modify (Map.insert prev (i - 1))
22+ return next
23+24+answer contents = run 2020 input
25+ where
26+ Right input = parse parseInput "" contents
27+28+main :: IO ()
29+main = getContents >>= print . answer
+28
2020/15/p2.hs
···0000000000000000000000000000
···1+import Control.Monad.State
2+import Data.IntMap.Strict (IntMap, (!?))
3+import Data.IntMap.Strict qualified as IntMap
4+import Text.Parsec
5+6+int :: Parsec String u Int
7+int = read <$> many digit
8+9+parseInput = int `sepBy` char ','
10+11+run :: Int -> [Int] -> Int
12+run target st = run_ (length st + 1) 0 (IntMap.fromList $ zip st [1 ..])
13+ where
14+ run_ :: Int -> Int -> IntMap Int -> Int
15+ run_ i n _ | i == target = n
16+ run_ i n map =
17+ let prev = map !? n
18+ map' = IntMap.insert n i map
19+ in case prev of
20+ Nothing -> run_ (i + 1) 0 map'
21+ Just time -> run_ (i + 1) (i - time) map'
22+23+answer contents = run 30000000 input
24+ where
25+ Right input = parse parseInput "" contents
26+27+main :: IO ()
28+main = getContents >>= print . answer
+43
2020/16/p1.hs
···0000000000000000000000000000000000000000000
···1+{-# LANGUAGE ViewPatterns, OverloadedStrings #-}
2+import Data.List
3+import qualified Data.Text as T
4+import Data.Text (Text)
5+6+split :: Eq a => [a] -> [a] -> [[a]]
7+split x ys = splitInner x [] ys
8+ where
9+ splitInner _ [] [] = []
10+ splitInner _ r [] = [reverse r]
11+ splitInner x r (stripPrefix x -> Just ys) = reverse r : splitInner x [] ys
12+ splitInner x r (y : ys) = splitInner x (y : r) ys
13+14+data Field = Field Text [[Int]]
15+fieldRanges (Field _ ranges) = ranges
16+17+newtype Ticket = Ticket [Int]
18+ticketFields (Ticket fields) = fields
19+20+range :: Text -> [Int]
21+range = containing . fmap (read . T.unpack) . T.splitOn "-"
22+ where containing [low, hi] = [low..hi]
23+24+field :: Text -> Field
25+field = makeField . T.splitOn ":"
26+ where makeField [name, ranges] = Field name (range . T.strip <$> T.splitOn "or" ranges)
27+28+ticket :: Text -> Ticket
29+ticket = Ticket . fmap (read . T.unpack) . T.splitOn ","
30+31+tickets :: [Text] -> [Ticket]
32+tickets = fmap ticket . tail
33+34+parse :: Text -> ([Field], Ticket, [Ticket])
35+parse input = (fmap field f, head $ tickets $ tail t, tickets $ tail ts)
36+ where [f, t, ts] = split [""] $ T.lines input
37+38+main :: IO ()
39+main = do
40+ (fields, _, nearbyTickets) <- parse . T.pack <$> getContents
41+ let ranges = fields >>= fieldRanges
42+ values = nearbyTickets >>= ticketFields
43+ in print $ sum $ filter (not . flip any (flip elem <$> ranges) . flip ($)) values
···1+{-# LANGUAGE OverloadedStrings #-}
2+import Control.Monad.State
3+import Data.Either
4+import Data.Maybe
5+import qualified Data.Text as T
6+import Data.Text (Text)
7+import Data.Text.Read
8+9+data Op = Add | Mul
10+11+eval :: Text -> Int
12+eval = evalState (eval' 0 Add)
13+14+number :: State Text Int
15+number = do
16+ e <- gets (decimal . T.strip)
17+ case e of
18+ Left _ -> do
19+ e <- get
20+ error $ T.unpack e
21+ Right (num, str) -> do
22+ put $ T.strip str
23+ return num
24+25+parenthesized :: State Text Int
26+parenthesized = do
27+ modify (T.strip . T.tail)
28+ eval' 0 Add
29+30+getValue :: State Text Int
31+getValue = do
32+ str <- gets T.strip
33+ if "(" `T.isPrefixOf` str
34+ then parenthesized
35+ else number
36+37+getOp :: State Text (Maybe Op)
38+getOp = do
39+ mc <- gets T.uncons
40+ case mc of
41+ Nothing -> return Nothing
42+ Just (c, cs) -> do
43+ put $ T.strip cs
44+ case c of
45+ '+' -> return $ Just Add
46+ '*' -> return $ Just Mul
47+ ')' -> return Nothing
48+ _ -> error [c]
49+50+eval' :: Int -> Op -> State Text Int
51+eval' lhs Add = do
52+ rhs <- getValue
53+ op <- getOp
54+ let v = lhs + rhs in
55+ maybe (return v) (eval' v) op
56+eval' lhs Mul = do
57+ rhs <- getValue
58+ op <- getOp
59+ let v = lhs * rhs in
60+ maybe (return v) (eval' v) op
61+62+main :: IO ()
63+main = getContents >>= print . sum . fmap eval . T.lines . T.pack
···1+{-# LANGUAGE OverloadedStrings, LambdaCase #-}
2+import Control.Monad.State
3+import Data.Either
4+import Data.Maybe
5+import qualified Data.Text as T
6+import Data.Text (Text)
7+import Data.Text.Read
8+9+data Op = Add | Mul
10+11+eval :: Text -> Int
12+eval = evalState factors
13+14+number :: State Text Int
15+number = do
16+ e <- gets (decimal . T.strip)
17+ case e of
18+ Left _ -> do
19+ e <- get
20+ error $ T.unpack e
21+ Right (num, str) -> do
22+ put $ T.strip str
23+ return num
24+25+parenthesized :: State Text Int
26+parenthesized = do
27+ modify (T.strip . T.tail)
28+ x <- factors
29+ modify (T.strip . T.tail)
30+ return x
31+32+getValue :: State Text Int
33+getValue = do
34+ str <- gets T.strip
35+ if "(" `T.isPrefixOf` str
36+ then parenthesized
37+ else number
38+39+mapsnd :: (b -> c) -> (a, b) -> (a, c)
40+mapsnd f (a, b) = (a, f b)
41+42+op :: Char -> State Text Bool
43+op c = do
44+ mc <- gets $ fmap (mapsnd T.strip) . T.uncons
45+ case mc of
46+ Just (cx, cs) | cx == c -> do
47+ put cs
48+ return True
49+ _ -> return False
50+51+add = op '+'
52+mul = op '*'
53+54+terms :: State Text Int
55+terms = do
56+ lhs <- getValue
57+ add >>= \case
58+ False -> return lhs
59+ True -> (lhs +) <$> terms
60+61+factors :: State Text Int
62+factors = do
63+ lhs <- terms
64+ mul >>= \case
65+ False -> return lhs
66+ True -> (lhs *) <$> factors
67+68+main :: IO ()
69+main = getContents >>= print . sum . fmap eval . T.lines . T.pack
···1+main :: IO ()
2+main = do
3+ contents <- getContents
4+ let
5+ levels = lines contents
6+ a = checkAll [0,3..] levels
7+ b = checkAll [0..] levels
8+ c = checkAll [0,5..] levels
9+ d = checkAll [0,7..] levels
10+ e = checkAll [0..] [l | (i, l) <- zip [0..] levels, i `mod` 2 == 0]
11+ in print $ a * b * c * d * e
12+13+checkAll :: [Int] -> [String] -> Int
14+checkAll step levels = length $ filter check $ zip step levels
15+16+check :: (Int, String) -> Bool
17+check (i, line) = line !! (i `mod` length line) == '#'
+16
2020/4/p1.hs
···0000000000000000
···1+import Data.List
2+3+main :: IO ()
4+main = do
5+ contents <- getContents
6+ print $ checkAll $ lines contents
7+8+checkAll :: [String] -> Int
9+checkAll [] = 0
10+checkAll ls =
11+ if length [w | w <- fmap (take 3) (passport >>= words), w `elem` ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]] == 7
12+ then 1 + checkAll rest
13+ else checkAll rest
14+ where (passport, rest) = case findIndex null ls of
15+ Nothing -> (ls, [])
16+ Just n -> let (p, r) = splitAt n ls in (p, tail r)
+36
2020/4/p2.hs
···000000000000000000000000000000000000
···1+{-# LANGUAGE ViewPatterns #-}
2+import Data.List
3+4+main :: IO ()
5+main = do
6+ contents <- getContents
7+ print $ checkAll $ lines contents
8+9+checkAll :: [String] -> Int
10+checkAll [] = 0
11+checkAll ls =
12+ if length (filter valid (passport >>= words)) == 7
13+ then 1 + checkAll rest
14+ else checkAll rest
15+ where (passport, rest) = case findIndex null ls of
16+ Nothing -> (ls, [])
17+ Just n -> let (p, r) = splitAt n ls in (p, tail r)
18+19+valid :: String -> Bool
20+valid (stripPrefix "byr:" -> Just y) = let year = read y in year >= 1920 && year <= 2002
21+valid (stripPrefix "iyr:" -> Just y) = let year = read y in year >= 2010 && year <= 2020
22+valid (stripPrefix "eyr:" -> Just y) = let year = read y in year >= 2020 && year <= 2030
23+valid (stripPrefix "hgt:" -> Just str)
24+ | "cm" `isSuffixOf` str = height >= 150 && height <= 193
25+ | "in" `isSuffixOf` str = height >= 59 && height <= 76
26+ | otherwise = False
27+ where
28+ height :: Int
29+ height = read (take (length str - 2) str)
30+valid (stripPrefix "hcl:#" -> Just col) | length col == 6 = all isHex col
31+valid (stripPrefix "ecl:" -> Just col) | col `elem` ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"] = True
32+valid (stripPrefix "pid:" -> Just pid) | length pid == 9 = all (`elem` ['0'..'9']) pid
33+valid _ = False
34+35+isHex :: Char -> Bool
36+isHex ch = ch `elem` ['0'..'9'] ++ ['a'..'f']
+20
2020/5/p1.hs
···00000000000000000000
···1+main :: IO ()
2+main = do
3+ contents <- getContents
4+ print $ maximum (fmap seatID (lines contents))
5+6+seatID :: String -> Int
7+seatID s = let (row, col) = rowcol s in row * 8 + col
8+9+rowcol :: String -> (Int, Int)
10+rowcol = rowcol_ [0..127] [0..8]
11+ where
12+ rowcol_ row col [] = (head row, head col)
13+ rowcol_ row col s = case s of
14+ 'F' : s -> rowcol_ (take halfrow row) col s
15+ 'B' : s -> rowcol_ (drop halfrow row) col s
16+ 'L' : s -> rowcol_ row (take halfcol col) s
17+ 'R' : s -> rowcol_ row (drop halfcol col) s
18+ _ -> error "wrong"
19+ where halfrow = length row `div` 2
20+ halfcol = length col `div` 2
+25
2020/5/p2.hs
···0000000000000000000000000
···1+import Data.List
2+3+main :: IO ()
4+main = do
5+ contents <- getContents
6+ let
7+ seats = sort $ fmap seatID (lines contents)
8+ Just (before, _) = find (\(x, y) -> x + 2 == y) (zip seats (tail seats))
9+ in print $ before + 1
10+11+seatID :: String -> Int
12+seatID s = let (row, col) = rowcol s in row * 8 + col
13+14+rowcol :: String -> (Int, Int)
15+rowcol = rowcol_ [0..127] [0..8]
16+ where
17+ rowcol_ row col [] = (head row, head col)
18+ rowcol_ row col s = case s of
19+ 'F' : s -> rowcol_ (take halfrow row) col s
20+ 'B' : s -> rowcol_ (drop halfrow row) col s
21+ 'L' : s -> rowcol_ row (take halfcol col) s
22+ 'R' : s -> rowcol_ row (drop halfcol col) s
23+ _ -> error "wrong"
24+ where halfrow = length row `div` 2
25+ halfcol = length col `div` 2
+24
2020/6/p1.hs
···000000000000000000000000
···1+groups :: [String] -> [[String]]
2+groups = splitWhere null
3+4+splitWhere :: (a -> Bool) -> [a] -> [[a]]
5+splitWhere = splitWhere_ []
6+ where
7+ splitWhere_ [] _ [] = []
8+ splitWhere_ g _ [] = [g]
9+ splitWhere_ g f (a : as)
10+ | f a = reverse g : splitWhere_ [] f as
11+ | otherwise = splitWhere_ (a : g) f as
12+13+uniq :: Eq a => [a] -> [a]
14+uniq = uniq_ []
15+ where
16+ uniq_ as [] = as
17+ uniq_ u (a : as)
18+ | a `elem` u = uniq_ u as
19+ | otherwise = uniq_ (a : u) as
20+21+main :: IO ()
22+main = do
23+ contents <- getContents
24+ print (sum $ fmap (length . uniq . concat) (groups $ lines contents))
+30
2020/6/p2.hs
···000000000000000000000000000000
···1+groups :: [String] -> [[String]]
2+groups = splitWhere null
3+4+splitWhere :: (a -> Bool) -> [a] -> [[a]]
5+splitWhere = splitWhere_ []
6+ where
7+ splitWhere_ [] _ [] = []
8+ splitWhere_ g _ [] = [g]
9+ splitWhere_ g f (a : as)
10+ | f a = reverse g : splitWhere_ [] f as
11+ | otherwise = splitWhere_ (a : g) f as
12+13+uniq :: Eq a => [a] -> [a]
14+uniq = uniq_ []
15+ where
16+ uniq_ as [] = as
17+ uniq_ u (a : as)
18+ | a `elem` u = uniq_ u as
19+ | otherwise = uniq_ (a : u) as
20+21+allAnswered :: [String] -> Int
22+allAnswered group = length $ filter answered questions
23+ where
24+ answered q = all (q `elem`) group
25+ questions = (uniq . concat) group
26+27+main :: IO ()
28+main = do
29+ contents <- getContents
30+ print (sum $ fmap allAnswered (groups $ lines contents))
+45
2020/7/p1.hs
···000000000000000000000000000000000000000000000
···1+import Control.Monad
2+import Data.List
3+import Data.Maybe
4+5+data Rule = Rule String [String] deriving (Show)
6+7+mapsnd :: (b -> c) -> (a, b) -> (a, c)
8+mapsnd f (x, y) = (x, f y)
9+10+rule :: String -> Rule
11+rule str = Rule from to
12+ where
13+ a : b : _ : _ : rest = words str
14+ from = a ++ " " ++ b
15+ to = bags rest
16+ bags (_ : a : b : _ : rest) = (a ++ " " ++ b) : bags rest
17+ bags _ = []
18+19+ruleFor s (Rule f _) = s == f
20+21+directlyAllowed :: Rule -> (String, Maybe Bool)
22+directlyAllowed (Rule k []) = (k, Just False)
23+directlyAllowed (Rule k rs)
24+ | "shiny gold" `elem` rs = (k, Just True)
25+ | otherwise = (k, Nothing)
26+27+check :: [Rule] -> [(String, Maybe Bool)] -> [(String, Bool)]
28+check rules pairs
29+ | all (isJust . snd) pairs = fmap (mapsnd fromJust) pairs
30+ | otherwise = check rules $ fmap allowed pairs
31+ where
32+ allowed (s, Just n) = (s, Just n)
33+ allowed (s, Nothing) = (s, updated)
34+ where
35+ Rule _ to = fromJust (find (ruleFor s) rules)
36+ children = fmap (\s -> snd . fromJust $ find ((== s) . fst) pairs) to
37+ updated = foldM (\b c -> (|| b) <$> c) False children :: Maybe Bool
38+39+main :: IO ()
40+main = do
41+ contents <- getContents
42+ let
43+ rules = fmap rule $ lines contents
44+ allowed = fmap directlyAllowed rules
45+ in print $ length $ filter snd $ check rules allowed
+29
2020/7/p2.hs
···00000000000000000000000000000
···1+import Data.List
2+import Data.Maybe
3+4+data Rule = Rule String [(Int, String)] deriving (Show)
5+6+mapsnd :: (b -> c) -> (a, b) -> (a, c)
7+mapsnd f (x, y) = (x, f y)
8+9+rule :: String -> Rule
10+rule str = Rule from to
11+ where
12+ a : b : _ : _ : rest = words str
13+ from = a ++ " " ++ b
14+ to = bags rest
15+ bags (n : a : b : _ : rest) = (read n, a ++ " " ++ b) : bags rest
16+ bags _ = []
17+18+ruleFor s (Rule f _) = s == f
19+20+mustContain :: String -> [Rule] -> Int
21+mustContain bag rules =
22+ let Rule _ to = fromJust $ find (ruleFor bag) rules in
23+ sum $ fmap (\(x, bag) -> x * (1 + mustContain bag rules)) to
24+25+main :: IO ()
26+main = do
27+ contents <- getContents
28+ let rules = fmap rule $ lines contents in
29+ print $ mustContain "shiny gold" rules
+27
2020/8/p1.hs
···000000000000000000000000000
···1+{-# LANGUAGE ViewPatterns #-}
2+import Control.Monad
3+import Data.List
4+5+data Instruction
6+ = Nop
7+ | Acc Int
8+ | Jmp Int
9+10+parse :: String -> Instruction
11+parse (fmap read . stripPrefix "acc +" -> Just i) = Acc i
12+parse (fmap read . stripPrefix "acc -" -> Just i) = Acc (-i)
13+parse (fmap read . stripPrefix "jmp +" -> Just i) = Jmp i
14+parse (fmap read . stripPrefix "jmp -" -> Just i) = Jmp (-i)
15+parse _ = Nop
16+17+exec :: Int -> [Int] -> [Instruction] -> Int
18+exec i e _ | i `elem` e = 0
19+exec i e inst = case inst !! i of
20+ Nop -> exec (i + 1) (i : e) inst
21+ Acc n -> n + exec (i + 1) (i : e) inst
22+ Jmp n -> exec (i + n) (i : e) inst
23+24+main :: IO ()
25+main = do
26+ instructions <- fmap parse . lines <$> getContents
27+ print $ exec 0 [] instructions
+46
2020/8/p2.hs
···0000000000000000000000000000000000000000000000
···1+{-# LANGUAGE ViewPatterns #-}
2+import Control.Monad
3+import Data.Functor
4+import Data.List
5+import Data.Maybe
6+7+data Instruction
8+ = Nop Int
9+ | Acc Int
10+ | Jmp Int
11+12+swap :: Instruction -> Maybe Instruction
13+swap (Nop i) = Just (Jmp i)
14+swap (Jmp i) = Just (Nop i)
15+swap _ = Nothing
16+17+parse :: String -> Instruction
18+parse (fmap read . stripPrefix "acc +" -> Just i) = Acc i
19+parse (fmap read . stripPrefix "acc -" -> Just i) = Acc (-i)
20+parse (fmap read . stripPrefix "jmp +" -> Just i) = Jmp i
21+parse (fmap read . stripPrefix "jmp -" -> Just i) = Jmp (-i)
22+parse (fmap read . stripPrefix "nop +" -> Just i) = Nop i
23+parse (fmap read . stripPrefix "nop -" -> Just i) = Nop (-i)
24+parse _ = error "invalid"
25+26+exec :: Int -> [Int] -> [Instruction] -> Maybe Int
27+exec i e _ | i `elem` e = Nothing
28+exec i _ inst | i >= length inst = Just 0
29+exec i e inst = case inst !! i of
30+ Nop _ -> exec (i + 1) (i : e) inst
31+ Acc n -> (n +) <$> exec (i + 1) (i : e) inst
32+ Jmp n -> exec (i + n) (i : e) inst
33+34+connect :: [Instruction] -> [Instruction] -> Instruction -> [Instruction]
35+connect ls rs i = ls ++ (i : rs)
36+37+fix :: [Instruction] -> Int
38+fix inst = fromJust $ join $ find isJust $ zipWith3 try (inits (init inst)) (tails (tail inst)) (swap <$> inst)
39+ where
40+ try :: [Instruction] -> [Instruction] -> Maybe Instruction -> Maybe Int
41+ try ls rs x = x <&> connect ls rs >>= exec 0 []
42+43+main :: IO ()
44+main = do
45+ instructions <- fmap parse . lines <$> getContents
46+ print $ fix instructions
+12
2020/9/p1.hs
···000000000000
···1+check :: [Int] -> [Int] -> Int
2+check _ [] = error "invalid"
3+check preamble (x : xs) = if x `elem` valid preamble then check (x : init preamble) xs else x
4+5+valid :: [Int] -> [Int]
6+valid preamble = [(preamble !! i) + (preamble !! j) | i <- [0..23], j <- [i+1..24]]
7+8+main :: IO ()
9+main = do
10+ numbers <- fmap read . lines <$> getContents :: IO [Int]
11+ let (preamble, contents) = splitAt 25 numbers in
12+ print $ check (reverse preamble) contents
+25
2020/9/p2.hs
···0000000000000000000000000
···1+import Data.Maybe
2+3+findInvalid :: [Int] -> [Int] -> Int
4+findInvalid _ [] = error "invalid"
5+findInvalid preamble (x : xs) = if x `elem` valid preamble then findInvalid (x : init preamble) xs else x
6+7+valid :: [Int] -> [Int]
8+valid preamble = [(preamble !! i) + (preamble !! j) | i <- [0..23], j <- [i+1..24]]
9+10+rangeOf :: Int -> [Int] -> [Int]
11+rangeOf x xs = fromMaybe (rangeOf x (tail xs)) $ findRange x xs 0
12+ where
13+ findRange :: Int -> [Int] -> Int -> Maybe [Int]
14+ findRange t (x : xs) a
15+ | x + a == t = Just [x]
16+ | x + a < t = (x :) <$> findRange t xs (x + a)
17+ | otherwise = Nothing
18+19+main :: IO ()
20+main = do
21+ numbers <- fmap read . lines <$> getContents :: IO [Int]
22+ let (preamble, contents) = splitAt 25 numbers
23+ invalid = findInvalid (reverse preamble) contents
24+ range = rangeOf invalid numbers
25+ in print $ minimum range + maximum range