mirror of
https://github.com/Smaug123/AdventOfCode2022
synced 2025-10-05 01:28:39 +00:00
Speed up Day 12 by the power of MANAGING YOUR OWN MEMORY (#17)
This commit is contained in:
@@ -41,15 +41,6 @@ Monkey 3:
|
||||
let ``Part 1, given`` () =
|
||||
Day11.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 10605
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1, single round, given`` () =
|
||||
let monkeys = Day11.parse (StringSplitEnumerator.make '\n' input)
|
||||
let inspections = Array.zeroCreate monkeys.Length
|
||||
|
||||
Day11.oneRoundDivThree monkeys inspections
|
||||
|
||||
inspections |> shouldEqual [| 2 ; 4 ; 3 ; 5 |]
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1`` () =
|
||||
let input = Assembly.readResource "Day11.txt"
|
||||
@@ -58,7 +49,7 @@ Monkey 3:
|
||||
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2, given 1`` () =
|
||||
let ``Part 2, given`` () =
|
||||
Day11.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 2713310158L
|
||||
|
||||
[<Test>]
|
||||
|
@@ -2,10 +2,14 @@ namespace AdventOfCode2022
|
||||
|
||||
open System.Collections.Generic
|
||||
open System
|
||||
open Microsoft.FSharp.NativeInterop
|
||||
|
||||
#if DEBUG
|
||||
open Checked
|
||||
#endif
|
||||
|
||||
#nowarn "9"
|
||||
|
||||
[<Measure>]
|
||||
type monkey
|
||||
|
||||
@@ -14,8 +18,6 @@ module Day11 =
|
||||
|
||||
type Monkey =
|
||||
{
|
||||
Number : int<monkey>
|
||||
StartingItems : int64 ResizeArray
|
||||
OperationIsPlus : bool
|
||||
/// Negative is None
|
||||
Argument : int64
|
||||
@@ -24,9 +26,10 @@ module Day11 =
|
||||
FalseCase : int<monkey>
|
||||
}
|
||||
|
||||
let parse (lines : StringSplitEnumerator) : Monkey array =
|
||||
let parse (memory : nativeptr<int64>) (lines : StringSplitEnumerator) : Monkey array * nativeptr<int64>[] * int[] =
|
||||
use mutable enum = lines
|
||||
let output = ResizeArray ()
|
||||
let startingItems = ResizeArray ()
|
||||
|
||||
while enum.MoveNext () do
|
||||
let monkey =
|
||||
@@ -160,9 +163,9 @@ module Day11 =
|
||||
if ifFalse = monkey then
|
||||
failwith "assumption broken: throws to self"
|
||||
|
||||
startingItems.Add startItems
|
||||
|
||||
{
|
||||
Number = monkey
|
||||
StartingItems = startItems
|
||||
OperationIsPlus = operationIsPlus
|
||||
Argument = arg
|
||||
TestDivisibleBy = test
|
||||
@@ -171,14 +174,36 @@ module Day11 =
|
||||
}
|
||||
|> output.Add
|
||||
|
||||
output.ToArray ()
|
||||
let totalItemCount = startingItems |> Seq.sumBy (fun x -> x.Count)
|
||||
|
||||
let oneRoundDivThree (monkeys : IReadOnlyList<Monkey>) (inspections : int64 array) =
|
||||
let items =
|
||||
Array.init
|
||||
startingItems.Count
|
||||
(fun i ->
|
||||
for j in 0 .. startingItems.[i].Count - 1 do
|
||||
NativePtr.write (NativePtr.add memory (totalItemCount * i + j)) startingItems.[i].[j]
|
||||
|
||||
NativePtr.add memory (totalItemCount * i)
|
||||
)
|
||||
|
||||
let counts = Array.init startingItems.Count (fun i -> startingItems.[i].Count)
|
||||
|
||||
output.ToArray (), items, counts
|
||||
|
||||
let oneRoundDivThree
|
||||
(monkeys : IReadOnlyList<Monkey>)
|
||||
(items : nativeptr<int64>[])
|
||||
(counts : nativeptr<int>)
|
||||
(inspections : int64 array)
|
||||
=
|
||||
for i in 0 .. monkeys.Count - 1 do
|
||||
let monkey = monkeys.[i]
|
||||
inspections.[i] <- inspections.[i] + int64 monkey.StartingItems.Count
|
||||
let countsI = NativePtr.get counts i
|
||||
inspections.[i] <- inspections.[i] + int64 countsI
|
||||
|
||||
for worryIndex in 0 .. countsI - 1 do
|
||||
let worry = NativePtr.get items.[i] worryIndex
|
||||
|
||||
for worry in monkey.StartingItems do
|
||||
let newWorry =
|
||||
let arg =
|
||||
match monkey.Argument with
|
||||
@@ -195,28 +220,55 @@ module Day11 =
|
||||
else
|
||||
monkey.FalseCase
|
||||
|
||||
monkeys.[target / 1<monkey>].StartingItems.Add newWorry
|
||||
let target = target / 1<monkey>
|
||||
let targetCount = NativePtr.get counts target
|
||||
NativePtr.write (NativePtr.add items.[target] targetCount) newWorry
|
||||
NativePtr.write (NativePtr.add counts target) (targetCount + 1)
|
||||
|
||||
monkey.StartingItems.Clear ()
|
||||
NativePtr.write (NativePtr.add counts i) 0
|
||||
|
||||
let inline maxTwo (arr : int64 array) : struct (int64 * int64) =
|
||||
let mutable best = max arr.[1] arr.[0]
|
||||
let mutable secondBest = min arr.[1] arr.[0]
|
||||
|
||||
for i in 2 .. arr.Length - 1 do
|
||||
if arr.[i] > best then
|
||||
secondBest <- best
|
||||
best <- arr.[i]
|
||||
elif arr.[i] > secondBest then
|
||||
secondBest <- arr.[i]
|
||||
|
||||
struct (secondBest, best)
|
||||
|
||||
let part1 (lines : StringSplitEnumerator) : int64 =
|
||||
let monkeys = parse lines
|
||||
let memory = NativePtr.stackalloc<int64> 1000
|
||||
let monkeys, items, counts = parse memory lines
|
||||
use counts = fixed counts
|
||||
|
||||
let mutable inspections = Array.zeroCreate<int64> monkeys.Length
|
||||
|
||||
for _round in 1..20 do
|
||||
oneRoundDivThree monkeys inspections
|
||||
oneRoundDivThree monkeys items counts inspections
|
||||
|
||||
inspections |> Array.sortInPlace
|
||||
inspections.[inspections.Length - 1] * inspections.[inspections.Length - 2]
|
||||
let struct (a, b) = maxTwo inspections
|
||||
|
||||
let inline oneRound (modulus : int64) (monkeys : Monkey array) (inspections : int64 array) =
|
||||
a * b
|
||||
|
||||
let oneRound
|
||||
(modulus : int64)
|
||||
(monkeys : Monkey array)
|
||||
(items : nativeptr<nativeptr<int64>>)
|
||||
(counts : nativeptr<int>)
|
||||
(inspections : nativeptr<int64>)
|
||||
=
|
||||
for i in 0 .. monkeys.Length - 1 do
|
||||
let monkey = monkeys.[i]
|
||||
inspections.[i] <- inspections.[i] + int64 monkey.StartingItems.Count
|
||||
let entry = NativePtr.add inspections i
|
||||
let countI = NativePtr.get counts i
|
||||
NativePtr.write entry (NativePtr.read entry + int64 countI)
|
||||
|
||||
for worryIndex in 0 .. monkey.StartingItems.Count - 1 do
|
||||
let worry = monkey.StartingItems.[worryIndex]
|
||||
for worryIndex in 0 .. countI - 1 do
|
||||
let worry = NativePtr.get (NativePtr.get items i) worryIndex
|
||||
|
||||
let newWorry =
|
||||
let arg =
|
||||
@@ -234,21 +286,42 @@ module Day11 =
|
||||
else
|
||||
monkey.FalseCase
|
||||
|
||||
monkeys.[target / 1<monkey>].StartingItems.Add newWorry
|
||||
let target = target / 1<monkey>
|
||||
NativePtr.write (NativePtr.add (NativePtr.get items target) (NativePtr.get counts target)) newWorry
|
||||
NativePtr.write (NativePtr.add counts target) (NativePtr.get counts target + 1)
|
||||
|
||||
monkey.StartingItems.Clear ()
|
||||
NativePtr.write (NativePtr.add counts i) 0
|
||||
|
||||
let inline unsafeMaxTwo (len : int) (arr : nativeptr<int64>) : struct (int64 * int64) =
|
||||
let arr0 = NativePtr.read arr
|
||||
let arr1 = NativePtr.get arr 1
|
||||
let mutable best = max arr0 arr1
|
||||
let mutable secondBest = min arr0 arr1
|
||||
|
||||
for i in 2 .. len - 1 do
|
||||
let arrI = NativePtr.get arr i
|
||||
|
||||
if arrI > best then
|
||||
secondBest <- best
|
||||
best <- arrI
|
||||
elif arrI > secondBest then
|
||||
secondBest <- arrI
|
||||
|
||||
struct (secondBest, best)
|
||||
|
||||
let part2 (lines : StringSplitEnumerator) : int64 =
|
||||
let monkeys = parse lines
|
||||
let memory = NativePtr.stackalloc<int64> 1000
|
||||
let monkeys, items, counts = parse memory lines
|
||||
use counts = fixed counts
|
||||
use items = fixed items
|
||||
|
||||
let mutable inspections = Array.zeroCreate<int64> monkeys.Length
|
||||
let inspections = NativePtr.stackalloc<int64> monkeys.Length
|
||||
|
||||
let modulus =
|
||||
(1L, monkeys) ||> Seq.fold (fun i monkey -> i * monkey.TestDivisibleBy)
|
||||
|
||||
for _round in 1..10000 do
|
||||
oneRound modulus monkeys inspections
|
||||
oneRound modulus monkeys items counts inspections
|
||||
|
||||
inspections |> Array.sortInPlace
|
||||
inspections.[inspections.Length - 1] * inspections.[inspections.Length - 2]
|
||||
let struct (a, b) = unsafeMaxTwo monkeys.Length inspections
|
||||
a * b
|
||||
|
Reference in New Issue
Block a user