Files
newt/aoc2024/Day13.newt
2024-12-13 08:02:43 -08:00

103 lines
2.6 KiB
Agda
Raw Blame History

module Day13
import Prelude
import Node
import Aoc
import Parser
Point : U
Point = Int × Int
instance Add Point where
(a,b) + (c,d) = (a + c, b + d)
instance Sub Point where
(a,b) - (c,d) = (a - c, b - d)
instance Ord Point where
(a,b) < (c,d) = a < c || a == c && b < d
instance Eq Point where
(a,b) == (c,d) = a == c && b == d
token : String Parser Unit
token str = string str >> ws
data Machine : U where
MkMachine : Point Point Point Machine
-- need Either parser..
parseButton : Parser Point
parseButton = do
token "Button"
any
token ":"
token "X+"
x <- number
token ","
token "Y+"
y <- number
match '\n'
pure (x,y)
parsePrize : Parser Point
parsePrize = do
token "Prize:"
token "X="
x <- number
token ","
token "Y="
y <- number
match '\n'
pure (x,y)
pMachine : Parser Machine
pMachine = MkMachine <$> parseButton <*> parseButton <*> parsePrize <* many (match '\n')
-- TODO should be a proper primitive, so we can have literals (also need Double)
ptype BigInt
pfunc itobi : Int BigInt := `(x) => BigInt(x)`
pfunc addbi : BigInt BigInt BigInt := `(a,b) => a + b`
pfunc subbi : BigInt BigInt BigInt := `(a,b) => a - b`
pfunc mulbi : BigInt BigInt BigInt := `(a,b) => a * b`
pfunc divbi : BigInt BigInt BigInt := `(a,b) => a / b`
instance Mul BigInt where a * b = mulbi a b
instance Div BigInt where a / b = divbi a b
instance Add BigInt where a + b = addbi a b
instance Sub BigInt where a - b = subbi a b
instance Cast Int BigInt where cast x = itobi x
instance Eq BigInt where a == b = jsEq a b
instance Show BigInt where show = jsShow
instance Ord BigInt where a < b = jsLT a b
calcCost : BigInt Machine Maybe BigInt
calcCost extra (MkMachine (ax, ay) (bx, by) (px, py)) =
let px = itobi px + extra
py = itobi py + extra
b = (px * itobi ay - py * itobi ax) / (itobi ay * itobi bx - itobi by * itobi ax)
a = (px - itobi bx * b) / itobi ax
in if a * itobi ax + b * itobi bx == px && a * itobi ay + b * itobi by == py
then Just (a * itobi 3 + b) else Nothing
run : String -> IO Unit
run fn = do
putStrLn fn
text <- readFile fn
let (Right (machines,_)) = some pMachine $ unpack text | _ => putStrLn "Parse Error"
let extra = itobi 0
let p1 = foldl _+_ (itobi 0) $ mapMaybe (calcCost extra) machines
putStrLn $ "part1 " ++ show p1
let extra = itobi 10000000 * itobi 1000000
let p2 = foldl _+_ (itobi 0) $ mapMaybe (calcCost extra) machines
putStrLn $ "part2 " ++ show p2
main : IO Unit
main = do
run "aoc2024/day13/eg.txt"
run "aoc2024/day13/input.txt"