From 9a78d237ad1d523f157e5af271ab8661267387ea Mon Sep 17 00:00:00 2001 From: NicoVIII Date: Tue, 30 Jul 2024 09:51:48 +0000 Subject: [PATCH] 2023 - F# - Day 06 - Part 2 --- 2023/outputs/06/output-example.txt | 2 +- 2023/outputs/06/output-puzzle.txt | 2 +- 2023/solutions/fsharp/06/src/Functions.fs | 33 ++++++++++++++------ 2023/solutions/fsharp/06/src/Program.fs | 8 +++-- 2023/solutions/fsharp/06/src/Types.fs | 6 +++- 2023/solutions/fsharp/06/test/Main.fs | 38 +++++++++++------------ 2023/solutions/fsharp/testBase/Library.fs | 35 ++++++++++++--------- 7 files changed, 76 insertions(+), 48 deletions(-) diff --git a/2023/outputs/06/output-example.txt b/2023/outputs/06/output-example.txt index 4c0efaa..41bb2b9 100644 --- a/2023/outputs/06/output-example.txt +++ b/2023/outputs/06/output-example.txt @@ -1,2 +1,2 @@ 288 -- +71503 diff --git a/2023/outputs/06/output-puzzle.txt b/2023/outputs/06/output-puzzle.txt index d9f4884..4f5a263 100644 --- a/2023/outputs/06/output-puzzle.txt +++ b/2023/outputs/06/output-puzzle.txt @@ -1,2 +1,2 @@ 1084752 -- +28228952 diff --git a/2023/solutions/fsharp/06/src/Functions.fs b/2023/solutions/fsharp/06/src/Functions.fs index 76b2dd9..9545599 100644 --- a/2023/solutions/fsharp/06/src/Functions.fs +++ b/2023/solutions/fsharp/06/src/Functions.fs @@ -11,23 +11,38 @@ module String = [] module Functions = - let parseLine line = + let parseLineV1 line : Base array = // Remove title (String.split ":" line)[1] |> String.trim |> String.split " " - |> Array.choose (fun x -> if x <> "" then uint16 x |> Some else None) + |> Array.choose (fun x -> if x <> "" then Base.convertTo x |> Some else None) - let parseInput input = + let parseInputV1 input = let lines = String.split "\n" input - let times = parseLine lines[0] - let distances = parseLine lines[1] + let times = parseLineV1 lines[0] + let distances = parseLineV1 lines[1] Array.zip times distances |> Array.map (fun (time, distance) -> { time = time; distance = distance }) |> List.ofArray - let beatRecordCount record = + let parseLineV2 line : Base = + // Remove title + (String.split ":" line)[1] + |> String.trim + |> String.filter (fun c -> c <> ' ') + |> Base.convertTo + + let parseInputV2 input = + let lines = String.split "\n" input + + { + time = parseLineV2 lines[0] + distance = parseLineV2 lines[1] + } + + let beatRecordCount record : Base = // We can express the problem like this // distance < (x-y)(x+y) with y < x and x = time / 2 // count how many ys element of integers are there which solve that @@ -45,7 +60,7 @@ module Functions = // y - 0.5 < sqrt (x² - distance) // y < sqrt (x² - distance) + 0.5 // biggest y = round-down (sqrt (x² - distance) + 0.5 - 0.0001) - let timeIsOdd = record.time % 2us <> 0us + let timeIsOdd = record.time % 2UL <> 0UL let biggestY = pown (float record.time / 2.) 2 - float record.distance @@ -53,6 +68,6 @@ module Functions = |> if timeIsOdd then (+) 0.5 else id |> (+) -0.0001 |> floor - |> uint16 + |> Base.convertTo - if timeIsOdd then biggestY * 2us else biggestY * 2us + 1us + if timeIsOdd then biggestY * 2UL else biggestY * 2UL + 1UL diff --git a/2023/solutions/fsharp/06/src/Program.fs b/2023/solutions/fsharp/06/src/Program.fs index eff1e37..e3774e0 100644 --- a/2023/solutions/fsharp/06/src/Program.fs +++ b/2023/solutions/fsharp/06/src/Program.fs @@ -1,11 +1,14 @@ namespace Day06 +open Microsoft.FSharp.Core.Operators.Checked + [] module Expose = open System.IO - let readInput = File.ReadAllText >> parseInput - let part1 = List.map beatRecordCount >> List.map uint >> List.reduce (*) + let readInput = File.ReadAllText + let part1 = parseInputV1 >> List.map beatRecordCount >> List.reduce (*) + let part2 = parseInputV2 >> beatRecordCount module Program = [] @@ -13,4 +16,5 @@ module Program = let input = readInput args[0] part1 input |> printfn "Part 1: %i" + part2 input |> printfn "Part 2: %i" 0 diff --git a/2023/solutions/fsharp/06/src/Types.fs b/2023/solutions/fsharp/06/src/Types.fs index cd4d30f..9dac7b7 100644 --- a/2023/solutions/fsharp/06/src/Types.fs +++ b/2023/solutions/fsharp/06/src/Types.fs @@ -1,4 +1,8 @@ namespace Day06 -type Base = uint16 +type Base = uint64 type Record = { time: Base; distance: Base } + +[] +module Base = + let inline convertTo x = uint64 x diff --git a/2023/solutions/fsharp/06/test/Main.fs b/2023/solutions/fsharp/06/test/Main.fs index 3d3115f..c094a2f 100644 --- a/2023/solutions/fsharp/06/test/Main.fs +++ b/2023/solutions/fsharp/06/test/Main.fs @@ -7,11 +7,11 @@ open Tests type RecordGen() = static member Record() : Arbitrary = - Arb.from + Arb.from |> Arb.convert (fun (time, distance) -> { time = time; distance = distance }) (fun record -> record.time, record.distance) |> Arb.filter (fun record -> - record.time > 0us && pown (float record.time / 2.) 2 > float record.distance) + record.time > 0UL && pown (float record.time / 2.) 2 > float record.distance) [] module Auto = @@ -22,46 +22,46 @@ module Auto = let testProperty = testPropertyWithConfig config -let alternativeImplementation record = - [ 0us .. record.time ] +let alternativeImplementation record : Base = + [ 0UL .. record.time ] |> List.filter (fun loadingTime -> (record.time - loadingTime) * loadingTime > record.distance) |> List.length - |> uint16 + |> Base.convertTo [] let unitTests = testList (nameof Functions) [ - testList (nameof parseInput) [ + testList (nameof parseInputV1) [ let paramList = [ [ "Time: 7 15 30"; "Distance: 9 40 200" ], [ - { time = 7us; distance = 9us } - { time = 15us; distance = 40us } - { time = 30us; distance = 200us } + { time = 7UL; distance = 9UL } + { time = 15UL; distance = 40UL } + { time = 30UL; distance = 200UL } ] [ "Time: 40 70 98 79" "Distance: 215 1051 2147 1005" ], [ - { time = 40us; distance = 215us } - { time = 70us; distance = 1051us } - { time = 98us; distance = 2147us } - { time = 79us; distance = 1005us } + { time = 40UL; distance = 215UL } + { time = 70UL; distance = 1051UL } + { time = 98UL; distance = 2147UL } + { time = 79UL; distance = 1005UL } ] ] for (input, expected) in paramList do test $"{expected}" { - Expect.equal (String.concat "\n" input |> parseInput) expected "" + Expect.equal (String.concat "\n" input |> parseInputV1) expected "" } ] testList (nameof beatRecordCount) [ let paramList = [ - { time = 7us; distance = 9us }, 4us - { time = 30us; distance = 200us }, 9us - { time = 40us; distance = 215us }, 27us - { time = 79us; distance = 1005us }, 48us + { time = 7UL; distance = 9UL }, 4UL + { time = 30UL; distance = 200UL }, 9UL + { time = 40UL; distance = 215UL }, 27UL + { time = 79UL; distance = 1005UL }, 48UL ] for (record, expected) in paramList do @@ -84,7 +84,7 @@ let integrationTests = { day = 6 part1 = part1 >> string - part2 = fun _ -> failwith "Not implemented" + part2 = part2 >> string readInput = readInput } |> Tests.build diff --git a/2023/solutions/fsharp/testBase/Library.fs b/2023/solutions/fsharp/testBase/Library.fs index 6b32df3..3ebddc0 100644 --- a/2023/solutions/fsharp/testBase/Library.fs +++ b/2023/solutions/fsharp/testBase/Library.fs @@ -18,7 +18,7 @@ module Tests = |> Seq.filter (fun filePath -> let fileName = Path.GetFileName filePath fileName.StartsWith "input-" && fileName.EndsWith ".txt") - |> Seq.choose (fun filePath -> + |> Seq.collect (fun filePath -> // Fetch input identifier let fileName = Path.GetFileName filePath let pattern = @"input-(.*).txt" @@ -37,24 +37,29 @@ module Tests = failwith $"Expected output file {outputFilePath} to contain exactly two lines" - test $"Input: {fileName}" { - let input = config.readInput filePath - + [ if part1Output <> "-" then - Expect.equal - (config.part1 input |> string) - part1Output - "Part 1 result wrong" + test $"Input: {fileName} - Part 1" { + let input = config.readInput filePath + + Expect.equal + (config.part1 input |> string) + part1Output + "Part 1 result wrong" + } if part2Output <> "-" then - Expect.equal - (config.part2 input |> string) - part2Output - "Part 2 result wrong" - } - |> Some + test $"Input: {fileName} - Part 2" { + let input = config.readInput filePath + + Expect.equal + (config.part2 input |> string) + part2Output + "Part 2 result wrong" + } + ] else printfn "Warning: No matching output file for %s" fileName - None) + []) |> Seq.toList |> testList $"Day {config.day}"