Files
newt/aoc2024/Day14.newt

157 lines
4.3 KiB
Agda
Raw 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 Day14
import Prelude
import Node
import Aoc
import Parser
import SortedMap
data Robot : U where
MkBot : Point Point Robot
pint : Parser Int
pint = do
sign <- pure (0 - 1) <* match '-' <|> pure 1
num <- number
pure $ sign * num
ppoint : Parser Point
ppoint = _,_ <$> pint <* match ',' <*> pint
probot : Parser Robot
probot = do
token "p="
p <- ppoint
ws
token "v="
v <- ppoint
ws
many (match '\n')
pure $ MkBot p v
-- TODO make Mod typeclass or something
infixl 7 _%_
pfunc _%_ : Int Int Int := `(x,y) => x % y`
pmod : Int Int Int
pmod a b =
if a < 0 then (a + b * ((0 - a / b) + 1)) % b else a % b
move : Int Int Int Robot Point
move w h time (MkBot (x,y) (dx,dy)) =
-- no HMul yet
-- let (x',y') = trace "to" $ (x,y) + (time * dx, time * dy) in
let x' = pmod (x + time * dx) w
y' = pmod (y + time * dy) h
in (x', y')
count : a. (a Bool) List a Int
count {a} f xs = go xs 0
where
go : List a Int Int
go Nil acc = acc
go (x :: xs) acc = if f x then go xs (acc + 1) else go xs acc
draw' : Int Int SortedMap Point Int IO Unit
draw' w h pts = go 0
where
mkLine : Int Int SnocList Char String
mkLine y x acc = if x == w then pack (acc <>> Nil)
else case lookupMap (x,y) pts of
Nothing => mkLine y (x + 1) (acc :< '.')
_ => mkLine y (x + 1) (acc :< '*')
go : Int IO Unit
go y = if y == h then pure MkUnit else do
putStrLn $ mkLine y 0 Lin
go (y + 1)
draw : Int Int List Point IO Unit
draw w h pts =
let m = foldMap _+_ EmptyMap $ map (flip _,_ 1) pts in draw' w h m
part2 : Int Int List Robot List Point × Int
part2 w h robots = go 1
where
heuristic : Point Bool
heuristic (x,y) = if x < w / 2 then 100 < 2 * x + y else 2 * (x - 50) < y
-- heuristic (x,y) = x == w / 2
go : Int List Point × Int
go t =
let pts = map (move w h t) robots
cnt = count heuristic pts
in if cnt > 20 then (pts, t)
else go (t + 1)
run : String Int Int IO Unit
run fn w h = do
putStrLn fn
text <- readFile fn
let (Right (robots, Nil)) = some probot $ unpack text
| Left msg => putStrLn $ "Parse Error " ++ msg
| Right (robots, rest) => putStrLn $ "stuck at¬" ++ pack rest
let result = map (move w h 100) robots
-- debugLog result
let q1 = count quad1 result
let q2 = count quad2 result
let q3 = count quad3 result
let q4 = count quad4 result
debugLog (q1,q2,q3,q4)
let p1 = q1 * q2 * q3 * q4
putStrLn $ "part1 " ++ show p1
printLn $ count (\ x => True) robots
let scores = collect robots 0 Nil
let stuff = qsort (\ a b => snd a < snd b) $ collect robots 0 Nil
-- debugLog stuff
dump robots stuff 1
where
dump : List Robot List (Int × Int) Int IO Unit
dump robots Nil _ = pure MkUnit
dump robots (((t,cnt) :: xs)) 0 = pure MkUnit
dump robots (((t,cnt) :: xs)) gas = do
printLn t
draw w h $ map (move w h t) robots
printLn ""
dump robots xs (gas - 1)
quad1 : Point Bool
quad1 (x,y) = x < w / 2 && y < h / 2
quad2 : Point Bool
quad2 (x,y) = x > w / 2 && y < h / 2
quad3 : Point Bool
quad3 (x,y) = x > w / 2 && y > h / 2
quad4 : Point Bool
quad4 (x,y) = x < w / 2 && y > h / 2
heuristic : Point Bool
heuristic (x,y) = if x < w / 2 then 100 - 2 * x < y else 2 * x - 100 < y
dist : Point Int
dist (x,y) = let d = if x < w / 2 then y - (h - 2 * x) else y - (h - 2 * (w - x)) in
if d < 0 then 0 - d else d
collect : List Robot Int List (Int × Int) List (Int × Int)
collect robots iter acc =
if iter > w * h then acc else
let pts = map (move w h iter) robots in
-- This heuristic found it, attempting to find an outline of a large tree
-- but the picture looks nothing like that, so I got lucky
-- let cnt = foldl _+_ 0 $ map dist pts in
-- so I'll go with min danger (although it takes 4 * as long)
let q1 = count quad1 pts
q2 = count quad2 pts
q3 = count quad3 pts
q4 = count quad4 pts
cnt = q1 * q2 * q3 * q4 in
collect robots (iter + 1) ((iter,cnt) :: acc)
main : IO Unit
main = do
-- run "aoc2024/day14/eg.txt" 11 7
run "aoc2024/day14/input.txt" 101 103