diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..506d284 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fantomas": { + "version": "6.2.3", + "commands": [ + "fantomas" + ] + } + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9ef5fed --- /dev/null +++ b/.editorconfig @@ -0,0 +1,41 @@ +root=true + +[*] +charset=utf-8 +end_of_line=crlf +trim_trailing_whitespace=true +insert_final_newline=true +indent_style=space +indent_size=4 + +# ReSharper properties +resharper_xml_indent_size=2 +resharper_xml_max_line_length=100 +resharper_xml_tab_width=2 + +[*.{csproj,fsproj,sqlproj,targets,props,ts,tsx,css,json}] +indent_style=space +indent_size=2 + +[*.{fs,fsi}] +fsharp_bar_before_discriminated_union_declaration=true +fsharp_space_before_uppercase_invocation=true +fsharp_space_before_class_constructor=true +fsharp_space_before_member=true +fsharp_space_before_colon=true +fsharp_space_before_semicolon=true +fsharp_multiline_bracket_style=aligned +fsharp_newline_between_type_definition_and_members=true +fsharp_align_function_signature_to_indentation=true +fsharp_alternative_long_member_definitions=true +fsharp_multi_line_lambda_closing_newline=true +fsharp_experimental_keep_indent_in_branch=true +fsharp_max_value_binding_width=80 +fsharp_max_record_width=0 +max_line_length=120 +end_of_line=lf + +[*.{appxmanifest,build,dtd,nuspec,xaml,xamlx,xoml,xsd}] +indent_style=space +indent_size=2 +tab_width=2 diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs index a29387f..514292f 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs @@ -99,4 +99,4 @@ module Arr2D = System.Array.Clear a.Elements #else NativePtr.initBlock a.Elements 0uy (uint32 sizeof<'a> * uint32 a.Length) -#endif \ No newline at end of file +#endif diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs index 1879e45..9b8cda2 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs @@ -4,11 +4,9 @@ open System.Collections.Generic [] module Day3 = - let inline private isSymbol (i : byte) = - i > 200uy + let inline private isSymbol (i : byte) = i > 200uy - let inline private isGear (i : byte) = - i = 255uy + let inline private isGear (i : byte) = i = 255uy /// Returns the parsed board as a buffer, the length of the buffer (there may be garbage at the end), and /// the number of lines the resulting 2D array has. @@ -16,6 +14,7 @@ module Day3 = let mutable lineCount = 0 let mutable len = 0 let resultArr = Array.zeroCreate fileContents.Length + for b in fileContents do if b = byte '.' then resultArr.[len] <- 100uy @@ -39,36 +38,48 @@ module Day3 = let isNearSymbol (row : int) (numStart : int) (curCol : int) : bool = let mutable isNearSymbol = false + if row > 0 then for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do if isSymbol (Arr2D.get contents col (row - 1)) then isNearSymbol <- true + if row < contents.Height - 1 then for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do if isSymbol (Arr2D.get contents col (row + 1)) then isNearSymbol <- true - if (numStart > 0 && isSymbol (Arr2D.get contents (numStart - 1) row)) || (curCol < lineLength && isSymbol (Arr2D.get contents curCol row)) then + + if + (numStart > 0 && isSymbol (Arr2D.get contents (numStart - 1) row)) + || (curCol < lineLength && isSymbol (Arr2D.get contents curCol row)) + then isNearSymbol <- true + isNearSymbol let mutable total = 0 + for row = 0 to contents.Height - 1 do let mutable currNum = 0 let mutable numStart = -1 + for col = 0 to lineLength - 1 do if Arr2D.get contents col row < 10uy then if numStart = -1 then numStart <- col + currNum <- currNum * 10 + int (Arr2D.get contents col row) elif numStart > -1 then if isNearSymbol row numStart col then total <- total + currNum + currNum <- 0 numStart <- -1 if numStart >= 0 then if isNearSymbol row numStart lineLength then total <- total + currNum + currNum <- 0 numStart <- -1 @@ -79,55 +90,64 @@ module Day3 = let isNearGear (row : int) (numStart : int) (curCol : int) : (int * int) IReadOnlyList = let gearsNear = ResizeArray () + if row > 0 then for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do if isGear (Arr2D.get contents col (row - 1)) then gearsNear.Add (row - 1, col) + if row < lineLength - 1 then for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do if isGear (Arr2D.get contents col (row + 1)) then gearsNear.Add (row + 1, col) + if (numStart > 0 && isGear (Arr2D.get contents (numStart - 1) row)) then gearsNear.Add (row, numStart - 1) + if (curCol < lineLength && isGear (Arr2D.get contents curCol row)) then gearsNear.Add (row, curCol) + gearsNear let gears = Dictionary> () + let addGear (gearPos : int * int) (num : int) = match gears.TryGetValue gearPos with | false, _ -> let arr = ResizeArray () arr.Add num gears.Add (gearPos, arr) - | true, arr when arr.Count < 3 -> - arr.Add num + | true, arr when arr.Count < 3 -> arr.Add num | _ -> () for row = 0 to contents.Height - 1 do let mutable currNum = 0 let mutable numStart = -1 + for col = 0 to lineLength - 1 do if Arr2D.get contents col row < 10uy then if numStart = -1 then numStart <- col + currNum <- currNum * 10 + int (Arr2D.get contents col row) elif numStart > -1 then for gearPos in isNearGear row numStart col do addGear gearPos currNum + currNum <- 0 numStart <- -1 if numStart >= 0 then for gearPos in isNearGear row numStart lineLength do addGear gearPos currNum + currNum <- 0 numStart <- -1 let mutable answer = 0 - for KeyValue(_gearPos, gears) in gears do + + for KeyValue (_gearPos, gears) in gears do if gears.Count = 2 then answer <- answer + gears.[0] * gears.[1] answer - diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs index 6e4affa..0bca9d8 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs @@ -38,6 +38,7 @@ module Program = } #else use ptr = fixed resultArr + let contents = { Elements = ptr @@ -62,4 +63,4 @@ module Program = endToEnd.Stop () System.Console.Error.WriteLine ("Total (us): " + (toUs endToEnd.ElapsedTicks).ToString ()) - 0 \ No newline at end of file + 0 diff --git a/AdventOfCode2023.FSharp/Test/Test.fsproj b/AdventOfCode2023.FSharp/Test/Test.fsproj index 48d6af2..95406ce 100644 --- a/AdventOfCode2023.FSharp/Test/Test.fsproj +++ b/AdventOfCode2023.FSharp/Test/Test.fsproj @@ -5,7 +5,6 @@ false true - TestProject1 @@ -13,11 +12,15 @@ + - + + + + diff --git a/AdventOfCode2023.FSharp/Test/TestDay3.fs b/AdventOfCode2023.FSharp/Test/TestDay3.fs index efa83d7..e09ca49 100644 --- a/AdventOfCode2023.FSharp/Test/TestDay3.fs +++ b/AdventOfCode2023.FSharp/Test/TestDay3.fs @@ -1,18 +1,133 @@ -namespace Test +namespace AdventOfCode2023.Test +#if DEBUG +#else +#nowarn "9" +#endif + +open AdventOfCode2023 open NUnit.Framework +open FsUnitTyped +open System.IO [] module TestDay3 = - [] - let day1Sample () = - () + let sample = + """467..114.. +...*...... +..35..633. +......#... +617*...... +.....+.58. +..592..... +......755. +...$.*.... +.664.598.. +""" [] - let day1Actual () = - 540131 + let part1Sample () = + let arr, len, rows = sample.ToCharArray () |> Array.map byte |> Day3.parse + +#if DEBUG + let arr = + { + Elements = arr + Width = len / rows + } +#else + use arr = fixed arr + + let arr = + { + Elements = arr + Length = len + Width = len / rows + } +#endif + + arr |> Day3.part1 |> shouldEqual 4361 [] - let day2Actual () = - 86879020 \ No newline at end of file + let part2Sample () = + let arr, len, rows = sample.ToCharArray () |> Array.map byte |> Day3.parse + +#if DEBUG + let arr = + { + Elements = arr + Width = len / rows + } +#else + use arr = fixed arr + + let arr = + { + Elements = arr + Length = len + Width = len / rows + } +#endif + + arr |> Day3.part2 |> shouldEqual 467835 + + [] + let part1Actual () = + let bytes = + try + File.ReadAllBytes (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day3.txt")) + with :? FileNotFoundException -> + Assert.Inconclusive () + failwith "unreachable" + + let arr, len, rows = Day3.parse bytes + +#if DEBUG + let arr = + { + Elements = arr + Width = len / rows + } +#else + use arr = fixed arr + + let arr = + { + Elements = arr + Length = len + Width = len / rows + } +#endif + + Day3.part1 arr |> shouldEqual 540131 + + [] + let part2Actual () = + let bytes = + try + File.ReadAllBytes (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day3.txt")) + with :? FileNotFoundException -> + Assert.Inconclusive () + failwith "unreachable" + + let arr, len, rows = Day3.parse bytes + +#if DEBUG + let arr = + { + Elements = arr + Width = len / rows + } +#else + use arr = fixed arr + + let arr = + { + Elements = arr + Length = len + Width = len / rows + } +#endif + + Day3.part2 arr |> shouldEqual 86879020