Day 13
[advent-of-code-17.git] / src / advent13 / advent13.hs
1 {-# LANGUAGE NegativeLiterals #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE OverloadedStrings #-}
4
5 import Data.Text (Text)
6 import qualified Data.Text as T
7 import qualified Data.Text.IO as TIO
8
9 import Text.Megaparsec
10 import qualified Text.Megaparsec.Lexer as L
11 import Text.Megaparsec.Text (Parser)
12
13 import qualified Control.Applicative as CA
14
15 type ScannerDef = (Integer, Integer)
16 type Scanner = Integer -> Integer
17
18
19 main :: IO ()
20 main = do
21 text <- TIO.readFile "data/advent13.txt"
22 let scannerDefs = successfulParse text
23 print $ part1 scannerDefs
24 print $ part2 scannerDefs
25
26
27 part1 :: [ScannerDef] -> Integer
28 part1 = sum . map (uncurry (*)) . filter (\(d, r) -> scanner d r 0 == 0)
29
30
31 part2 :: [ScannerDef] -> Integer
32 part2 scannerDefs = head $ filter (canPass scanners) [0..]
33 where scanners = scanify scannerDefs
34
35
36 scanify :: [ScannerDef] -> [Scanner]
37 scanify = map (uncurry scanner)
38
39 canPass :: [Scanner] -> Integer -> Bool
40 canPass scannersF t = all (\s -> s t /= 0) scannersF
41
42
43 scanner :: Integer -> Integer -> Integer -> Integer
44 scanner depth range t =
45 let t' = (t + depth) `mod` ((range - 1) * 2)
46 in if t' < range
47 then t'
48 else range - t' - 1 -- t' + (t' - range + 1) * -2
49
50
51 sc :: Parser ()
52 sc = L.space (skipSome spaceChar) CA.empty CA.empty
53
54 lexeme = L.lexeme sc
55 integer = lexeme L.integer
56 symb = L.symbol sc
57
58 scannersP = many scannerP
59
60 scannerP = (,) <$> integer <*> (symb ":" *> integer)
61
62 successfulParse :: Text -> [ScannerDef]
63 successfulParse input =
64 case parse scannersP "input" input of
65 Left err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
66 Right scanners -> scanners