From 6cdfc0d33cadd05130a13e9243d67aed49c49f16 Mon Sep 17 00:00:00 2001 From: Smaug123 Date: Fri, 15 Dec 2023 12:37:31 +0000 Subject: [PATCH] Faster --- .../AdventOfCode2023.FSharp.Lib/Day15.fs | 28 +++++++++++++------ AdventOfCode2023.FSharp/Test/TestDay15.fs | 6 ++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day15.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day15.fs index 2218e46..fa6171a 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day15.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day15.fs @@ -58,11 +58,17 @@ module Day15 = // no replacement was made arr.Add value - let inline focusingPower (boxNumber : int) (arr : ResizeArray<_ * _>) : int = - let mutable answer = 0 + let inline getLength (labelAndLength : uint64) : uint32 = + (labelAndLength % uint64 UInt32.MaxValue) |> uint32 + + let inline getLabel (labelAndLength : uint64) : uint32 = + (labelAndLength / uint64 UInt32.MaxValue) |> uint32 + + let inline focusingPower (boxNumber : uint32) (arr : ResizeArray<_>) = + let mutable answer = 0ul for i = 0 to arr.Count - 1 do - answer <- answer + (boxNumber + 1) * (i + 1) * snd arr.[i] + answer <- answer + (boxNumber + 1ul) * (uint32 i + 1ul) * getLength arr.[i] answer @@ -74,31 +80,35 @@ module Day15 = answer + let inline pack (label : uint32) (focalLength : uint32) : uint64 = + uint64 label * uint64 UInt32.MaxValue + uint64 focalLength + let part2 (s : string) = let s = s.AsSpan().TrimEnd () use chunks = StringSplitEnumerator.make' ',' s // The max length of a label turns out to be 6, which means we need 26^6 < 2^32 entries. // So we'll use a uint32 instead of our string, to save hopping around memory. - let lenses = Array.init 256 (fun _ -> ResizeArray ()) + // We'll also pack the focal length into the elements, to save tupling. + let lenses = Array.init 256 (fun _ -> ResizeArray ()) for chunk in chunks do if chunk.[chunk.Length - 1] = '-' then let label = chunk.Slice (0, chunk.Length - 1) let labelShrunk = toUint32 label - removeFirst (fun (label2 : uint32, _focalLength) -> label2 = labelShrunk) lenses.[hash label] + removeFirst (fun labelAndLength -> getLabel labelAndLength = labelShrunk) lenses.[hash label] else let equalsPos = chunk.IndexOf '=' let focalLength = - Int32.Parse (chunk.Slice (equalsPos + 1), NumberStyles.None, CultureInfo.InvariantCulture) + UInt32.Parse (chunk.Slice (equalsPos + 1), NumberStyles.None, CultureInfo.InvariantCulture) let label = chunk.Slice (0, equalsPos) let labelShrunk = toUint32 label - replace fst labelShrunk (labelShrunk, focalLength) lenses.[hash label] + replace getLabel labelShrunk (pack labelShrunk focalLength) lenses.[hash label] - let mutable answer = 0 + let mutable answer = 0ul for i = 0 to 255 do - answer <- answer + focusingPower i lenses.[i] + answer <- answer + focusingPower (uint32 i) lenses.[i] answer diff --git a/AdventOfCode2023.FSharp/Test/TestDay15.fs b/AdventOfCode2023.FSharp/Test/TestDay15.fs index 48e9758..29b3519 100644 --- a/AdventOfCode2023.FSharp/Test/TestDay15.fs +++ b/AdventOfCode2023.FSharp/Test/TestDay15.fs @@ -1,7 +1,5 @@ namespace AdventOfCode2023.Test -open System - open AdventOfCode2023 open NUnit.Framework open FsUnitTyped @@ -19,7 +17,7 @@ module TestDay15 = [] let part2Sample () = - sample |> Day15.part2 |> shouldEqual 145 + sample |> Day15.part2 |> shouldEqual 145ul [] let part1Actual () = @@ -45,4 +43,4 @@ module TestDay15 = Assert.Inconclusive () failwith "unreachable" - Day15.part2 s |> shouldEqual 248279 + Day15.part2 s |> shouldEqual 248279ul