diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day6.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day6.fs index 4021732..8547640 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day6.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day6.fs @@ -5,10 +5,82 @@ open System [] module Day6 = - let part1 (s : string) = + let parse (s : string) = use mutable lines = StringSplitEnumerator.make '\n' s - -1 + let times = + lines.MoveNext () |> ignore + use mutable line = StringSplitEnumerator.make' ' ' lines.Current + StringSplitEnumerator.chomp "Time:" &line + line.MoveNext () |> ignore + let times = ResizeArray () + while line.MoveNext () do + if not line.Current.IsEmpty then + times.Add (UInt64.Parse line.Current) + times + let distance = + lines.MoveNext () |> ignore + use mutable line = StringSplitEnumerator.make' ' ' lines.Current + StringSplitEnumerator.chomp "Distance:" &line + line.MoveNext () |> ignore + let distance = ResizeArray () + while line.MoveNext () do + if not line.Current.IsEmpty then + distance.Add (UInt64.Parse line.Current) + distance + times, distance + + let furthest (distance : uint64) (toBeat : uint64) = + // Count i in [1 .. distance - 1] such that (distance - i) * i > toBeat + // i.e. such that distance * i - i * i > toBeat + // -i^2 + distance * i - toBeat = 0 when: + // i = (distance +- sqrt(distance^2 - 4 * toBeat)) / 2 + let distFloat = float distance + let inside = sqrt (distFloat * distFloat - 4.0 * float toBeat) + let limit1 = (distFloat + inside) / 2.0 + let limit2 = (distFloat - sqrt (distFloat * distFloat - 4.0 * float toBeat)) / 2.0 + // round limit2 up and limit1 down + let limit1 = uint64 (floor limit1) + let limit2 = uint64 (ceil limit2) + // cope with edge case of an exact square + if (uint64 inside) * (uint64 inside) = uint64 distance * uint64 distance - 4uL * uint64 toBeat then + limit1 - limit2 - 1uL + else + limit1 - limit2 + 1uL + + let part1 (s : string) = + let times, distance = parse s + let mutable answer = 1uL + for i = 0 to times.Count - 1 do + let time = times.[i] + let distance = distance.[i] + let winners = furthest time distance + answer <- answer * winners + answer let part2 (s : string) = - use mutable lines = StringSplitEnumerator.make '\n' s - -1 + let times, distance = parse s + let mutable concatTime = 0uL + for time in times do + // four digits will do + if time < 10uL then + concatTime <- concatTime * 10uL + time + elif time < 100uL then + concatTime <- concatTime * 100uL + time + elif time < 1000uL then + concatTime <- concatTime * 1000uL + time + else + concatTime <- concatTime * 10000uL + time + + let mutable concatDist = 0uL + for dist in distance do + // four digits will do + if dist < 10uL then + concatDist <- concatDist * 10uL + dist + elif dist < 100uL then + concatDist <- concatDist * 100uL + dist + elif dist < 1000uL then + concatDist <- concatDist * 1000uL + dist + else + concatDist <- concatDist * 10000uL + dist + + furthest concatTime concatDist diff --git a/AdventOfCode2023.FSharp/Test/TestDay6.fs b/AdventOfCode2023.FSharp/Test/TestDay6.fs index 2848b73..6235479 100644 --- a/AdventOfCode2023.FSharp/Test/TestDay6.fs +++ b/AdventOfCode2023.FSharp/Test/TestDay6.fs @@ -13,11 +13,11 @@ module TestDay6 = [] let part1Sample () = - sample |> Day6.part1 |> shouldEqual 0 + sample |> Day6.part1 |> shouldEqual 288uL [] let part2Sample () = - sample |> Day6.part2 |> shouldEqual 0 + sample |> Day6.part2 |> shouldEqual 71503uL [] let part1Actual () = @@ -30,7 +30,7 @@ module TestDay6 = Assert.Inconclusive () failwith "unreachable" - Day6.part1 s |> shouldEqual 0 + Day6.part1 s |> shouldEqual 32076uL [] let part2Actual () = @@ -43,4 +43,4 @@ module TestDay6 = Assert.Inconclusive () failwith "unreachable" - Day6.part2 s |> shouldEqual 0 + Day6.part2 s |> shouldEqual 34278221uL diff --git a/AdventOfCode2023.FSharp/Test/samples/day6.txt b/AdventOfCode2023.FSharp/Test/samples/day6.txt index f756727..28f5ae9 100644 --- a/AdventOfCode2023.FSharp/Test/samples/day6.txt +++ b/AdventOfCode2023.FSharp/Test/samples/day6.txt @@ -1,33 +1,2 @@ -seeds: 79 14 55 13 - -seed-to-soil map: -50 98 2 -52 50 48 - -soil-to-fertilizer map: -0 15 37 -37 52 2 -39 0 15 - -fertilizer-to-water map: -49 53 8 -0 11 42 -42 0 7 -57 7 4 - -water-to-light map: -88 18 7 -18 25 70 - -light-to-temperature map: -45 77 23 -81 45 19 -68 64 13 - -temperature-to-humidity map: -0 69 1 -1 0 69 - -humidity-to-location map: -60 56 37 -56 93 4 +Time: 7 15 30 +Distance: 9 40 200