diff --git a/aoc2025/Aoc.newt b/aoc2025/Aoc.newt index 206bff2..a1e418f 100644 --- a/aoc2025/Aoc.newt +++ b/aoc2025/Aoc.newt @@ -6,6 +6,9 @@ import Prelude nums' : String → String → List Int nums' by s = map stringToInt $ filter (_/=_ "") $ split (trim s) by +min : ∀ a. {{Ord a}} → a → a → a +min x y = if x < y then x else y + max : ∀ a. {{Ord a}} → a → a → a max a b = if a < b then b else a diff --git a/aoc2025/Day9.newt b/aoc2025/Day9.newt new file mode 100644 index 0000000..7633067 --- /dev/null +++ b/aoc2025/Day9.newt @@ -0,0 +1,95 @@ +module Day9 + +import Prelude +import Node +import Aoc + +parsePoint : String → Maybe Point +parsePoint text = case split text "," of + a :: b :: Nil => Just (stringToInt a, stringToInt b) + _ => Nothing + +parse : String → List Point +parse text = mapMaybe parsePoint $ split (trim text) "\n" + +abs : Int → Int +abs x = if x < 0 then 0 - x else x + +data Line : U where + VL : (x y1 y2 : Int) → Line + HL : (y x1 x2 : Int) → Line + +instance Show Line where + show (VL x y1 y2) = "VL \{show (x,y1,y2)}" + show (HL x y1 y2) = "HL \{show (x,y1,y2)}" + +data Box = B Int Int Int Int + +instance Show Box where + show (B l r t b) = "Box \{show (l,r,t,b)}" + +area : Box → Int +area (B l r t b) = (abs (l - r) + 1) * (abs (t - b) + 1) + +mkbox : Point → Point → Box +mkbox (a,b) (c,d) = B (min a c) (max a c) (min b d) (max b d) + +boxes : List Point → List Box +boxes pts = go pts Nil + where + go2 : Point → List Point → List Box → List Box + go2 pt (x :: xs) acc = go2 pt xs (mkbox pt x :: acc) + go2 pt _ acc = acc + + go : List Point → List Box → List Box + go (pt :: rest) acc = go rest $ go2 pt rest acc + go Nil acc = acc + +-- line intersects middle of a box +isect : Box → Line → Bool +isect (B l r t b) (VL x y1 y2) = x < r && l < x && y1 < b && t < y2 +isect (B l r t b) (HL y x1 x2) = y < b && t < y && x1 < r && l < x2 + +getLines : List Point → List Line +getLines points = go points Nil + where + go : List Point → List Line → List Line + go ((a,b) :: rest@((c,d) :: _)) acc = + if a == c + then let seg = if b < d then VL a b d else VL a d b in go rest (seg :: acc) + else if b == d then let seg = if a < c then HL b a c else HL b c a in go rest (seg :: acc) + else Nil + go _ acc = acc + +-- I'm assuming the winner isn't a single row/column +part2 : List (Int × Box) → List Line → Int +part2 Nil _ = 0 +part2 ((size, box) :: rest) lines = if checkRec box then size else part2 rest lines + where + winds : Box → Line → Bool + winds (B l r t b) (VL x y1 y2) = + -- pick a point in the middle, the rest is connected because no intersection + if t == b then False else r <= x && y1 < t + 1 && t + 1 < y2 + winds (B l r t b) (HL x y1 y2) = False + + checkRec : Box → Bool + checkRec box = + let (Nothing) = find (isect box) lines | _ => False in + let winding = length' $ filter (winds box) lines in mod winding 2 == 1 + +run : String -> IO Unit +run fn = do + putStrLn fn + text <- readFile fn + let (pts@(a :: _)) = parse text | _ => putStrLn "empty input" + -- printLn pts + let sortBoxes = qsort (\ a b => fst a > fst b) $ map (\box => (area box, box)) $ boxes pts + let ((p1,_) :: _ ) = sortBoxes | _ => printLn "no boxes" + putStrLn $ "part1 \{show p1}" + let vl = getLines $ a :: reverse pts + putStrLn $ "part2 " ++ show (part2 sortBoxes vl) + +main : IO Unit +main = do + run "aoc2025/day9/eg.txt" + run "aoc2025/day9/input.txt" diff --git a/aoc2025/day9/eg.txt b/aoc2025/day9/eg.txt new file mode 100644 index 0000000..c8563ea --- /dev/null +++ b/aoc2025/day9/eg.txt @@ -0,0 +1,8 @@ +7,1 +11,1 +11,7 +9,7 +9,5 +2,5 +2,3 +7,3