module advent_of_code.tasks.day_5.Star2 open System open System.IO let stream = new StreamReader("tasks/day-5/input.txt") let rec buildFresh() = let line = stream.ReadLine() if line.Length = 0 then List.empty else let splitLine = line.Split("-") let low, high = splitLine[0] |> int64, splitLine[1] |> int64 List.append [ (low, high) ] (buildFresh()) let isFresh (fruit: int64) (range: int64 * int64) = let low, high = range.Deconstruct() if (fruit >= low && fruit <= high) then 1 else 0 let matchRange (a: int64 * int64) (b: int64 * int64) = let aMin, aMax = a.Deconstruct() let bMin, bMax = b.Deconstruct() (aMin <= bMin && bMin <= aMax) || (bMin <= aMin && aMin <= bMax) || (aMin <= bMin && aMax >= bMax) || (bMin <= aMin && bMax >= aMax) let combineRange (a: int64 * int64) (b: int64 * int64) = let aMin, aMax = a.Deconstruct() let bMin, bMax = b.Deconstruct() (min aMin bMin, max aMax bMax) let rec trimFresh (trimmedFreshList: (int64 * int64) list) (fullFreshList: (int64 * int64) list) = let currentRange, tail = fullFreshList.Head, fullFreshList.Tail let overlaps = trimmedFreshList |> List.map (matchRange currentRange) let firstOverlap = List.tryFindIndex ((=) true) overlaps let newTrimmedList = match firstOverlap with | None -> List.append trimmedFreshList [currentRange] | Some 0 -> List.append [combineRange currentRange trimmedFreshList[0]] trimmedFreshList[1 ..] | Some index -> List.append (List.append trimmedFreshList[.. index - 1] [combineRange currentRange trimmedFreshList[index]]) trimmedFreshList[index + 1 ..] if tail.IsEmpty then newTrimmedList else trimFresh newTrimmedList tail let rec trimLoop (fullFreshList: (int64 * int64) list) = let trimmedList = trimFresh List.empty fullFreshList if trimmedList.Length = fullFreshList.Length then trimmedList else trimLoop trimmedList let rec addRanges (ranges: (int64 * int64) list) = let range, tail = ranges.Head, ranges.Tail let low, high = range.Deconstruct() ((high - low) + (1 |> int64)) + (if tail.IsEmpty then 0 |> int64 else (addRanges tail)) let main = let freshSet = List.sort (buildFresh()) let trimmed = trimLoop freshSet addRanges trimmed