Lower level
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/all-checks-complete Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/all-checks-complete Pipeline was successful

This commit is contained in:
Smaug123
2023-12-05 20:20:59 +00:00
parent 713b139bc2
commit 8178585ebd

View File

@@ -1,7 +1,6 @@
namespace AdventOfCode2023
open System
open System.Collections.Generic
[<Struct>]
type Range =
@@ -14,12 +13,6 @@ type Range =
[<RequireQualifiedAccess>]
module Day5 =
let remap (range : Range) (i : uint32) =
if range.SourceStart <= i && i - range.SourceStart < range.Len then
i + (range.DestStart - range.SourceStart) |> ValueSome
else
ValueNone
let parse (s : string) =
use mutable lines = StringSplitEnumerator.make '\n' s
lines.MoveNext () |> ignore
@@ -75,11 +68,12 @@ module Day5 =
for interval in map do
if not hasRemappedThisLayer then
match remap interval remapped with
| ValueNone -> ()
| ValueSome n ->
if
interval.SourceStart <= remapped
&& remapped - interval.SourceStart < interval.Len
then
hasRemappedThisLayer <- true
remapped <- n
remapped <- remapped + (interval.DestStart - interval.SourceStart)
if remapped < best then
best <- remapped
@@ -89,22 +83,22 @@ module Day5 =
// The input ranges are inclusive at both ends.
// Returns any range we didn't map.
let private split
(result : ResizeArray<uint32 * uint32>)
(start, finish)
(resultStarts : ResizeArray<uint32>)
(resultEnds : ResizeArray<uint32>)
start
finish
(rangeFromLayer : Range)
: (uint32 * uint32 * (uint32 * uint32) voption) voption
=
let low, high =
rangeFromLayer.SourceStart, rangeFromLayer.SourceStart + rangeFromLayer.Len - 1ul
let low = rangeFromLayer.SourceStart
let high = rangeFromLayer.SourceStart + rangeFromLayer.Len - 1ul
if low <= start then
if finish <= high then
// low ... start .. finish .. high
// so the entire input range gets mapped down
result.Add (
start + rangeFromLayer.DestStart - rangeFromLayer.SourceStart,
finish + rangeFromLayer.DestStart - rangeFromLayer.SourceStart
)
resultStarts.Add (start + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
resultEnds.Add (finish + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
ValueNone
elif start <= high then
@@ -112,10 +106,8 @@ module Day5 =
// so start .. high gets mapped down
// and high + 1 .. finish stays where it is.
// high < finish is already guaranteed by previous if block.
result.Add (
start + rangeFromLayer.DestStart - rangeFromLayer.SourceStart,
high + rangeFromLayer.DestStart - rangeFromLayer.SourceStart
)
resultStarts.Add (start + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
resultEnds.Add (high + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
ValueSome (high + 1ul, finish, ValueNone)
else
@@ -125,20 +117,16 @@ module Day5 =
// so start .. low - 1 stays where it is
// low .. high gets mapped down
// and high + 1 .. finish stays where it is
result.Add (
low + rangeFromLayer.DestStart - rangeFromLayer.SourceStart,
high + rangeFromLayer.DestStart - rangeFromLayer.SourceStart
)
resultStarts.Add (low + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
resultEnds.Add (high + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
ValueSome (start, low - 1ul, ValueSome (high + 1ul, finish))
elif low < finish then
// start .. low .. finish .. high
// so start .. low - 1 stays where it is
// and low .. finish gets mapped down
result.Add (
low + rangeFromLayer.DestStart - rangeFromLayer.SourceStart,
finish + rangeFromLayer.DestStart - rangeFromLayer.SourceStart
)
resultStarts.Add (low + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
resultEnds.Add (finish + rangeFromLayer.DestStart - rangeFromLayer.SourceStart)
ValueSome (start, low - 1ul, ValueNone)
else
@@ -147,18 +135,20 @@ module Day5 =
let part2 (s : string) : uint32 =
let seeds, mappings = parse s
let mutable intervals = ResizeArray ()
let mutable intervalStarts = ResizeArray ()
let mutable intervalEnds = ResizeArray ()
for i = 0 to (seeds.Length - 1) / 2 do
let t = seeds.[2 * i], seeds.[2 * i + 1] + seeds.[2 * i] - 1ul
intervals.Add t
intervalStarts.Add seeds.[2 * i]
intervalEnds.Add (seeds.[2 * i + 1] + seeds.[2 * i] - 1ul)
let mutable nextIntervals = ResizeArray ()
let mutable nextIntervalStarts = ResizeArray ()
let mutable nextIntervalEnds = ResizeArray ()
for mapLayer in mappings do
let mutable i = 0
while i < intervals.Count do
while i < intervalStarts.Count do
// split interval according to every map
let mutable allMoved = false
let mutable currentRange = 0
@@ -166,30 +156,36 @@ module Day5 =
while not allMoved && currentRange < mapLayer.Count do
let range = mapLayer.[currentRange]
// range is e.g. 50 98 2, i.e. "98-99 goes to 50-51"
match split nextIntervals intervals.[i] range with
match split nextIntervalStarts nextIntervalEnds intervalStarts.[i] intervalEnds.[i] range with
| ValueNone -> allMoved <- true
| ValueSome (start, finish, v) ->
intervals.[i] <- (start, finish)
intervalStarts.[i] <- start
intervalEnds.[i] <- finish
match v with
| ValueNone -> ()
| ValueSome (start, finish) -> intervals.Add (start, finish)
| ValueSome (start, finish) ->
intervalStarts.Add start
intervalEnds.Add finish
currentRange <- currentRange + 1
if not allMoved then
nextIntervals.Add intervals.[i]
nextIntervalStarts.Add intervalStarts.[i]
nextIntervalEnds.Add intervalEnds.[i]
i <- i + 1
let oldIntervals = intervals
let oldIntervals = intervalStarts
oldIntervals.Clear ()
intervals <- nextIntervals
nextIntervals <- oldIntervals
intervalStarts <- nextIntervalStarts
nextIntervalStarts <- oldIntervals
let mutable best = UInt32.MaxValue
let oldIntervals = intervalEnds
oldIntervals.Clear ()
intervalEnds <- nextIntervalEnds
nextIntervalEnds <- oldIntervals
for i, _ in intervals do
best <- min best i
best
// SIMD go brrr
System.Linq.Enumerable.Min intervalStarts