From 785dce4d2bf98e76ef16be039a78acd055a9b375 Mon Sep 17 00:00:00 2001 From: Smaug123 Date: Tue, 5 Dec 2023 20:05:32 +0000 Subject: [PATCH] Terrible --- .../AdventOfCode2023.FSharp.Lib/Day5.fs | 136 +++++++++++++++++- .../EfficientString.fs | 6 + .../AdventOfCode2023.FSharp/Program.fs | 5 + AdventOfCode2023.FSharp/Test/TestDay5.fs | 9 +- AdventOfCode2023.FSharp/Test/samples/day5.txt | 33 +++++ 5 files changed, 180 insertions(+), 9 deletions(-) diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day5.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day5.fs index 7afa4cd..3390fa9 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day5.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day5.fs @@ -3,14 +3,140 @@ namespace AdventOfCode2023 open System open System.Collections.Generic +[] +type Range = + { + SourceStart : uint64 + DestStart : uint64 + Len : uint64 + } + [] module Day5 = + let remap (range : Range) (i : uint64) = + if range.SourceStart <= i && i < range.SourceStart + range.Len then + i - range.SourceStart + range.DestStart + |> ValueSome + else + ValueNone + + let parse (s : string) = + use mutable lines = StringSplitEnumerator.make '\n' s + lines.MoveNext () |> ignore + let seeds = + use mutable line1 = StringSplitEnumerator.make' ' ' lines.Current + StringSplitEnumerator.chomp "seeds:" &line1 + let result = ResizeArray () + while line1.MoveNext () do + result.Add (UInt64.Parse line1.Current) + result.ToArray () + lines.MoveNext () |> ignore + + let mappings = ResizeArray () + + let mutable currentMapping = null + + for line in lines do + if line.IsEmpty then + if not (isNull currentMapping) then + mappings.Add currentMapping + currentMapping <- null + else + if isNull currentMapping then + currentMapping <- ResizeArray () + else + use mutable line = StringSplitEnumerator.make' ' ' line + let destStart = StringSplitEnumerator.consumeU64 &line + let sourceStart = StringSplitEnumerator.consumeU64 &line + let rangeLen = StringSplitEnumerator.consumeU64 &line + { + SourceStart = sourceStart + DestStart = destStart + Len = rangeLen + } + |> currentMapping.Add + + seeds, mappings + let part1 (s : string) = - use lines = StringSplitEnumerator.make '\n' s - 0 + let seeds, mappings = parse s - let part2 (s : string) = - use lines = StringSplitEnumerator.make '\n' s + let mutable best = UInt64.MaxValue + for seed in seeds do + let mutable remapped = seed + for map in mappings do + let mutable hasRemappedThisLayer = false + for interval in map do + if not hasRemappedThisLayer then + match remap interval remapped with + | ValueNone -> + () + | ValueSome n -> + hasRemappedThisLayer <- true + remapped <- n + if remapped < best then + best <- remapped - 0 + best + + let private split (ranges : (uint64 * uint64) ResizeArray) (newRange : Range) : unit = + let startsStack = ResizeArray () + let endsStack = ResizeArray () + startsStack.Add newRange.SourceStart + endsStack.Add (newRange.SourceStart + newRange.Len - 1uL) + while startsStack.Count > 0 do + let mutable i = 0 + while i < ranges.Count do + let low, high = ranges.[i] + if low <= startsStack.[startsStack.Count - 1] && endsStack.[endsStack.Count - 1] <= high then + // splitting because: + // low ... start .. finish .. high + ranges.[i] <- (low, startsStack.[startsStack.Count - 1]) + ranges.Add (startsStack.[startsStack.Count - 1], endsStack.[endsStack.Count - 1]) + ranges.Add (endsStack.[endsStack.Count - 1], high) + startsStack.RemoveAt (startsStack.Count - 1) + endsStack.RemoveAt (endsStack.Count - 1) + elif low <= startsStack.[startsStack.Count - 1] && high < endsStack.[endsStack.Count - 1] then + // splitting because: + // low .. start .. high .. finish + ranges.[i] <- (low, startsStack.[startsStack.Count - 1]) + ranges.Add (startsStack.[startsStack.Count - 1], high) + startsStack.[startsStack.Count - 1] <- high + elif low > startsStack.[startsStack.Count - 1] && low < newRange.SourceStart + newRange.Len && newRange.SourceStart + newRange.Len < high then + // splitting because: + // start .. low .. finish .. high + ranges.[i] <- (low, endsStack.[endsStack.Count - 1]) + ranges.Add (endsStack.[endsStack.Count - 1], high) + endsStack.[endsStack.Count - 1] <- low + elif low > newRange.SourceStart && low < newRange.SourceStart + newRange.Len && high < newRange.SourceStart + newRange.Len then + // splitting because: + // start .. low .. high .. finish + failwith "" + i <- i + 1 + + let part2 (s : string) : uint64 = + let seeds, mappings = parse s + + let chunks = seeds |> Array.splitInto (seeds.Length / 2) + chunks + |> Array.Parallel.map (fun arr -> + let start, len = match arr with | [| s ; l |] -> s, l | _ -> failwith "bad" + let mutable best = UInt64.MaxValue + for seed in start .. start + len - uint64 1 do + let mutable remapped = seed + for map in mappings do + let mutable hasRemappedThisLayer = false + for interval in map do + if not hasRemappedThisLayer then + match remap interval remapped with + | ValueNone -> + () + | ValueSome n -> + hasRemappedThisLayer <- true + remapped <- n + if remapped < best then + best <- remapped + best + ) + |> Array.min diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/EfficientString.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/EfficientString.fs index 16eb2fb..d9cf07b 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/EfficientString.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/EfficientString.fs @@ -95,3 +95,9 @@ module StringSplitEnumerator = failwith "expected an int, got nothing" Int32.Parse e.Current + + let consumeU64 (e : byref) : uint64 = + if not (e.MoveNext ()) then + failwith "expected an int, got nothing" + + UInt64.Parse e.Current diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs index 000ca44..8a14ef2 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs @@ -23,6 +23,7 @@ module Program = let sw = Stopwatch.StartNew () + printfn "=====Day 1=====" do sw.Restart () let input = Path.Combine (dir.FullName, "day1.txt") |> File.ReadAllText @@ -36,6 +37,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") + printfn "=====Day 2=====" do let input = Path.Combine (dir.FullName, "day2.txt") |> File.ReadAllText sw.Restart () @@ -49,6 +51,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") + printfn "=====Day 3=====" do let input = Path.Combine (dir.FullName, "day3.txt") |> File.ReadAllBytes @@ -85,6 +88,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") + printfn "=====Day 4=====" do let input = Path.Combine (dir.FullName, "day4.txt") |> File.ReadAllText sw.Restart () @@ -98,6 +102,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") + printfn "=====Day 5=====" do let input = Path.Combine (dir.FullName, "day5.txt") |> File.ReadAllText sw.Restart () diff --git a/AdventOfCode2023.FSharp/Test/TestDay5.fs b/AdventOfCode2023.FSharp/Test/TestDay5.fs index dc38b6b..feb770d 100644 --- a/AdventOfCode2023.FSharp/Test/TestDay5.fs +++ b/AdventOfCode2023.FSharp/Test/TestDay5.fs @@ -1,5 +1,6 @@ namespace AdventOfCode2023.Test +open System open AdventOfCode2023 open NUnit.Framework open FsUnitTyped @@ -11,10 +12,10 @@ module TestDay5 = let sample = Assembly.getEmbeddedResource typeof.Assembly "day5.txt" [] - let part1Sample () = sample |> Day5.part1 |> shouldEqual 0 + let part1Sample () = sample |> Day5.part1 |> shouldEqual (uint64 35) [] - let part2Sample () = sample |> Day5.part2 |> shouldEqual 0 + let part2Sample () = sample |> Day5.part2 |> shouldEqual (uint64 46) [] let part1Actual () = @@ -27,7 +28,7 @@ module TestDay5 = Assert.Inconclusive () failwith "unreachable" - Day5.part1 s |> shouldEqual 0 + Day5.part1 s |> shouldEqual (uint64 806029445) [] let part2Actual () = @@ -40,4 +41,4 @@ module TestDay5 = Assert.Inconclusive () failwith "unreachable" - Day5.part2 s |> shouldEqual 0 + Day5.part2 s |> shouldEqual (uint64 59370572) diff --git a/AdventOfCode2023.FSharp/Test/samples/day5.txt b/AdventOfCode2023.FSharp/Test/samples/day5.txt index e69de29..f756727 100644 --- a/AdventOfCode2023.FSharp/Test/samples/day5.txt +++ b/AdventOfCode2023.FSharp/Test/samples/day5.txt @@ -0,0 +1,33 @@ +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