aboutsummaryrefslogtreecommitdiff
path: root/2024/13/solve.hs
blob: 3386f26b9c6509c05dfcac0ce0f360585079c0b7 (plain) (blame)
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
import           Data.Void
import           Prelude                 hiding ( (||) )
import           Text.Megaparsec         hiding ( Pos
                                                , single
                                                )
import           Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer    as L

type Parser = Parsec Void String

data Pos = Pos
  { x :: Int
  , y :: Int
  }
  deriving Show

data Machine = Machine
  { a :: Button
  , b :: Button
  , p :: Prize
  }
  deriving Show

type Button = Pos
type Prize = Pos

signed :: Parser Int
signed = L.signed (pure ()) L.decimal

delim :: Parser ()
delim = many (oneOf " \n\r") *> pure ()

button :: String -> Parser Button
button n = do
  string $ "Button " <> n <> ": X"
  x <- signed
  string ", Y"
  y <- signed
  return $ Pos x y

prize :: Parser Prize
prize = do
  string "Prize: X="
  x <- L.decimal
  string ", Y="
  y <- L.decimal
  return $ Pos x y

machine :: Parser Machine
machine = do
  a <- button "A"
  delim
  b <- button "B"
  delim
  p <- prize
  delim
  return $ Machine a b p

machines :: Parser [Machine]
machines = many machine

single :: Machine -> Int
single m@(Machine { a = Pos ax ay, b = Pos bx by, p = Pos px py }) =
  let d   = ax * by - ay * bx
      aD  = (by * px - bx * py) `div` d
      bD  = (ax * py - ay * px) `div` d
      hit = ax * aD + bx * bD == px && ay * aD + by * bD == py
  in  if hit then aD * 3 + bD else 0

part1 :: [Machine] -> Int
part1 = sum . map single

part2 :: [Machine] -> Int
part2 = part1 . map
  (\(Machine { a, b, p = Pos px py }) ->
    Machine a b (Pos (px + 10000000000000) (py + 10000000000000))
  )

main :: IO ()
main = do
  f <- readFile "input"
  case runParser (machines <* eof) "" f of
    Right ms -> do
      print $ part1 ms
      print $ part2 ms
    Left err -> print $ errorBundlePretty err