-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
91 lines (73 loc) · 2.16 KB
/
run.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
import AoC.Parse
import Data.Ratio ((%), denominator, numerator)
import Data.Void (Void)
import Data.List.Split (splitOn)
import qualified Data.Matrix as M
import Text.Megaparsec
import Text.Megaparsec.Char
type N = Integer
type InputRow = ((N, N), (N, N), (N, N))
type Input = [InputRow]
type Parser = Parsec Void String
buttonP :: Parser (N, N)
buttonP = do
_ <- string "Button "
_ <- anySingle
_ <- string ": X+"
x <- numP @N
_ <- string ", Y+"
y <- numP @N
pure (x, y)
prizeP :: Parser (N, N)
prizeP = do
_ <- string "Prize: X="
x <- numP @N
_ <- string ", Y="
y <- numP @N
pure (x, y)
parse :: [String] -> InputRow
parse = \[a, b, p] ->
fromRight $ (,,) <$> runParser buttonP "a" a
<*> runParser buttonP "b" b
<*> runParser prizeP "p" p
fromRight :: Show a => Either a b -> b
fromRight = \case Right x -> x
Left e -> error $ show e
parseAll :: String -> Input
parseAll = map Main.parse . splitOn [""] . lines
solve :: Bool -> InputRow -> Maybe (N, N)
solve limit ((x11, x12), (x21, x22), (p1, p2)) =
let f = (% 1)
m = M.fromLists [[f x11, f x21], [f x12, f x22]]
p = M.fromLists [[f p1], [f p2]]
in case M.inverse m of
Left _ -> Nothing
Right m' | [a, b] <- M.toList $ m' `M.multStd` p
, denominator a == 1
, denominator b == 1
, not limit || a <= 100
, not limit || b <= 100
-> Just (numerator a, numerator b)
_ -> Nothing
cost :: Bool -> InputRow -> N
cost limit =
maybe 0 (\(a, b) -> 3 * a + b) . solve limit
part1 :: Input -> N
part1 = sum . map (cost True)
part2 :: Input -> N
part2 = sum . map (cost False) . map stupidIncrement
where stupidIncrement (a, b, (px, py)) = (a, b, (px + 10000000000000, py + 10000000000000))
main :: IO ()
main = main' "input.txt"
exampleMain :: IO ()
exampleMain = main' "example.txt"
main' :: FilePath -> IO ()
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)