module Day8

import Prelude
import Node
import Aoc
import SortedMap

Ant : U
Ant = Char × Int × Int

-- This should be a utility...
parse : String → List Ant
parse text = go 0 0 (unpack text) Nil
  where
    -- might as well be tail recursive
    go : Int → Int → List Char → List Ant → List Ant
    go row col Nil ants = ants
    go row col ('\n' :: cs) ants = go (row + 1) 0 cs ants
    go row col (c :: cs) ants = go row (col + 1) cs ((c,row,col) :: ants)

doPair : Point → Point → List Point
doPair x y = let d = y - x in y + d :: x - d :: Nil

doGroup : List Ant -> List Point
doGroup (x :: xs) = join $ doGroup xs ::  map (doPair (snd x) ∘ snd) xs
doGroup Nil = Nil

group : List Ant → (List Ant) → List (List Ant)
group (a :: as) Nil = group as (a :: Nil)
group (a :: as) (b :: bs) =
  if fst a == fst b
    then group as (a :: b :: bs)
    else (b :: bs) :: group as (a :: Nil)
group Nil bs = bs :: Nil

max : Int → Int → Int
max a b = if a < b then b else a

check : Int → Point → Bool
check mr (r,c) = 0 <= r && 0 <= c && r <= mr && c <= mr


doPair2 : Int -> Point → Point → List Point
doPair2 m x y = go x (y - x) ++ go y (x - y)
  where
    go : Point -> Point -> List Point
    go pt d = if check m pt then pt :: go (pt + d) d else Nil

doGroup2 : Int -> List Ant -> List Point
doGroup2 m (x :: xs) = join $ doGroup2 m xs ::  map (doPair2 m (snd x) ∘ snd) xs
doGroup2 m Nil = Nil

run : String -> IO Unit
run fn = do
  putStrLn fn
  text <- readFile fn
  let points = parse text
  let maxrow = trace "maxrow" $ foldl max 0 $ map (fst ∘ snd) points
  let maxcol = trace "maxcol" $ foldl max 0 $ map (snd ∘ snd) points
  let ants = filter (\ pt => fst pt /= '.') points
  let ants = qsort (\ x y => fst x < fst y) ants
  let groups = group ants Nil
  let stuff = join $ map doGroup groups
  let nodes = filter (check maxrow) stuff

  let part1 = length $ ordNub nodes
  putStrLn $ "part1 " ++ show part1

  let stuff2 = join $ map (doGroup2 maxrow) groups
  let part2 = length $ ordNub stuff2
  putStrLn $ "part2 " ++ show part2





main : IO Unit
main = do
  run "aoc2024/day8/eg.txt"
  run "aoc2024/day8/input.txt"
