module Solutions.Day9 open System.IO open System.Text.RegularExpressions open FSharpPlus.Operators let parseInstruction line = let groups = Regex.Match(line, "([LRUD]) (\d+)").Groups |> Seq.map (fun x -> x.Value) |> Array.ofSeq match groups[1], groups[2] with | "L", count -> List.replicate (int count) (-1, 0) | "R", count -> List.replicate (int count) (1, 0) | "U", count -> List.replicate (int count) (0, 1) | "D", count -> List.replicate (int count) (0, -1) | _ -> failwith "invalid input" let headPositions steps = List.scan (fun (x1, y1) (x2, y2) -> (x1 + x2, y1 + y2)) (0, 0) steps let instructions = File.ReadLines("inputs/day9.txt") |> Seq.map parseInstruction |> Seq.concat |> List.ofSeq |> headPositions let rec followPath (rope: list) (tailSet: Set) (heads: list) = let touches pointA pointB = abs (fst pointA - fst pointB) <= 1 && abs (snd pointA - snd pointB) <= 1 let moveTowards head tail = (fst tail + signum (fst head - fst tail), snd tail + signum (snd head - snd tail)) if List.length heads = 0 then Set.count tailSet else let newHead = List.head heads let newRope = List.scan (fun head tail -> if touches head tail then tail else moveTowards head tail) newHead (List.tail rope) followPath newRope (Set.add (List.last newRope) tailSet) (List.tail heads) let solution ropeSize = followPath (List.replicate ropeSize (0, 0)) Set.empty let part1 () = instructions |> solution 2 let part2 () = instructions |> solution 10