module Solutions.Day14 open System open System.IO let lineToCoords (line: string) = line.Split([|","; " -> "|], StringSplitOptions.None) |> Array.map int |> Array.chunkBySize 2 |> Array.map (fun x -> x[0], x[1]) let coordsToPointSet (coords: (int * int) array) = let coordLine (x1, y1) (x2, y2) = seq { for x in min x1 x2 .. max x1 x2 do for y in min y1 y2 .. max y1 y2 -> (x, y) } |> Set.ofSeq Array.fold2 (fun points coord1 coord2 -> coordLine coord1 coord2 |> Set.union points) Set.empty coords[..Array.length coords - 2] coords[1..] let cave = File.ReadAllLines("inputs/day14.txt") |> Array.map (lineToCoords >> coordsToPointSet) |> Set.unionMany let startPoint = (500, 0) let rec watch abyss (cave, p1) = let rec drop cave p1 (x, y) = [ x, y+1; x-1, y+1; x+1, y+1] |> Seq.tryFind (fun n -> not (Set.contains n cave)) |> (function | None -> Set.add (x, y) cave, p1 | Some (nx, ny) when ny = abyss -> Set.add (nx, ny) cave, (if p1 = -1 then Set.count cave else p1) | Some n -> drop cave p1 n) if Set.contains startPoint cave then (p1, Set.count cave) else watch abyss (drop cave p1 startPoint) let solution = let abyss = (cave |> Seq.maxBy snd |> snd) + 1 let r = Set.count cave let rns = watch abyss (cave, -1) (fst rns - r), (snd rns - r) let part1 () = fst solution let part2 () = snd solution