Files
newt/aoc2024/Day17.newt
Steve Dunham d6156ebc79 Fix aoc2024 build
- Holes are no longer allowed when building executables
- Stack overflow in mapMaybe (Day15)
2025-04-10 08:50:52 -04:00

138 lines
4.0 KiB
Agda
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module Day17
import Prelude
import Node
import Aoc
import Parser
ptype BigInt
pfunc itobi : Int BigInt := `(x) => BigInt(x)`
pfunc bitoi : BigInt Int := `(x) => Number(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 compare a b = jsCompare a b
data Machine : U where
M : BigInt BigInt BigInt List Int Int SnocList Int Machine
preg : Parser BigInt
preg = do
token "Register"
any
token ":"
n <- number
match '\n'
pure $ itobi n
pprog : Parser (List Int)
pprog = do
token "Program:"
n <- number
ns <- many $ match ',' >> number
many $ match '\n'
pure $ n :: ns
pmachine : Parser Machine
pmachine = do
a <- preg
b <- preg
c <- preg
many $ match '\n'
prog <- pprog
pure $ M a b c prog 0 Lin
infixl 7 _**_ _|_ _^_ _%_ _>>>_
pfunc _**_ : Int Int Int := `(x,y) => x ** y`
pfunc _>>>_ : BigInt BigInt BigInt := `(x,y) => x >> y`
pfunc _%_ : BigInt BigInt BigInt := `(x,y) => x % y`
pfunc bxor : BigInt BigInt BigInt := `(x,y) => x ^ y`
step : Machine -> Machine
step mach@(M a b c mem ip out) =
let ip' = cast ip in
let (Just ins) = getAt ip' mem | _ => mach in
let (Just op) = getAt (S ip') mem | _ => mach in
case ins of
0 => let a = a >>> combo op in step (M a b c mem (ip + 2) out)
1 => let b = bxor b (itobi op) in step (M a b c mem (ip + 2) out)
2 => let b = combo op % itobi 8 in step (M a b c mem (ip + 2) out)
3 => if a == itobi 0 then step (M a b c mem (ip + 2) out) else step (M a b c mem op out)
4 => let b = bxor b c in step (M a b c mem (ip + 2) out)
5 => let o = combo op % itobi 8 in step (M a b c mem (ip + 2) (out :< bitoi o))
6 => let b = a >>> combo op in step (M a b c mem (ip + 2) out)
7 => let c = a >>> combo op in step (M a b c mem (ip + 2) out)
_ => mach
where
combo : Int BigInt
combo 4 = a
combo 5 = b
combo 6 = c
combo n = itobi n
Cand : U
Cand = BigInt × SnocList Int × List Int
part2 : Machine -> Maybe BigInt
part2 mach@(M a b c mem ip out) = go ((itobi 0,(Lin <>< mem), Nil) :: Nil)
where
cands : List BigInt
cands = map itobi (0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: Nil)
matches : List Int BigInt Bool
matches want a =
let (M _ b c mem ip out) = step (M a b c mem ip Lin) in
let out = out <>> Nil in
out == want
chain : (Int Maybe Int) List Int Maybe Int
chain f Nil = Nothing
chain f (x :: xs) = case f x of
Just a => Just a
Nothing => chain f xs
go : List Cand Maybe BigInt
go Nil = Nothing
go ((a, Lin, acc) :: _) = Just a
go ((a, xs :< x, acc) :: todo) =
let next = filter (matches (x :: acc)) $ map (_+_ (a * itobi 8)) cands in
go (map (\a => (a, xs, x :: acc)) next ++ todo)
render : SnocList Int String
render out = go out Nil
where
go : SnocList Int List Char String
go Lin chars = pack $ tail chars
go (xs :< x) acc = go xs (',' :: chr (x + 48) :: acc)
run : String -> IO Unit
run fn = do
putStrLn fn
text <- readFile fn
let (Right (mach, Nil)) = pmachine (unpack text)
| (Right (_, cs)) => putStrLn $ "extra: " ++ pack cs
| _ => putStrLn "parse error"
let (M a b c mem ip out) = (step mach)
putStrLn $ "part1 " ++ render out
let (Just p2) = part2 mach | Nothing => putStrLn "fail"
putStrLn $ "part2 " ++ show p2
putStrLn ""
main : IO Unit
main = do
run "aoc2024/day17/eg.txt"
run "aoc2024/day17/eg2.txt"
run "aoc2024/day17/input.txt"