···11+import System.Environment (getArgs)
22+33+p1 l = head [a * b | a <- l, b <- l, a + b == 2020]
44+55+p2 l = head [a * b * c | a <- l, b <- l, c <- l, a + b + c == 2020]
66+77+main = do
88+ args <- getArgs
99+ n <- case args of
1010+ ["-"] -> getContents
1111+ [file] -> readFile file
1212+ let f = map read $ lines n
1313+ print $ p1 f
1414+ print $ p2 f
+27
src/2020/02.lhs
···11+import Data.Bits (xor)
22+import Data.List.Split (splitOn)
33+import System.Environment (getArgs)
44+55+parse i = (read l, read h, c', p)
66+ where
77+ [r, c, p] = splitOn " " i
88+ [l, h] = splitOn "-" r
99+ c' = head c
1010+1111+p1 = length . filter id . map solve
1212+ where
1313+ solve (l, u, c, p) = all ($ length $ filter (== c) p) [(>= l), (<= u)]
1414+1515+p2 = length . filter id . map solve
1616+ where
1717+ solve (l, u, c, p) = foldl1 xor $ map ((== c) . (p !!) . subtract 1) [l, u]
1818+1919+main = do
2020+ args <- getArgs
2121+ n <- case args of
2222+ ["-"] -> getContents
2323+ [file] -> readFile file
2424+ let f = map parse $ lines n
2525+ print $ p1 f
2626+ print $ p2 f
2727+
+27
src/2020/03.lhs
···11+import System.Environment (getArgs)
22+33+countTrees right down ls = go (map cycle ls)
44+ where
55+ go [] = 0
66+ go remaining@(r : rs) =
77+ fromEnum (head r == '#') + go (map (drop right) (drop down remaining))
88+99+p1 = countTrees 3 1
1010+1111+p2 n =
1212+ product
1313+ [ countTrees 1 1 n,
1414+ countTrees 3 1 n,
1515+ countTrees 5 1 n,
1616+ countTrees 7 1 n,
1717+ countTrees 1 2 n
1818+ ]
1919+2020+main = do
2121+ args <- getArgs
2222+ n <- case args of
2323+ ["-"] -> getContents
2424+ [file] -> readFile file
2525+ let f = lines n
2626+ print $ p1 f
2727+ print $ p2 f
+84
src/2020/04.lhs
···11+module Main where
22+33+import Data.Char (isDigit, isHexDigit)
44+import Data.Map.Strict (Map, (!))
55+import qualified Data.Map.Strict as Map
66+import System.Environment (getArgs)
77+import Text.ParserCombinators.Parsec
88+99+bet k (l, u) = k >= l && k <= u
1010+1111+right (Right b) = b
1212+1313+requiredFields = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
1414+1515+eyeColors = ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
1616+1717+block = cell `sepBy` oneOf " \n"
1818+1919+cell = do
2020+ tag <- many lower
2121+ char ':'
2222+ rest <- many (alphaNum <|> char '#')
2323+ return (tag, rest)
2424+2525+parseInput :: String -> Either ParseError (Map String String)
2626+parseInput s = Map.fromList <$> parse block "input" s
2727+2828+doCheck :: Map String String -> Bool
2929+doCheck ls = all (`Map.member` ls) requiredFields
3030+3131+validByr s = bet (read s :: Int) (1920, 2002)
3232+3333+validIyr s = bet (read s :: Int) (2010, 2020)
3434+3535+validEyr s = bet (read s :: Int) (2020, 2030)
3636+3737+validEcl = flip elem eyeColors
3838+3939+validPid s = length s == 9 && all isDigit s
4040+4141+validHcl ('#' : rest) = length rest == 6 && all isHexDigit rest
4242+validHcl _ = False
4343+4444+validHgt s =
4545+ let value = takeWhile isDigit s
4646+ unit = dropWhile isDigit s
4747+ height = (read value :: Int, unit)
4848+ in case height of
4949+ (v, "cm") -> bet v (150, 193)
5050+ (v, "in") -> bet v (59, 76)
5151+ _ -> False
5252+5353+doValidate :: Map String String -> Bool
5454+doValidate map = all (\(s, v) -> v $ map ! s) ls
5555+ where
5656+ ls =
5757+ [ ("byr", validByr),
5858+ ("iyr", validIyr),
5959+ ("eyr", validEyr),
6060+ ("hgt", validHgt),
6161+ ("hcl", validHcl),
6262+ ("ecl", validEcl),
6363+ ("pid", validPid)
6464+ ]
6565+6666+parseLines :: [String] -> [String]
6767+parseLines allLines = unwords first : next
6868+ where
6969+ (first, rest) = break null allLines
7070+ next = if null rest then [] else parseLines (tail rest)
7171+7272+p1 = length . filter doCheck
7373+7474+p2 = length . filter doValidate . filter doCheck
7575+7676+main = do
7777+ args <- getArgs
7878+ n <- case args of
7979+ ["-"] -> getContents
8080+ [file] -> readFile file
8181+ let f = parseLines $ lines n
8282+ let blocks = map (right . parseInput) f
8383+ print $ p1 blocks
8484+ print $ p2 blocks
+33
src/2020/05.lhs
···11+module Main where
22+33+import Data.Char (digitToInt)
44+import Data.List (sort)
55+import System.Environment (getArgs)
66+77+binaryToInt = foldl (\a x -> a * 2 + digitToInt x) 0
88+99+doValidate = binaryToInt . map readBin
1010+1111+readBin s
1212+ | s `elem` "FL" = '0'
1313+ | otherwise = '1'
1414+1515+p1 = maximum . sort . map doValidate
1616+1717+p2 =
1818+ (+ 1)
1919+ . fst
2020+ . head
2121+ . dropWhile ((== 1) . uncurry subtract)
2222+ . (zip <*> tail)
2323+ . sort
2424+ . map doValidate
2525+2626+main = do
2727+ args <- getArgs
2828+ n <- case args of
2929+ ["-"] -> getContents
3030+ [file] -> readFile file
3131+ let f = lines n
3232+ print $ p1 f
3333+ print $ p2 f
+17
src/2020/06.lhs
···11+import Data.List.Split (splitOn)
22+import Data.Set (Set)
33+import qualified Data.Set as Set
44+import System.Environment (getArgs)
55+66+p1 = sum . map (Set.size . Set.fromList . filter (/= '\n'))
77+88+p2 = sum . map (Set.size . foldl1 Set.intersection . map Set.fromList . words)
99+1010+main = do
1111+ args <- getArgs
1212+ n <- case args of
1313+ ["-"] -> getContents
1414+ [file] -> readFile file
1515+ let f = splitOn "\n\n" n
1616+ print $ p1 f
1717+ print $ p2 f
+34
src/2020/07.lhs
···11+import Data.Map (Map)
22+import qualified Data.Map as Map
33+import System.Environment (getArgs)
44+55+myBag = "shiny gold"
66+77+parseContained [] = []
88+parseContained ("no" : _) = []
99+parseContained (count : b : c : _ : rest) = (read count, unwords [b, c]) : parseContained rest
1010+1111+parseLine s = (leadingBag, parseContained trailingBags)
1212+ where
1313+ leadingBag = unwords (take 2 s)
1414+ trailingBags = drop 4 s
1515+1616+canContain m outer = myBag `elem` inners || any (canContain m) inners
1717+ where
1818+ inners = map snd $ m Map.! outer
1919+2020+countNested s m = foldl (\acc (c, b) -> acc + c * (1 + countNested b m)) 0 $ m Map.! s
2121+2222+p1 q = length $ filter (canContain q . fst) $ Map.toList q
2323+2424+p2 = countNested myBag
2525+2626+main = do
2727+ args <- getArgs
2828+ n <- case args of
2929+ ["-"] -> getContents
3030+ [file] -> readFile file
3131+ let f = map (parseLine . words) $ lines n
3232+ let q = Map.fromList f
3333+ print $ p1 q
3434+ print $ p2 q
+53
src/2020/08.lhs
···11+module Main where
22+33+import Data.Map (Map)
44+import qualified Data.Map as Map
55+import Data.Set (Set)
66+import qualified Data.Set as Set
77+import System.Environment (getArgs)
88+99+type Op = (String, Int)
1010+1111+parseLine :: [String] -> Op
1212+parseLine [s, j] = (s, read (dropWhile (== '+') j))
1313+1414+run :: Int -> Int -> Set Int -> Map Int Op -> Int
1515+run acc pc visited operations = if Set.member pc visited then acc else handleCase
1616+ where
1717+ visited' = Set.insert pc visited
1818+ handleCase =
1919+ case Map.lookup pc operations of
2020+ Just ("acc", v) -> run (acc + v) (pc + 1) visited' operations
2121+ Just ("nop", _) -> run acc (pc + 1) visited' operations
2222+ Just ("jmp", j) -> run acc (pc + j) visited' operations
2323+ _ -> acc
2424+2525+doesEnd :: Int -> Int -> Set Int -> Map Int Op -> Bool
2626+doesEnd acc pc visited operations = not (Set.member pc visited) && handleCase
2727+ where
2828+ visited' = Set.insert pc visited
2929+ handleCase =
3030+ case Map.lookup pc operations of
3131+ Just ("acc", v) -> doesEnd (acc + v) (pc + 1) visited' operations
3232+ Just ("nop", _) -> doesEnd acc (pc + 1) visited' operations
3333+ Just ("jmp", j) -> doesEnd acc (pc + j) visited' operations
3434+ _ -> True -- pc has crossed the end!
3535+3636+genAll :: [Op] -> [[Op]]
3737+genAll [] = []
3838+genAll (n@("nop", v) : rest) = (("jmp", v) : rest) : map (n :) (genAll rest)
3939+genAll (j@("jmp", v) : rest) = (("nop", v) : rest) : map (j :) (genAll rest)
4040+genAll (acc : rest) = map (acc :) $ genAll rest
4141+4242+p1 = run 0 0 mempty . Map.fromList . zip [0 ..]
4343+4444+p2 = p1 . head . filter (doesEnd 0 0 mempty . Map.fromList . zip [0 ..]) . genAll
4545+4646+main = do
4747+ args <- getArgs
4848+ n <- case args of
4949+ ["-"] -> getContents
5050+ [file] -> readFile file
5151+ let f = map (parseLine . words) $ lines n
5252+ print $ p1 f
5353+ print $ p2 f
+30
src/2020/09.lhs
···11+import Data.Bifunctor
22+import Data.List (find, inits, sort, tails)
33+import System.Environment (getArgs)
44+55+sublists = concatMap inits . tails
66+77+windows m = foldr (zipWith (:)) (repeat []) . take m . tails
88+99+doCheck preamble target = target `elem` [x + y | x <- preamble, y <- preamble, x /= y]
1010+1111+checkAll = zipWith (\p t -> (t, doCheck p t))
1212+1313+findWeakness subs target = minimum t + maximum t
1414+ where
1515+ Just t = find ((== target) . sum) subs
1616+1717+p1 f = find (not . snd) $ checkAll (windows 25 f) (drop 25 f)
1818+1919+p2 f = findWeakness (sublists f) target
2020+ where
2121+ Just (target, _) = p1 f
2222+2323+main = do
2424+ args <- getArgs
2525+ n <-
2626+ map read . lines <$> case args of
2727+ ["-"] -> getContents
2828+ [file] -> readFile file
2929+ print $ p1 n
3030+ print $ p2 n
+24
src/2020/10.lhs
···11+import Control.Monad.Memo
22+import Data.List (sort)
33+import System.Environment (getArgs)
44+55+p1 s = product $ ($ q s) <$> [length . filter (== 1), length . filter (== 3)]
66+ where
77+ q = zipWith subtract <*> tail
88+99+p2 top s = startEvalMemo $ go 0
1010+ where
1111+ go c
1212+ | c == top = return 1
1313+ | otherwise = sum <$> mapM (memo go) (filter (`elem` s) $ map (+ c) [1, 2, 3])
1414+1515+main = do
1616+ args <- getArgs
1717+ n <-
1818+ map read . lines <$> case args of
1919+ ["-"] -> getContents
2020+ [file] -> readFile file
2121+ let top = maximum n + 3
2222+ ls = sort (0 : top : n)
2323+ print $ p1 ls
2424+ print $ p2 top ls
+79
src/2020/11.lhs
···11+import Data.List (sortOn)
22+import Data.Map (Map, (!))
33+import qualified Data.Map as Map
44+import Data.Maybe
55+import System.Environment (getArgs)
66+77+dirs =
88+ [ (-1, -1),
99+ (0, -1),
1010+ (1, -1),
1111+ (-1, 0),
1212+ (1, 0),
1313+ (-1, 1),
1414+ (0, 1),
1515+ (1, 1)
1616+ ]
1717+1818+makeGrid s = (grid, width, height)
1919+ where
2020+ rows = lines s
2121+ grid = Map.fromList [((x, y), a) | (y, row) <- zip [0 ..] rows, (x, a) <- zip [0 ..] row]
2222+ width = length (head rows)
2323+ height = length rows
2424+2525+adjs1 m pt = length $ filter (== '#') $ mapMaybe ((`Map.lookup` m) . add pt) dirs
2626+2727+inGrid (x, y) w h = x < w && x >= 0 && y < h && y >= 0
2828+2929+add (x, y) (a, b) = (x + a, y + b)
3030+3131+-- [f, f.f, f.f.f, ...]
3232+repeatF f = f : map (f .) (repeatF f)
3333+3434+bet k (l, u) = k >= l && k <= u
3535+3636+inside (p, q) (r, s) (a, b) = bet a (p, r) && bet b (q, s)
3737+3838+adjs2 grid pt w h =
3939+ length $
4040+ filter ((== '#') . head) $
4141+ filter (not . null) $
4242+ map
4343+ ( dropWhile (== '.')
4444+ . map (grid !)
4545+ . takeWhile (inside (0, 0) (w - 1, h - 1))
4646+ . map ($ pt)
4747+ . repeatF
4848+ . add
4949+ )
5050+ dirs
5151+5252+rule1 w h m pt@(x, y) = if as == 0 then '#' else 'L'
5353+ where
5454+ as = adjs2 m pt w h
5555+5656+rule2 w h m pt@(x, y) = if as >= 5 then 'L' else '#'
5757+ where
5858+ as = adjs2 m pt w h
5959+6060+doStep w h m = Map.mapWithKey fn m
6161+ where
6262+ fn k 'L' = rule1 w h m k
6363+ fn k '#' = rule2 w h m k
6464+ fn k '.' = '.'
6565+6666+stepWhile prev w h
6767+ | prev == next = next
6868+ | otherwise = stepWhile next w h
6969+ where
7070+ next = doStep w h prev
7171+7272+main = do
7373+ args <- getArgs
7474+ n <- case args of
7575+ ["-"] -> getContents
7676+ [file] -> readFile file
7777+ let (grid, width, height) = makeGrid n
7878+ let solve1 = stepWhile grid width height
7979+ print $ length $ filter ((== '#') . snd) $ Map.toList solve1
+46
src/2020/12.lhs
···11+import System.Environment (getArgs)
22+33+parseLine s = (head s, read (tail s) :: Float)
44+55+rotate (x, y) t = (nx, ny)
66+ where
77+ nx = x * cos (pi * t / 180) - y * sin (pi * t / 180)
88+ ny = x * sin (pi * t / 180) + y * cos (pi * t / 180)
99+1010+p1 ls = sum $ map (round . abs) [fx, fy]
1111+ where
1212+ (fx, fy, _) = foldl fn (0.0, 0.0, 0.0) ls
1313+ fn (x, y, rot) ('N', v) = (x, y + v, rot)
1414+ fn (x, y, rot) ('E', v) = (x + v, y, rot)
1515+ fn (x, y, rot) ('W', v) = (x - v, y, rot)
1616+ fn (x, y, rot) ('S', v) = (x, y - v, rot)
1717+ fn (x, y, rot) ('R', v) = (x, y, rot - v)
1818+ fn (x, y, rot) ('L', v) = (x, y, rot + v)
1919+ fn (x, y, rot) ('F', v) = (nx, ny, rot)
2020+ where
2121+ nx = x + v * cos (pi * rot / 180)
2222+ ny = y + v * sin (pi * rot / 180)
2323+2424+p2 (sx, sy) ls = sum $ map (round . abs) [fx, fy]
2525+ where
2626+ (fx, fy, _, _) = foldl fn (0.0, 0.0, sx, sy) ls
2727+ fn (x, y, wx, wy) ('N', v) = (x, y, wx, wy + v)
2828+ fn (x, y, wx, wy) ('E', v) = (x, y, wx + v, wy)
2929+ fn (x, y, wx, wy) ('W', v) = (x, y, wx - v, wy)
3030+ fn (x, y, wx, wy) ('S', v) = (x, y, wx, wy - v)
3131+ fn (x, y, wx, wy) ('R', v) = (x, y, nwx, nwy)
3232+ where
3333+ (nwx, nwy) = rotate (wx, wy) (negate v)
3434+ fn (x, y, wx, wy) ('L', v) = (x, y, nwx, nwy)
3535+ where
3636+ (nwx, nwy) = rotate (wx, wy) v
3737+ fn (x, y, wx, wy) ('F', v) = (x + v * wx, y + v * wy, wx, wy)
3838+3939+main = do
4040+ args <- getArgs
4141+ n <-
4242+ map parseLine . lines <$> case args of
4343+ ["-"] -> getContents
4444+ [file] -> readFile file
4545+ print $ p1 n
4646+ print $ p2 (10.0, 1.0) n
+50
src/2020/13.lhs
···11+import Control.Monad (ap, zipWithM)
22+import Data.Bifunctor
33+import Data.List (sortOn)
44+import Data.List.Split
55+import Data.Tuple
66+import System.Environment (getArgs)
77+88+egcd _ 0 = (1, 0)
99+egcd a b = (t, s - q * t)
1010+ where
1111+ (s, t) = egcd b r
1212+ (q, r) = a `quotRem` b
1313+1414+modInv a b =
1515+ case egcd a b of
1616+ (x, y)
1717+ | a * x + b * y == 1 -> Just x
1818+ | otherwise -> Nothing
1919+2020+-- from rosetta code
2121+chineseRemainder ls =
2222+ zipWithM modInv crtModulii modulii
2323+ >>= (Just . (`mod` modPI) . sum . zipWith (*) crtModulii . zipWith (*) residues)
2424+ where
2525+ residues = map fst ls
2626+ modulii = map snd ls
2727+ modPI = product modulii
2828+ crtModulii = (modPI `div`) <$> modulii
2929+3030+earliest start ls = t * b
3131+ where
3232+ (t, b) = minimum $ map swap $ zip `ap` map (mod start) $ ls
3333+3434+p1 n = earliest (negate start) departs
3535+ where
3636+ start = read (head n) :: Int
3737+ departs = map read $ filter (/= "x") $ splitOn "," (last n)
3838+3939+p2 n = chineseRemainder offs
4040+ where
4141+ offs = map (bimap negate read) $ filter ((/= "x") . snd) $ zip [0 ..] $ splitOn "," (last n)
4242+4343+main = do
4444+ args <- getArgs
4545+ n <-
4646+ lines <$> case args of
4747+ ["-"] -> getContents
4848+ [file] -> readFile file
4949+ print $ p1 n
5050+ print $ p2 n
+78
src/2020/14.lhs
···11+module Main where
22+33+import Data.Bifunctor (bimap)
44+import Data.Char
55+import Data.Either
66+import Data.Map (Map)
77+import qualified Data.Map as Map
88+import Data.Strings
99+import Numeric (readInt, showIntAtBase)
1010+import System.Environment (getArgs)
1111+import Text.Parsec.Char
1212+import Text.ParserCombinators.Parsec
1313+1414+data Stmt = Mask String | Mem Int Int deriving (Show)
1515+1616+parseMask :: Parser Stmt
1717+parseMask = string "mask = " >> Mask <$> many anyChar
1818+1919+parseNumber :: Parser Int
2020+parseNumber = read <$> many1 digit
2121+2222+parseMem :: Parser Stmt
2323+parseMem = Mem <$ string "mem[" <*> parseNumber <* string "] = " <*> parseNumber
2424+2525+parseLine :: Parser Stmt
2626+parseLine = try parseMask <|> parseMem
2727+2828+applyMask :: Int -> String -> Int
2929+applyMask v m = fst $ head $ readInt 2 (`elem` "01") digitToInt wm
3030+ where
3131+ bv = strPadLeft '0' 36 $ showIntAtBase 2 intToDigit v ""
3232+ wm = zipWith fn bv m
3333+ fn o 'X' = o
3434+ fn _ '1' = '1'
3535+ fn _ '0' = '0'
3636+3737+runProgram :: [Stmt] -> Int
3838+runProgram ls = sum regs
3939+ where
4040+ (mask, regs) = foldl fn ("", Map.empty) ls
4141+ fn (_, regs) (Mask s) = (s, regs)
4242+ fn (m, regs) (Mem idx val) = (m, Map.insert idx nval regs)
4343+ where
4444+ nval = applyMask val m
4545+4646+floatings :: String -> [String]
4747+floatings [] = [[]]
4848+floatings ('X' : xs) = floatings xs >>= (\b -> ['0' : b, '1' : b])
4949+floatings (x : xs) = map (x :) $ floatings xs
5050+5151+genIdxs :: Int -> String -> [Int]
5252+genIdxs v m = map (fst . head . readInt 2 (`elem` "01") digitToInt) (floatings wm)
5353+ where
5454+ bv = strPadLeft '0' 36 $ showIntAtBase 2 intToDigit v ""
5555+ wm = zipWith fn bv m
5656+ fn o '0' = o
5757+ fn _ '1' = '1'
5858+ fn _ 'X' = 'X'
5959+6060+v2chip :: [Stmt] -> Int
6161+v2chip ls = sum regs
6262+ where
6363+ (mask, regs) = foldl fn ("", Map.empty) ls
6464+ fn (_, regs) (Mask s) = (s, regs)
6565+ fn (m, regs) (Mem idx val) = (m, nmap)
6666+ where
6767+ idxs = genIdxs idx m
6868+ nmap = flip Map.union regs $ Map.fromList $ map (,val) idxs
6969+7070+main = do
7171+ args <- getArgs
7272+ n <-
7373+ rights . map (parse parseLine "main") . lines <$> case args of
7474+ ["-"] -> getContents
7575+ [file] -> readFile file
7676+ print $ runProgram n
7777+ print $ v2chip n
7878+
+25
src/2020/15.lhs
···11+module Main where
22+33+import Data.List.Split
44+import qualified Data.Map as M
55+import Data.Maybe
66+import System.Environment (getArgs)
77+88+run ls start input = fst $ foldl fn (start, startMap) ls
99+ where
1010+ startMap = M.fromList $ zip input [1 ..]
1111+ fn (last, seen) i = (i - last', seen')
1212+ where
1313+ last' = fromMaybe i (M.lookup last seen)
1414+ seen' = M.insert last i seen
1515+1616+main = do
1717+ args <- getArgs
1818+ n <-
1919+ map read . splitOn "," <$> case args of
2020+ ["-"] -> getContents
2121+ [file] -> readFile file
2222+2323+ -- holy off-by-one errors
2424+ print $ run [8 .. 2020 - 1] 0 n
2525+ print $ run [8 .. 30000000 - 1] 0 n
+72
src/2020/16.lhs
···11+module Main where
22+33+import Control.Monad (liftM2)
44+import Data.Function (on)
55+import Data.List (sortBy)
66+import Data.List.Split (splitOn)
77+import Data.Map (Map, (!))
88+import qualified Data.Map as Map
99+import Data.Set (Set, (\\))
1010+import qualified Data.Set as Set
1111+import System.Environment (getArgs)
1212+import Text.Parsec.Char
1313+import Text.ParserCombinators.Parsec
1414+1515+type Constraint = ((Int, Int), (Int, Int))
1616+1717+parseNumber = read <$> many1 digit
1818+1919+parseBound = (,) <$> parseNumber <* char '-' <*> parseNumber
2020+2121+parseConstraint = (,) <$> parseBound <* string " or " <*> parseBound
2222+2323+parseConstraints = (manyTill anyChar (string ": ") *> parseConstraint) `sepBy` newline
2424+2525+parseTicket = parseNumber `sepBy` char ','
2626+2727+parseNears = string "nearby tickets:" *> newline *> parseTicket `sepBy` newline
2828+2929+parseMine = string "your ticket:" *> newline *> parseTicket
3030+3131+parseInput s = do
3232+ let (p : q : r : _) = splitOn "\n\n" s
3333+ (,,)
3434+ <$> parse parseConstraints "cs" p
3535+ <*> parse parseMine "mine" q
3636+ <*> parse parseNears "nears" r
3737+3838+bet k (l, u) = k >= l && k <= u
3939+4040+(|+) = liftM2 (||)
4141+4242+within (a, b) = flip bet a |+ flip bet b
4343+4444+findInvalid cs = filter (\t -> not $ any (`within` t) cs)
4545+4646+isValid cs = all (\t -> any (`within` t) cs)
4747+4848+validFor :: [Constraint] -> [Int] -> Set Int
4949+validFor cs items = foldl1 Set.intersection (map vcf items)
5050+ where
5151+ vcf i = Set.fromList [idx | (cons, idx) <- zip cs [0 ..], cons `within` i]
5252+5353+main = do
5454+ args <- getArgs
5555+ n <-
5656+ parseInput <$> case args of
5757+ ["-"] -> getContents
5858+ [file] -> readFile file
5959+ let Right (cs, mine, nears) = n
6060+ validTickets = filter (isValid cs) nears
6161+ cols = map (\i -> map (!! i) validTickets) [0 .. length cs - 1]
6262+ possibleCons = sortBy (compare `on` (Set.size . snd)) $ zip [0 ..] $ map (validFor cs) cols
6363+ corresp =
6464+ Map.fromList $
6565+ map (\(i, v) -> (head $ Set.toList v, i)) $
6666+ (head possibleCons :) $
6767+ zipWith fn <*> tail $
6868+ possibleCons
6969+ where
7070+ fn (i, s) (i', s') = (i', s' \\ s)
7171+ print $ sum $ concatMap (findInvalid cs) nears
7272+ print $ product $ map ((mine !!) . (corresp !)) [0 .. 5]
+52
src/2020/17.lhs
···11+module Main where
22+33+import Control.Monad
44+import Data.Map (Map)
55+import qualified Data.Map as M
66+import Data.Maybe
77+import System.Environment (getArgs)
88+99+toBool '#' = True
1010+toBool '.' = False
1111+1212+gridMap s =
1313+ M.fromList
1414+ [ ((x, y, 0, 0), toBool a)
1515+ | (y, row) <- zip [0 ..] rows,
1616+ (x, a) <- zip [0 ..] row
1717+ ]
1818+ where
1919+ rows = lines s
2020+2121+around (x, y, z, w) =
2222+ [ (x + x', y + y', z + z', w + w')
2323+ | x' <- [-1 .. 1],
2424+ y' <- [-1 .. 1],
2525+ z' <- [-1 .. 1],
2626+ w' <- [-1 .. 1],
2727+ (x', y', z', w') /= (0, 0, 0, 0)
2828+ ]
2929+3030+convert True 2 = True
3131+convert True 3 = True
3232+convert False 3 = True
3333+convert _ _ = False
3434+3535+doStep m = M.mapWithKey fn $ m <> M.fromList [(p, False) | p <- concatMap around (M.keys m)]
3636+ where
3737+ fn pos v = convert v n
3838+ where
3939+ n = length $ filter id $ map (fromMaybe False . flip M.lookup m) $ around pos
4040+4141+p1 grid = M.size $ M.filter id (iterate doStep grid !! 6)
4242+4343+p2 grid = M.size $ M.filter id (iterate doStep grid !! 6)
4444+4545+main = do
4646+ args <- getArgs
4747+ n <- case args of
4848+ ["-"] -> getContents
4949+ [file] -> readFile file
5050+ let grid = gridMap n
5151+ print $ p1 grid
5252+ print $ p2 grid