namespace AdventOfCode2023 open System [] module Day11 = let inline private toRowAndCol (lineLength : int) (pos : int) : struct (int * int) = let lineNum = pos / lineLength let withinLine = pos % lineLength struct (lineNum, withinLine) let inline private ofRowAndCol (lineLength : int) (lineNum : int) (col : int) : int = lineNum * lineLength + col let part1 (s : string) = let galaxies = ResizeArray () let rowsWithoutGalaxies = ResizeArray () let rowLength = s.IndexOf '\n' let mutable hasAnyGalaxy = false let mutable currRowIndex = 0 let mutable currColIndex = 0 for c in s do if c = '\n' then if not hasAnyGalaxy then rowsWithoutGalaxies.Add currRowIndex currRowIndex <- currRowIndex + 1 currColIndex <- 0 hasAnyGalaxy <- false elif c = '#' then hasAnyGalaxy <- true galaxies.Add (currRowIndex, currColIndex) currColIndex <- currColIndex + 1 else currColIndex <- currColIndex + 1 galaxies.Sort (fun (_, c1) (_, c2) -> compare c1 c2) let colsWithoutGalaxies = let result = ResizeArray () let mutable prevCol = 0 for (_, c) in galaxies do if c > prevCol then for j = prevCol + 1 to c - 1 do result.Add j prevCol <- c result let mutable answer = 0 for galaxy1 = 0 to galaxies.Count - 1 do let row1, col1 = galaxies.[galaxy1] for galaxy2 = galaxy1 + 1 to galaxies.Count - 1 do let row2, col2 = galaxies.[galaxy2] let baseDistance = abs (row1 - row2) + abs (col1 - col2) let extraDistance = let mutable extraDistance = 0 for i = 1 + min row1 row2 to max row1 row2 - 1 do if rowsWithoutGalaxies.Contains i then extraDistance <- extraDistance + 1 for i = 1 + min col1 col2 to max col1 col2 - 1 do if colsWithoutGalaxies.Contains i then extraDistance <- extraDistance + 1 extraDistance answer <- answer + extraDistance + baseDistance answer let part2 (s : string) = use s = StringSplitEnumerator.make '\n' s 0