diff --git a/AdventOfCode2022.App/AdventOfCode2022.App.fsproj b/AdventOfCode2022.App/AdventOfCode2022.App.fsproj
index 580885c..54f0958 100644
--- a/AdventOfCode2022.App/AdventOfCode2022.App.fsproj
+++ b/AdventOfCode2022.App/AdventOfCode2022.App.fsproj
@@ -27,6 +27,7 @@
+
diff --git a/AdventOfCode2022.App/Inputs.fs b/AdventOfCode2022.App/Inputs.fs
index cadaaf1..75ac441 100644
--- a/AdventOfCode2022.App/Inputs.fs
+++ b/AdventOfCode2022.App/Inputs.fs
@@ -2,5 +2,5 @@ namespace AdventOfCode2022.App
[]
module Inputs =
- let days = Array.init 17 (fun day -> Assembly.readResource $"Day%i{day + 1}.txt")
+ let days = Array.init 18 (fun day -> Assembly.readResource $"Day%i{day + 1}.txt")
let inline day (i : int) = days.[i - 1]
diff --git a/AdventOfCode2022.App/Program.fs b/AdventOfCode2022.App/Program.fs
index df409f8..c7025fe 100644
--- a/AdventOfCode2022.App/Program.fs
+++ b/AdventOfCode2022.App/Program.fs
@@ -61,7 +61,7 @@ type Benchmark16To20 () =
[]
member _.Setup () = Run.shouldWrite <- false
- []
+ []
member val Day = 0 with get, set
[]
diff --git a/AdventOfCode2022.App/Run.fs b/AdventOfCode2022.App/Run.fs
index bd9f0d2..7234491 100644
--- a/AdventOfCode2022.App/Run.fs
+++ b/AdventOfCode2022.App/Run.fs
@@ -246,6 +246,20 @@ module Run =
if shouldWrite then
printfn "%i" output
+ let day18 (partTwo : bool) (input : string) =
+ let day18 = StringSplitEnumerator.make '\n' input
+
+ if not partTwo then
+ let output = Day18.part1 day18
+
+ if shouldWrite then
+ printfn "%i" output
+ else
+ let output = Day18.part2 day18
+
+ if shouldWrite then
+ printfn "%i" output
+
let allRuns =
[|
day1
@@ -265,4 +279,5 @@ module Run =
day15
day16
day17
+ day18
|]
diff --git a/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj b/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
index 7e1ebfe..796bb65 100644
--- a/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
+++ b/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
@@ -25,6 +25,7 @@
+
@@ -42,6 +43,7 @@
+
diff --git a/AdventOfCode2022.Test/Day18.fs b/AdventOfCode2022.Test/Day18.fs
new file mode 100644
index 0000000..7be6341
--- /dev/null
+++ b/AdventOfCode2022.Test/Day18.fs
@@ -0,0 +1,51 @@
+namespace AdventOfCode2022.Test
+
+open NUnit.Framework
+open FsUnitTyped
+open AdventOfCode2022
+
+[]
+module TestDay18 =
+
+ let input1 =
+ """1,1,1
+2,1,1
+"""
+
+ let input2 =
+ """2,2,2
+1,2,2
+3,2,2
+2,1,2
+2,3,2
+2,2,1
+2,2,3
+2,2,4
+2,2,6
+1,2,5
+3,2,5
+2,1,5
+2,3,5
+"""
+
+ []
+ let ``Part 1, given`` () =
+ Day18.part1 (StringSplitEnumerator.make '\n' input1) |> shouldEqual 10
+ Day18.part1 (StringSplitEnumerator.make '\n' input2) |> shouldEqual 64
+
+ []
+ let ``Part 1`` () =
+ let input = Assembly.readResource "Day18.txt"
+
+ Day18.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 3542
+
+
+ []
+ let ``Part 2, given`` () =
+ Day18.part2 (StringSplitEnumerator.make '\n' input2) |> shouldEqual 58
+
+ []
+ let ``Part 2`` () =
+ let input = Assembly.readResource "Day18.txt"
+
+ Day18.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 2080
diff --git a/AdventOfCode2022.Test/Inputs/Day18.txt b/AdventOfCode2022.Test/Inputs/Day18.txt
new file mode 100644
index 0000000..5cbd33c
--- /dev/null
+++ b/AdventOfCode2022.Test/Inputs/Day18.txt
@@ -0,0 +1,2057 @@
+4,15,12
+16,10,16
+15,15,10
+14,11,16
+5,7,15
+15,9,12
+8,5,3
+2,9,10
+13,16,9
+2,7,9
+6,5,5
+17,7,10
+6,13,15
+3,14,13
+4,14,13
+3,6,7
+5,16,7
+6,16,12
+16,13,6
+4,10,4
+3,5,8
+3,14,9
+14,9,1
+16,5,9
+16,12,15
+16,7,6
+4,4,9
+17,13,10
+13,4,14
+9,2,10
+5,4,12
+6,9,16
+10,2,13
+18,10,8
+6,4,4
+5,14,5
+7,9,18
+7,14,16
+7,4,15
+9,11,17
+12,10,16
+2,6,8
+5,13,4
+12,2,9
+14,4,16
+9,8,4
+4,10,3
+5,14,4
+13,16,13
+11,8,17
+16,8,15
+3,12,12
+13,13,16
+15,7,6
+13,16,7
+2,10,9
+3,11,5
+3,9,4
+11,15,14
+13,6,13
+4,12,4
+6,2,9
+5,13,9
+3,7,7
+14,8,16
+5,16,11
+7,16,13
+7,6,3
+8,4,4
+14,16,8
+18,7,9
+7,4,14
+14,11,4
+7,9,3
+12,8,1
+11,8,1
+6,15,7
+11,2,12
+1,7,9
+11,10,17
+2,11,6
+13,10,3
+16,13,12
+5,8,3
+8,5,2
+11,7,2
+7,18,12
+14,7,3
+5,10,16
+16,7,12
+9,7,1
+9,16,7
+6,9,17
+16,11,8
+14,12,4
+11,12,3
+7,17,12
+11,3,4
+5,5,14
+3,13,8
+7,17,8
+4,10,12
+16,15,8
+16,11,15
+3,3,9
+15,6,9
+12,4,7
+16,10,14
+16,9,5
+7,12,17
+17,13,9
+2,10,8
+5,3,10
+17,8,5
+12,17,13
+9,15,12
+8,6,16
+8,14,3
+7,2,12
+17,9,6
+7,11,17
+12,5,3
+15,16,9
+8,10,0
+14,9,17
+3,11,9
+15,7,15
+8,16,14
+3,12,15
+15,14,13
+2,9,12
+14,3,7
+9,4,5
+12,2,6
+12,16,11
+13,2,9
+7,15,14
+7,5,3
+17,7,7
+6,8,17
+10,1,9
+10,4,5
+4,17,10
+10,18,10
+8,7,16
+5,2,7
+7,11,2
+2,11,11
+10,3,15
+9,15,14
+9,4,4
+9,11,1
+8,12,16
+7,8,1
+10,3,5
+14,16,10
+4,7,16
+7,12,3
+16,13,14
+4,14,10
+13,2,7
+8,18,7
+10,15,3
+6,5,14
+18,11,12
+4,15,13
+15,5,14
+14,15,14
+10,17,13
+4,15,7
+3,7,12
+7,5,15
+14,4,8
+2,12,11
+9,3,12
+14,9,18
+13,8,2
+5,13,6
+11,16,14
+16,14,8
+16,14,7
+15,10,4
+19,11,9
+12,3,6
+18,11,6
+13,2,12
+14,16,12
+15,10,5
+17,13,6
+3,11,6
+11,3,8
+7,6,17
+3,8,14
+17,6,10
+5,4,8
+9,3,15
+11,13,14
+6,14,6
+5,9,2
+11,5,9
+3,14,10
+4,10,16
+8,6,1
+9,15,4
+9,16,9
+10,4,4
+7,2,10
+13,3,12
+6,6,4
+2,8,12
+18,12,8
+9,9,16
+12,17,15
+4,16,10
+9,16,6
+15,14,5
+4,12,5
+15,4,9
+11,11,2
+9,18,10
+15,5,13
+1,9,8
+16,6,8
+12,2,8
+9,16,12
+7,11,16
+3,10,16
+11,9,16
+3,4,10
+16,12,11
+17,8,13
+4,6,7
+2,7,11
+3,8,16
+9,17,7
+12,9,17
+3,11,7
+14,15,10
+16,5,12
+10,3,7
+15,13,3
+1,10,11
+11,2,6
+7,16,6
+7,12,18
+13,10,17
+5,4,11
+12,13,17
+7,7,17
+12,16,7
+2,8,10
+3,12,8
+16,11,6
+14,5,5
+15,4,10
+14,16,9
+9,3,7
+4,5,12
+11,6,18
+5,3,7
+2,7,7
+15,11,5
+5,3,11
+7,17,11
+8,9,17
+15,5,7
+7,9,17
+14,13,14
+13,6,14
+9,11,2
+5,8,4
+13,5,4
+18,11,13
+7,7,4
+14,8,5
+15,6,6
+13,7,4
+13,3,7
+9,17,11
+16,9,7
+13,16,14
+15,11,16
+9,15,6
+7,17,9
+3,13,11
+4,12,14
+4,6,11
+16,14,13
+10,3,14
+14,7,6
+15,5,5
+4,12,11
+9,7,2
+17,11,12
+16,13,7
+11,8,2
+8,2,8
+15,13,4
+12,3,5
+4,11,5
+9,12,2
+10,15,15
+4,6,4
+9,6,16
+2,8,11
+17,7,12
+3,14,8
+14,4,14
+13,12,15
+3,11,12
+8,17,5
+5,3,13
+10,11,17
+16,10,13
+14,10,3
+13,4,7
+16,7,13
+18,8,11
+8,3,13
+3,8,12
+15,16,13
+17,14,9
+6,2,12
+17,15,10
+10,5,15
+13,16,10
+16,6,15
+6,15,15
+6,7,16
+14,17,9
+10,12,3
+4,7,14
+13,11,2
+8,11,2
+16,6,11
+8,5,5
+7,14,3
+8,17,6
+4,13,5
+7,3,9
+2,8,13
+12,16,6
+17,10,7
+14,7,2
+7,7,16
+7,4,7
+9,2,13
+8,8,17
+8,4,9
+16,12,7
+16,9,15
+8,14,4
+15,6,10
+16,7,14
+7,1,6
+12,7,2
+7,8,2
+10,14,4
+3,14,11
+12,6,15
+14,14,9
+16,5,8
+10,15,11
+2,10,11
+9,14,3
+4,8,5
+7,10,17
+5,14,14
+16,8,5
+9,13,18
+16,3,10
+14,14,5
+11,5,16
+6,4,13
+17,12,7
+7,18,8
+6,6,16
+6,4,14
+13,17,8
+3,8,5
+12,15,15
+8,3,14
+10,16,10
+9,1,11
+6,14,7
+12,3,9
+17,9,13
+8,9,18
+9,15,16
+6,16,10
+12,15,13
+9,6,2
+1,9,12
+6,16,8
+9,6,1
+12,3,14
+10,9,17
+13,13,4
+13,15,7
+11,14,16
+16,10,6
+16,11,13
+5,10,3
+1,11,8
+11,16,8
+10,13,16
+3,3,11
+11,16,7
+14,4,10
+15,11,3
+5,4,6
+9,17,10
+6,15,12
+15,10,16
+11,14,3
+4,7,12
+14,6,3
+18,10,11
+16,5,11
+12,15,11
+6,16,7
+13,4,5
+14,9,4
+11,3,9
+18,7,11
+14,14,6
+11,1,9
+14,4,5
+6,9,3
+4,4,14
+2,13,7
+6,3,9
+6,4,7
+8,1,6
+18,12,10
+9,13,3
+17,13,11
+5,6,5
+4,12,12
+3,7,14
+17,11,6
+10,12,2
+9,2,7
+8,17,13
+5,13,3
+9,10,17
+14,3,10
+15,8,4
+15,5,11
+4,9,15
+17,7,11
+4,5,11
+2,9,11
+10,7,4
+5,17,10
+2,14,9
+13,12,16
+17,13,13
+4,7,5
+4,13,14
+13,4,13
+6,14,4
+5,9,14
+9,4,6
+12,7,16
+9,14,2
+7,17,6
+7,2,8
+13,1,11
+13,9,18
+6,4,16
+10,3,13
+14,5,15
+14,8,3
+14,16,4
+4,4,11
+12,8,18
+5,5,13
+2,9,8
+16,8,8
+15,11,7
+4,9,16
+2,13,11
+5,15,9
+4,8,6
+15,12,6
+4,12,6
+15,10,8
+9,2,4
+13,7,17
+4,14,6
+3,5,12
+15,7,13
+2,11,5
+12,2,11
+3,10,14
+10,9,18
+6,8,16
+11,6,3
+2,7,13
+12,14,16
+8,2,14
+6,17,7
+8,3,6
+8,3,11
+16,9,13
+15,10,14
+9,2,9
+8,16,5
+14,11,14
+3,8,13
+11,12,2
+7,4,4
+7,1,9
+9,13,2
+15,6,5
+11,3,12
+13,6,16
+2,5,6
+17,8,9
+8,4,14
+2,11,7
+6,12,4
+2,6,7
+14,13,6
+10,16,14
+5,3,6
+15,12,7
+17,8,12
+8,4,16
+11,9,1
+14,16,6
+11,11,16
+11,7,17
+10,17,11
+3,7,9
+9,9,17
+10,14,3
+8,5,16
+9,11,16
+8,12,17
+6,10,17
+11,17,11
+11,13,4
+3,7,8
+16,10,8
+6,15,6
+10,17,12
+4,13,8
+3,12,6
+4,4,12
+10,6,2
+10,2,10
+17,4,9
+17,8,14
+14,10,16
+12,7,15
+11,2,15
+16,13,13
+10,16,9
+16,4,7
+6,2,7
+6,4,15
+15,13,13
+5,12,14
+15,14,14
+11,3,6
+14,3,14
+12,7,3
+13,3,5
+10,6,16
+18,8,10
+11,12,16
+7,18,10
+11,4,16
+1,12,8
+11,2,10
+9,6,3
+2,7,14
+4,14,9
+7,14,4
+2,8,7
+10,18,11
+14,12,16
+4,16,11
+9,5,4
+5,11,2
+4,13,11
+8,15,4
+2,5,10
+9,1,6
+6,6,5
+8,4,6
+15,12,14
+12,2,10
+6,14,16
+9,11,18
+16,8,9
+14,3,8
+15,13,14
+13,14,16
+7,12,4
+6,17,12
+1,11,10
+7,9,2
+4,15,14
+13,15,5
+13,10,2
+11,2,8
+7,8,3
+8,18,8
+7,13,16
+4,11,16
+10,19,11
+11,7,16
+17,13,7
+12,5,15
+17,13,12
+2,12,12
+16,11,4
+4,10,14
+13,10,0
+8,11,18
+13,13,14
+12,12,2
+12,15,5
+4,5,14
+10,18,12
+6,13,4
+11,9,18
+14,3,13
+8,10,1
+11,7,3
+15,8,3
+5,13,15
+6,17,8
+15,12,12
+2,8,8
+5,14,11
+5,13,14
+12,2,5
+9,12,17
+6,11,16
+2,12,9
+14,11,15
+15,15,12
+4,14,14
+6,5,3
+12,17,11
+3,16,9
+2,9,14
+16,9,12
+17,5,11
+14,8,15
+9,7,17
+4,5,10
+5,14,8
+7,2,11
+18,8,13
+7,3,12
+12,5,16
+17,10,11
+9,3,14
+2,11,4
+13,3,13
+6,3,7
+14,14,7
+12,14,5
+6,13,3
+6,15,16
+16,13,5
+11,18,10
+16,9,6
+15,3,8
+15,15,7
+16,11,5
+3,9,5
+8,11,17
+8,8,2
+4,12,15
+6,3,6
+8,2,9
+16,12,13
+15,9,14
+9,14,16
+10,16,4
+16,7,10
+15,2,11
+2,8,5
+15,13,5
+3,6,9
+18,9,11
+3,4,7
+14,7,14
+11,11,17
+5,9,4
+2,9,9
+5,7,5
+6,12,3
+5,16,6
+8,13,16
+10,11,3
+12,14,3
+5,12,5
+3,7,6
+17,10,4
+16,6,9
+7,10,3
+3,6,6
+10,2,6
+10,3,10
+8,1,9
+14,9,14
+11,3,5
+2,6,11
+7,13,3
+8,4,10
+16,8,14
+16,10,15
+16,14,12
+16,9,10
+18,9,7
+17,8,8
+3,11,13
+9,3,9
+5,3,9
+6,15,4
+10,13,17
+2,9,6
+3,7,11
+5,6,4
+10,1,10
+6,3,11
+6,14,3
+12,16,14
+10,8,4
+9,10,1
+9,2,11
+6,4,12
+5,4,7
+10,6,3
+7,6,2
+16,12,5
+10,17,10
+14,5,14
+10,15,5
+9,10,16
+15,14,7
+10,17,8
+8,1,8
+14,3,11
+17,10,10
+14,13,13
+7,3,14
+16,14,11
+11,9,2
+4,13,4
+9,16,10
+9,17,5
+2,7,12
+12,12,1
+7,18,11
+2,11,15
+12,14,15
+3,14,6
+3,12,10
+12,11,17
+5,17,8
+3,6,13
+4,9,7
+5,6,3
+7,8,17
+13,2,13
+9,9,3
+13,8,4
+13,17,7
+14,8,14
+12,10,17
+1,9,9
+15,6,12
+8,3,5
+4,9,5
+10,10,2
+9,5,17
+3,15,10
+10,17,6
+16,14,9
+13,6,3
+3,15,9
+9,11,3
+13,9,15
+7,14,5
+15,11,4
+6,15,5
+7,1,8
+15,13,12
+7,1,11
+12,16,12
+3,14,14
+4,6,6
+10,9,3
+15,4,13
+17,12,8
+2,12,8
+16,6,12
+8,15,5
+9,6,17
+13,8,16
+16,13,9
+6,14,5
+8,7,2
+11,10,2
+5,9,3
+12,4,14
+10,7,2
+3,3,7
+12,9,1
+12,3,12
+5,16,12
+16,6,6
+10,3,8
+12,6,4
+10,13,4
+6,7,17
+2,9,7
+17,12,13
+16,9,4
+9,16,3
+3,16,8
+14,14,14
+7,4,13
+6,4,5
+14,3,12
+13,15,11
+18,9,8
+3,7,5
+8,3,9
+14,6,15
+4,3,7
+16,14,10
+8,14,14
+11,18,9
+7,3,10
+8,8,18
+4,11,15
+2,8,9
+12,5,2
+3,10,15
+13,16,5
+5,6,16
+1,12,11
+16,6,10
+5,11,14
+16,14,14
+10,11,0
+15,8,6
+8,5,4
+12,2,12
+12,3,11
+17,6,12
+6,12,17
+7,6,16
+11,17,14
+8,12,2
+1,9,11
+15,7,4
+11,2,13
+6,3,12
+7,12,2
+16,9,11
+5,15,6
+16,5,7
+13,12,17
+17,9,11
+9,8,2
+11,16,16
+5,12,16
+15,7,12
+3,10,7
+17,5,10
+15,8,13
+16,12,10
+17,11,7
+3,12,5
+3,12,9
+9,17,12
+15,3,9
+12,4,5
+4,6,8
+13,14,14
+9,8,1
+7,3,11
+11,16,10
+11,16,6
+9,5,2
+14,16,11
+1,12,9
+9,9,2
+17,7,8
+9,13,16
+8,15,15
+14,14,13
+1,7,10
+12,8,17
+4,11,3
+9,1,9
+12,10,3
+16,5,10
+13,5,16
+9,1,12
+14,15,8
+15,14,12
+10,2,14
+11,17,10
+17,10,12
+5,14,3
+3,7,10
+12,13,3
+16,14,5
+9,5,16
+11,14,2
+11,13,1
+10,8,18
+8,10,2
+9,10,18
+3,14,5
+5,10,4
+8,7,15
+11,3,13
+12,14,4
+6,13,5
+8,1,11
+15,14,10
+13,4,11
+10,15,6
+15,9,16
+18,9,10
+6,17,9
+15,10,3
+10,10,1
+4,5,13
+17,6,8
+14,13,3
+10,5,17
+9,14,15
+9,8,0
+7,3,6
+3,4,11
+2,8,14
+5,8,17
+15,5,9
+15,8,5
+4,10,15
+14,3,6
+5,14,6
+7,13,15
+5,5,4
+10,17,7
+13,13,17
+6,11,2
+8,10,17
+9,8,17
+17,6,7
+10,10,15
+4,14,7
+7,2,9
+11,15,11
+8,1,7
+14,7,17
+15,3,10
+12,10,1
+10,8,3
+13,3,9
+13,4,4
+11,6,17
+15,6,4
+15,7,3
+5,12,3
+13,16,12
+9,7,3
+15,6,11
+4,5,6
+6,14,14
+12,8,14
+8,15,16
+13,4,9
+6,10,16
+16,15,9
+10,15,4
+3,6,11
+3,7,13
+10,5,3
+8,6,3
+18,11,9
+8,16,13
+2,12,7
+9,18,11
+8,15,6
+12,13,14
+17,5,9
+6,11,14
+17,13,8
+10,15,7
+15,5,6
+5,5,6
+9,9,18
+14,7,8
+7,4,6
+14,15,13
+11,6,16
+4,12,7
+11,11,1
+12,4,13
+12,14,17
+9,17,6
+9,15,15
+6,17,11
+9,11,4
+12,17,9
+13,11,18
+16,5,13
+15,6,13
+4,12,9
+11,6,2
+3,11,11
+12,3,10
+6,15,11
+15,9,15
+4,15,8
+14,12,5
+9,17,8
+1,12,10
+2,13,12
+10,3,4
+5,4,4
+13,11,15
+14,10,4
+9,16,11
+1,13,8
+5,15,8
+11,2,5
+4,5,9
+13,11,17
+8,16,3
+10,5,2
+2,10,7
+13,15,6
+14,5,4
+10,13,2
+13,15,14
+10,7,3
+6,11,3
+1,9,7
+6,11,18
+6,4,10
+16,12,9
+10,4,3
+5,6,6
+15,5,8
+4,12,16
+8,16,7
+11,9,4
+6,7,3
+14,10,17
+5,13,5
+5,15,12
+11,15,15
+16,10,5
+13,17,6
+16,7,9
+2,11,12
+9,14,1
+10,10,18
+4,3,8
+7,16,5
+8,2,13
+8,17,11
+13,5,13
+8,2,11
+4,4,13
+13,7,16
+3,12,4
+14,6,5
+9,3,11
+8,12,1
+17,9,8
+12,4,6
+10,17,9
+14,6,14
+8,17,12
+10,1,7
+11,15,13
+4,7,4
+7,7,15
+2,6,12
+17,10,5
+16,9,3
+3,10,5
+7,10,15
+10,10,17
+11,5,4
+12,11,3
+10,2,5
+6,6,3
+11,1,8
+1,6,7
+6,8,4
+2,7,6
+12,16,5
+4,16,7
+4,6,10
+2,9,4
+12,9,18
+5,17,12
+5,5,8
+18,10,9
+14,2,7
+1,9,10
+8,10,5
+5,2,6
+8,3,12
+14,14,15
+6,16,11
+7,14,11
+2,9,13
+3,8,6
+16,12,4
+6,8,15
+10,16,13
+3,9,14
+2,6,6
+8,16,15
+11,4,15
+1,6,11
+7,16,15
+11,2,14
+11,3,11
+17,12,11
+6,3,14
+12,3,7
+2,5,11
+16,6,5
+13,18,10
+4,8,13
+14,17,11
+5,16,10
+8,17,10
+11,13,15
+15,15,8
+7,3,8
+4,13,15
+13,17,10
+4,2,10
+3,7,4
+10,12,18
+8,18,11
+1,13,9
+3,13,13
+11,5,15
+11,13,3
+15,15,9
+17,9,7
+15,4,6
+7,12,16
+15,13,9
+8,2,12
+14,4,7
+15,3,7
+11,7,1
+5,7,4
+13,7,3
+12,16,8
+15,5,12
+1,13,10
+10,15,13
+12,6,17
+5,17,7
+5,7,16
+12,18,8
+4,9,13
+11,10,1
+1,9,6
+7,15,15
+13,14,3
+17,10,13
+16,15,5
+4,3,10
+10,11,18
+3,6,12
+3,15,8
+11,15,5
+10,1,8
+12,4,4
+15,4,11
+3,12,11
+17,7,6
+14,4,9
+5,12,4
+12,5,5
+9,1,8
+9,4,16
+8,9,16
+12,1,11
+14,4,11
+2,15,10
+17,12,6
+12,8,2
+10,4,15
+12,7,14
+4,8,3
+3,10,4
+8,6,4
+17,11,8
+15,14,9
+7,6,4
+17,9,12
+3,9,7
+7,12,13
+14,15,5
+13,4,6
+10,12,1
+11,3,15
+2,6,9
+16,4,13
+9,5,13
+4,6,14
+13,9,2
+15,9,4
+17,11,13
+4,4,6
+6,14,13
+13,13,3
+9,8,3
+11,5,2
+13,11,14
+16,8,11
+16,10,10
+13,14,5
+14,5,9
+9,3,6
+1,11,6
+14,15,12
+9,18,8
+13,7,15
+1,10,7
+9,4,13
+7,15,8
+8,16,8
+12,9,3
+5,15,7
+3,9,16
+8,18,12
+6,2,8
+4,16,6
+11,15,4
+6,13,16
+8,10,3
+13,14,2
+11,11,18
+7,16,12
+15,6,14
+11,3,10
+11,4,7
+14,4,6
+12,3,8
+14,11,3
+16,7,11
+7,11,4
+2,13,9
+14,3,9
+5,2,10
+3,12,7
+13,15,13
+9,6,15
+13,7,2
+14,9,15
+9,1,10
+17,6,11
+9,12,16
+11,3,7
+8,11,16
+13,10,16
+11,15,12
+10,16,15
+4,15,10
+12,12,3
+14,17,10
+7,13,2
+10,5,16
+13,15,15
+5,4,13
+1,10,10
+14,15,9
+9,16,14
+18,14,9
+16,13,11
+5,15,13
+5,13,13
+10,17,4
+8,6,15
+1,7,11
+3,10,12
+4,11,6
+11,8,16
+2,7,8
+2,10,13
+8,4,7
+5,11,3
+10,15,16
+8,2,5
+7,5,6
+2,7,10
+6,5,4
+1,6,10
+5,15,4
+2,9,5
+5,15,14
+3,5,9
+12,11,18
+5,16,13
+10,8,1
+10,15,12
+10,2,12
+14,16,7
+13,11,3
+10,2,11
+11,17,13
+5,11,15
+7,13,17
+10,2,9
+5,7,3
+10,16,6
+5,6,14
+4,4,7
+13,9,17
+14,13,15
+3,14,7
+14,13,8
+18,12,13
+12,17,12
+16,9,8
+4,15,6
+9,15,13
+7,11,1
+3,10,8
+10,11,15
+3,13,6
+4,9,3
+12,6,2
+16,8,4
+17,7,9
+6,9,2
+13,2,11
+11,15,16
+10,10,3
+5,11,16
+15,8,12
+5,14,10
+8,12,3
+1,10,8
+4,10,6
+5,2,5
+3,13,9
+8,6,17
+15,11,15
+5,9,16
+7,17,10
+9,17,9
+7,16,4
+8,15,14
+10,13,3
+12,5,4
+15,16,10
+3,5,7
+7,3,13
+13,2,10
+8,13,17
+3,5,10
+6,15,14
+11,12,17
+15,15,11
+2,7,4
+10,9,0
+13,16,8
+17,8,7
+6,10,2
+11,14,17
+12,18,10
+4,8,15
+7,2,7
+8,16,9
+6,7,15
+5,5,3
+17,14,11
+15,4,7
+14,13,4
+13,3,6
+13,3,11
+7,15,4
+16,7,7
+9,16,13
+12,5,12
+7,10,16
+14,7,15
+5,12,13
+10,12,17
+13,13,15
+11,8,3
+17,9,14
+13,17,11
+1,8,10
+5,6,13
+4,17,12
+3,9,12
+4,11,4
+9,2,12
+5,16,14
+14,5,10
+3,8,11
+14,7,4
+9,17,14
+7,4,3
+15,7,5
+13,4,12
+5,1,10
+17,10,8
+8,14,17
+5,17,9
+3,11,15
+12,3,4
+4,13,6
+6,7,1
+1,10,9
+16,4,9
+17,5,8
+8,14,16
+5,4,9
+10,14,17
+16,6,13
+3,13,7
+17,14,10
+9,7,16
+14,9,3
+14,5,13
+14,11,2
+6,14,15
+6,5,6
+11,14,5
+5,12,15
+5,10,2
+12,13,15
+15,4,8
+12,15,6
+16,11,12
+13,5,5
+18,12,9
+11,4,4
+16,11,7
+5,7,2
+14,4,12
+11,5,17
+6,10,15
+13,10,4
+7,4,12
+12,11,16
+5,14,15
+18,9,9
+4,13,2
+16,13,8
+4,3,11
+15,4,14
+8,13,18
+11,7,4
+7,15,16
+9,18,12
+5,4,14
+12,17,7
+6,11,5
+6,14,10
+3,14,12
+9,4,14
+8,11,1
+14,2,9
+12,1,10
+4,13,13
+6,2,13
+5,8,15
+13,7,14
+17,11,11
+10,3,11
+10,15,14
+4,14,12
+5,13,16
+5,10,14
+4,7,13
+6,2,11
+5,11,17
+12,9,16
+1,8,13
+2,13,6
+13,3,8
+14,15,4
+16,15,7
+17,8,10
+4,13,3
+2,12,10
+12,15,7
+9,3,5
+6,3,10
+15,12,15
+11,17,9
+16,8,13
+17,11,14
+9,1,7
+6,10,4
+9,2,6
+4,15,9
+5,15,11
+7,16,9
+6,2,10
+8,5,14
+14,8,4
+7,4,11
+15,16,11
+16,12,14
+9,13,4
+8,3,15
+17,11,5
+15,6,7
+11,3,14
+18,9,12
+14,10,14
+2,11,13
+15,10,6
+17,10,9
+9,7,4
+14,10,5
+16,10,12
+10,7,17
+3,5,6
+13,16,6
+12,11,4
+7,16,8
+6,5,10
+13,14,4
+11,14,14
+6,8,2
+6,5,15
+17,8,6
+8,13,2
+14,15,11
+2,14,7
+15,12,4
+15,10,15
+13,4,16
+12,16,4
+6,13,6
+17,11,15
+12,11,2
+11,2,7
+14,13,16
+14,4,15
+16,9,14
+6,5,7
+12,16,13
+8,4,15
+8,3,4
+12,15,4
+9,8,16
+6,11,17
+5,15,10
+3,6,4
+11,4,8
+7,14,14
+5,4,10
+10,18,9
+14,12,3
+18,9,6
+14,14,10
+1,8,11
+5,14,12
+12,3,13
+9,16,5
+12,10,2
+3,9,13
+14,4,13
+16,15,11
+6,6,15
+14,13,17
+2,11,10
+14,16,14
+5,2,11
+8,15,2
+3,13,5
+10,7,16
+14,5,12
+15,8,16
+11,16,15
+9,3,13
+4,7,11
+4,6,5
+16,5,14
+2,14,8
+8,8,1
+17,6,9
+13,4,15
+2,8,6
+14,12,12
+13,4,3
+4,13,12
+16,8,16
+6,4,6
+12,13,5
+14,12,11
+8,11,14
+7,1,10
+18,11,10
+1,10,12
+15,16,8
+8,13,3
+11,13,2
+10,5,5
+4,15,11
+12,15,14
+12,16,15
+9,15,7
+12,15,16
+8,0,8
+10,18,8
+1,8,7
+18,6,10
+10,3,12
+13,9,4
+7,17,13
+6,14,2
+11,0,9
+16,12,6
+13,17,12
+4,4,10
+17,10,14
+16,8,12
+7,4,16
+1,10,6
+5,10,17
+6,13,14
+13,15,16
+6,7,5
+6,12,15
+16,4,10
+10,6,14
+14,6,4
+7,5,4
+16,7,8
+11,9,17
+5,9,15
+10,9,2
+11,5,3
+3,3,10
+10,16,5
+11,6,4
+4,10,5
+2,10,14
+7,15,11
+12,15,12
+5,14,13
+15,8,14
+6,13,17
+8,15,13
+7,2,13
+18,8,7
+7,16,16
+15,6,8
+12,7,18
+10,5,14
+17,9,10
+13,8,15
+18,11,7
+15,13,6
+10,6,17
+4,11,12
+18,11,8
+13,2,14
+12,17,10
+1,9,13
+3,13,12
+16,11,14
+9,5,6
+18,10,12
+15,9,6
+12,16,10
+7,5,16
+15,16,7
+9,16,15
+6,12,16
+13,9,1
+14,14,4
+2,13,10
+6,17,10
+5,11,9
+4,4,8
+19,7,9
+14,8,6
+14,13,5
+1,8,8
+12,17,6
+13,15,8
+15,3,11
+6,16,13
+7,15,10
+8,5,18
+5,4,3
+14,16,15
+13,6,17
+14,9,2
+16,10,4
+7,16,7
+9,3,16
+6,16,9
+10,8,17
+3,5,13
+13,13,6
+8,9,2
+13,16,11
+13,17,9
+14,15,7
+3,13,4
+5,8,16
+4,8,14
+8,18,9
+9,12,1
+3,5,11
+15,14,6
+5,8,2
+18,13,13
+4,10,17
+8,6,2
+14,11,17
+15,11,14
+4,7,6
+4,16,12
+16,6,7
+12,16,9
+12,2,7
+7,3,4
+14,9,16
+7,6,5
+5,16,9
+3,10,9
+10,10,16
+8,9,3
+17,10,6
+6,2,6
+4,16,9
+7,9,14
+7,3,15
+6,11,1
+9,12,19
+18,5,8
+6,11,4
+14,15,6
+9,4,15
+13,15,9
+2,14,13
+6,11,15
+13,9,16
+3,9,8
+10,7,18
+18,11,11
+6,10,3
+13,12,2
+10,16,7
+4,3,13
+17,12,12
+13,9,3
+15,12,5
+2,10,10
+12,7,17
+13,8,3
+12,15,3
+13,1,10
+8,10,18
+8,4,13
+11,2,11
+3,11,14
+13,13,2
+13,10,15
+7,3,7
+13,1,8
+4,16,8
+13,18,7
+14,11,5
+2,12,13
+15,2,8
+5,17,11
+2,13,14
+13,2,8
+12,5,14
+9,13,15
+14,14,12
+3,6,8
+15,15,13
+7,16,14
+4,13,9
+11,15,3
+15,16,12
+3,13,10
+9,2,8
+13,7,5
+15,14,16
+12,18,11
+12,13,16
+10,13,15
+8,15,3
+3,9,6
+17,11,9
+7,14,13
+13,5,15
+3,4,9
+10,2,8
+4,3,9
+15,15,6
+4,6,12
+13,8,17
+16,12,8
+16,4,8
+5,3,14
+9,18,9
+3,10,6
+7,4,5
+13,14,7
+5,10,6
+9,12,3
+14,10,15
+11,1,7
+18,6,9
+15,15,14
+17,8,11
+8,14,15
+16,12,12
+15,3,12
+4,11,14
+12,17,8
+8,1,12
+3,9,15
+3,15,12
+13,14,13
+12,6,16
+14,15,16
+10,4,17
+14,6,13
+3,8,9
+2,11,9
+10,6,15
+8,2,10
+12,14,2
+11,1,11
+15,9,8
+4,9,4
+11,10,5
+6,9,14
+17,7,13
+18,13,9
+8,7,1
+0,10,7
+9,6,4
+5,3,8
+8,5,17
+7,15,13
+11,15,7
+3,12,13
+3,10,13
+13,6,15
+8,3,10
+8,7,17
+11,17,12
+16,4,11
+4,5,4
+15,9,13
+15,5,10
+10,11,16
+13,13,13
+5,6,7
+14,11,8
+10,18,6
+13,6,5
+16,3,11
+6,3,4
+1,6,12
+5,5,15
+11,16,12
+11,14,18
+10,12,15
+8,3,7
+12,8,4
+15,13,7
+12,12,16
+13,11,16
+15,11,12
+9,6,6
+7,10,19
+14,12,15
+14,7,12
+17,9,9
+6,7,4
+15,8,10
+8,2,7
+5,16,8
+7,9,15
+7,7,3
+16,5,6
+12,11,14
+17,12,10
+5,5,7
+14,2,8
+11,15,2
+6,18,11
+10,18,7
+1,10,13
+15,12,3
+11,12,1
+6,3,8
+3,3,8
+12,9,2
+9,4,3
+11,2,9
+4,8,4
+11,5,6
+15,14,8
+10,11,2
+6,6,14
+6,3,5
+4,14,5
+10,12,16
+12,8,13
+16,8,6
+6,9,15
+12,19,10
+18,7,8
+7,5,2
+2,15,9
+14,12,13
+9,2,5
+7,18,7
+9,0,9
+13,15,12
+2,5,12
+14,13,10
+18,13,10
+9,15,2
+16,10,7
+7,4,17
+8,17,9
+9,14,14
+6,5,8
+12,1,12
+9,17,13
+4,6,13
+2,10,6
+9,14,4
+7,6,15
+3,15,13
+6,1,9
+11,15,6
+11,13,17
+8,14,2
+11,12,18
+17,11,4
+11,11,3
+15,17,12
+3,10,11
+2,11,8
+5,4,5
+8,2,6
+8,16,12
+7,15,3
+4,8,8
+6,9,1
+15,11,13
+3,4,6
+8,16,6
+7,8,16
+5,11,13
+14,12,17
+12,18,9
+4,11,9
+17,9,5
+7,18,6
+12,14,6
+15,11,9
+5,6,15
+7,16,10
+12,4,15
+11,17,8
+16,5,5
+9,3,8
+7,10,2
+8,1,10
+13,3,10
+11,10,16
+14,6,6
+11,4,5
+15,17,10
+11,14,15
+16,7,4
+12,1,8
+4,16,13
+10,2,7
+13,17,13
+4,14,16
+7,5,5
+14,6,16
+6,15,10
+15,14,11
+7,13,12
+6,5,16
+3,4,8
+16,9,9
+2,13,8
+10,4,16
+10,4,14
+5,9,9
+3,9,10
+1,8,9
+4,14,11
+11,8,15
+15,7,16
+5,7,14
+5,11,12
+10,14,13
+12,8,3
+4,14,4
+10,17,5
+9,7,15
+8,14,5
+11,16,13
+9,7,5
+15,5,4
+15,3,6
+9,18,13
+3,13,14
+15,11,6
+16,15,10
+13,15,10
+9,17,4
+5,12,17
+9,15,17
+12,12,18
+13,14,15
+9,13,17
+16,8,3
+15,6,3
+14,7,5
+4,17,8
+10,16,8
+9,9,1
+12,5,13
+12,5,6
diff --git a/AdventOfCode2022/AdventOfCode2022.fsproj b/AdventOfCode2022/AdventOfCode2022.fsproj
index 849abb2..e21aa73 100644
--- a/AdventOfCode2022/AdventOfCode2022.fsproj
+++ b/AdventOfCode2022/AdventOfCode2022.fsproj
@@ -10,6 +10,7 @@
+
@@ -28,6 +29,7 @@
+
diff --git a/AdventOfCode2022/Arr3D.fs b/AdventOfCode2022/Arr3D.fs
new file mode 100644
index 0000000..16d5ae0
--- /dev/null
+++ b/AdventOfCode2022/Arr3D.fs
@@ -0,0 +1,100 @@
+namespace AdventOfCode2022
+
+#if DEBUG
+#else
+#nowarn "9"
+#endif
+
+open Microsoft.FSharp.NativeInterop
+
+[]
+#if DEBUG
+type Arr3D<'a> =
+ {
+ Elements : 'a array
+ Width : int
+ WidthTimesHeight : int
+ }
+
+ member this.Depth = this.Elements.Length / this.WidthTimesHeight
+#else
+type Arr3D<'a when 'a : unmanaged> =
+ {
+ Elements : nativeptr<'a>
+ Length : int
+ Width : int
+ WidthTimesHeight : int
+ }
+
+ member this.Depth = this.Length / this.WidthTimesHeight
+#endif
+
+[]
+module Arr3D =
+
+ /// It's faster to iterate forward over the first argument, `x`, and then the
+ /// second argument, `y`.
+ let inline get (arr : Arr3D<'a>) (x : int) (y : int) (z : int) : 'a =
+#if DEBUG
+ arr.Elements.[z * arr.WidthTimesHeight + y * arr.Width + x]
+#else
+ NativePtr.get arr.Elements (z * arr.WidthTimesHeight + y * arr.Width + x)
+#endif
+
+ let inline set (arr : Arr3D<'a>) (x : int) (y : int) (z : int) (newVal : 'a) : unit =
+#if DEBUG
+ arr.Elements.[z * arr.WidthTimesHeight + y * arr.Width + x] <- newVal
+#else
+ NativePtr.write (NativePtr.add arr.Elements (z * arr.WidthTimesHeight + y * arr.Width + x)) newVal
+#endif
+
+#if DEBUG
+ let create (width : int) (height : int) (depth : int) (value : 'a) : Arr3D<'a> =
+ let arr = Array.create (width * height * depth) value
+
+ {
+ Width = width
+ WidthTimesHeight = width * height
+ Elements = arr
+ }
+#else
+ /// The input array must be at least of size width * height * depth
+ let create (arr : nativeptr<'a>) (width : int) (height : int) (depth : int) (value : 'a) : Arr3D<'a> =
+ {
+ Width = width
+ Elements = arr
+ Length = width * height * depth
+ WidthTimesHeight = width * height
+ }
+#endif
+
+ []
+#if DEBUG
+ let zeroCreate<'a when 'a : unmanaged> (width : int) (height : int) (depth : int) : Arr3D<'a> =
+ {
+ Elements = Array.zeroCreate (width * height * depth)
+ Width = width
+ WidthTimesHeight = width * height
+ }
+#else
+ let zeroCreate<'a when 'a : unmanaged>
+ (elts : nativeptr<'a>)
+ (width : int)
+ (height : int)
+ (depth : int)
+ : Arr3D<'a>
+ =
+ {
+ Elements = elts
+ Width = width
+ WidthTimesHeight = width * height
+ Length = width * height * depth
+ }
+#endif
+
+ let inline clear (a : Arr3D<'a>) : unit =
+#if DEBUG
+ System.Array.Clear a.Elements
+#else
+ NativePtr.initBlock a.Elements 0uy (uint32 sizeof<'a> * uint32 a.Length)
+#endif
diff --git a/AdventOfCode2022/Day16.fs b/AdventOfCode2022/Day16.fs
index f5ebf41..ae2c81b 100644
--- a/AdventOfCode2022/Day16.fs
+++ b/AdventOfCode2022/Day16.fs
@@ -16,7 +16,7 @@ module Day16 =
type Node = int
/// Returns the nodes, and also the "AA" node.
- let parse (lines : string seq) : Map * Node =
+ let parse (lines : string seq) : Map * Node =
let allNodes =
lines
|> Seq.filter (not << String.IsNullOrEmpty)
@@ -31,7 +31,10 @@ module Day16 =
allNodes
|> Map.toSeq
|> Seq.map (fun (key, (node, (weight, outbound))) ->
- node, (weight, (Set.map (fun x -> fst (Map.find x allNodes)) outbound))
+ let outbound =
+ outbound |> Seq.map (fun x -> Map.find x allNodes |> fst) |> IntSet.ofSeq
+
+ node, (weight, outbound)
)
|> Map.ofSeq
@@ -50,36 +53,48 @@ module Day16 =
Some answer
- let tryMin (s : seq<'a>) : 'a option =
+ let tryMin (s : seq<'a>) : 'a ValueOption =
use enum = s.GetEnumerator ()
if not (enum.MoveNext ()) then
- None
+ ValueNone
else
let mutable answer = enum.Current
while enum.MoveNext () do
answer <- min answer enum.Current
- Some answer
+ ValueSome answer
let getShortestPathLength (valves : Map<_, _>) : Node -> Node -> int =
- let rec go (seenSoFar : Node Set) (v1 : Node) (v2 : Node) =
+ let rec go (seenSoFar : IntSet) (v1 : Node) (v2 : Node) : int =
let v2Neighbours = snd valves.[v2]
if v1 = v2 then
- Some 0
- elif Set.contains v1 v2Neighbours then
- Some 1
- elif Set.contains v2 seenSoFar then
- None
+ 0
+ elif IntSet.contains v2Neighbours v1 then
+ 1
+ elif IntSet.contains seenSoFar v2 then
+ -1
else
- v2Neighbours
- |> Seq.choose (go (Set.add v2 seenSoFar) v1)
- |> tryMin
- |> Option.map ((+) 1)
+ let mutable best = Int32.MaxValue
+ let mutable neighbours = v2Neighbours
+ let mutable neighbour = 0
- fun v1 v2 -> go Set.empty v1 v2 |> Option.get
+ while neighbours > 0 do
+ if neighbours % 2L = 1L then
+ match go (IntSet.set seenSoFar v2) v1 neighbour with
+ | -1 -> ()
+ | next ->
+ if next < best then
+ best <- next
+
+ neighbours <- neighbours >>> 1
+ neighbour <- neighbour + 1
+
+ if best = Int32.MaxValue then -1 else best + 1
+
+ fun v1 v2 -> go IntSet.empty v1 v2
let part1 (lines : string seq) : int =
diff --git a/AdventOfCode2022/Day17.fs b/AdventOfCode2022/Day17.fs
index 7fefe1e..6af4288 100644
--- a/AdventOfCode2022/Day17.fs
+++ b/AdventOfCode2022/Day17.fs
@@ -65,12 +65,13 @@ module Day17 =
let y = currentBase + row - shape.Length + 1
Arr2D.set startGrid x y 1
- let moveJet (direction : Direction) (currentBase : int) (startGrid : Arr2D) : unit =
+ let inline moveJet (direction : Direction) (currentBase : int) (startGrid : Arr2D) : unit =
match direction with
| Direction.Left ->
let mutable canMove = true
+ let mutable row = currentBase
- for row in currentBase .. -1 .. currentBase - 3 do
+ while row >= currentBase - 3 && canMove do
if Arr2D.get startGrid 0 row = 1 then
canMove <- false
else
@@ -78,6 +79,8 @@ module Day17 =
if Arr2D.get startGrid col row = 1 && Arr2D.get startGrid (col - 1) row = 2 then
canMove <- false
+ row <- row - 1
+
if canMove then
for row in currentBase .. -1 .. currentBase - 3 do
for col in 0..5 do
@@ -89,8 +92,9 @@ module Day17 =
Arr2D.set startGrid 6 row 0
| Direction.Right ->
let mutable canMove = true
+ let mutable row = currentBase
- for row in currentBase .. -1 .. currentBase - 3 do
+ while row >= currentBase - 3 && canMove do
if Arr2D.get startGrid 6 row = 1 then
canMove <- false
else
@@ -98,6 +102,8 @@ module Day17 =
if Arr2D.get startGrid col row = 1 && Arr2D.get startGrid (col + 1) row = 2 then
canMove <- false
+ row <- row - 1
+
if canMove then
for row in currentBase .. -1 .. currentBase - 3 do
for col in 6..-1..1 do
@@ -109,9 +115,9 @@ module Day17 =
Arr2D.set startGrid 0 row 0
| _ -> failwith "Unexpected direction"
- /// Returns the new currentBase if we're still falling, or None if we're not
- /// still falling.
- let fallOnce (currentBase : int) (startGrid : Arr2D) : int option =
+ /// Returns the new currentBase if we're still falling, or -1 if we're not
+ /// still falling. (Allocation of a ValueNone was actually nontrivially slow!)
+ let fallOnce (currentBase : int) (startGrid : Arr2D) : int =
let mutable isFalling = true
// Fall one place. Can we fall?
@@ -130,7 +136,7 @@ module Day17 =
Arr2D.set startGrid col (row + 1) 1
Arr2D.set startGrid col row 0
- Some (currentBase + 1)
+ currentBase + 1
else
for row in currentBase .. -1 .. currentBase - 3 do
for col in 0..6 do
@@ -138,7 +144,7 @@ module Day17 =
// Freeze in place
Arr2D.set startGrid col row 2
- None
+ -1
let findCurrentTop (currentTop : int) (startGrid : Arr2D) : int =
let mutable currentTop = currentTop
@@ -203,8 +209,8 @@ module Day17 =
jetCount <- (jetCount + 1) % directions.Length
match fallOnce currentBase startGrid with
- | Some newCurrentBase -> currentBase <- newCurrentBase
- | None -> isFalling <- false
+ | -1 -> isFalling <- false
+ | newCurrentBase -> currentBase <- newCurrentBase
// Set new currentTop
currentTop <- findCurrentTop currentTop startGrid
@@ -259,8 +265,8 @@ module Day17 =
jetCount <- (jetCount + 1) % directions.Length
match fallOnce currentBase startGrid with
- | Some newCurrentBase -> currentBase <- newCurrentBase
- | None -> isFalling <- false
+ | -1 -> isFalling <- false
+ | newCurrentBase -> currentBase <- newCurrentBase
// Set new currentTop
currentTop <- findCurrentTop currentTop startGrid
diff --git a/AdventOfCode2022/Day18.fs b/AdventOfCode2022/Day18.fs
new file mode 100644
index 0000000..0b84c09
--- /dev/null
+++ b/AdventOfCode2022/Day18.fs
@@ -0,0 +1,196 @@
+namespace AdventOfCode2022
+
+open System
+open System.Collections.Generic
+open FSharp.Collections.ParallelSeq
+
+#if DEBUG
+open Checked
+#else
+#nowarn "9"
+#endif
+
+
+[]
+module Day18 =
+
+ /// Returns the points, and also minX, minY, minZ, maxX, maxY, maxZ.
+ let parse
+ (line : StringSplitEnumerator)
+ : struct (int * int * int) ResizeArray * int * int * int * int * int * int
+ =
+ use mutable enum = line.GetEnumerator ()
+ let output = ResizeArray ()
+ let mutable minX = Int32.MaxValue
+ let mutable minY = Int32.MaxValue
+ let mutable minZ = Int32.MaxValue
+ let mutable maxX = Int32.MinValue
+ let mutable maxY = Int32.MinValue
+ let mutable maxZ = Int32.MinValue
+
+ while enum.MoveNext () do
+ if not (enum.Current.IsWhiteSpace ()) then
+ let mutable split = StringSplitEnumerator.make' ',' enum.Current
+ let x = StringSplitEnumerator.consumeInt &split
+
+ if x < minX then
+ minX <- x
+
+ if x > maxX then
+ maxX <- x
+
+ let y = StringSplitEnumerator.consumeInt &split
+
+ if y < minY then
+ minY <- y
+
+ if y > maxY then
+ maxY <- y
+
+ let z = StringSplitEnumerator.consumeInt &split
+
+ if z < minZ then
+ minZ <- z
+
+ if z > maxZ then
+ maxZ <- z
+
+ assert (not (split.MoveNext ()))
+ output.Add (struct (x, y, z))
+
+ output, minX, minY, minZ, maxX, maxY, maxZ
+
+ let inline private doPart1
+ (cubes : ResizeArray<_>)
+ (arr : Arr3D)
+ (minX : int)
+ (minY : int)
+ (minZ : int)
+ maxX
+ maxY
+ maxZ
+ =
+ let mutable exposedFaces = 0
+
+ let maxX = maxX - minX
+ let maxY = maxY - minY
+ let maxZ = maxZ - minZ
+
+ for i in 0 .. cubes.Count - 1 do
+ let struct (x, y, z) = cubes.[i]
+ let x = x - minX
+ let y = y - minY
+ let z = z - minZ
+
+ if not (x > 0 && Arr3D.get arr (x - 1) y z = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ if not (x < maxX && Arr3D.get arr (x + 1) y z = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ if not (y > 0 && Arr3D.get arr x (y - 1) z = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ if not (y < maxY && Arr3D.get arr x (y + 1) z = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ if not (z > 0 && Arr3D.get arr x y (z - 1) = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ if not (z < maxZ && Arr3D.get arr x y (z + 1) = 1) then
+ exposedFaces <- exposedFaces + 1
+
+ exposedFaces
+
+ let part1 (line : StringSplitEnumerator) : int =
+ let cubes, minX, minY, minZ, maxX, maxY, maxZ = parse line
+
+ let xSpan = maxX - minX + 1
+ let ySpan = maxY - minY + 1
+ let zSpan = maxZ - minZ + 1
+
+#if DEBUG
+ let arr = Arr3D.zeroCreate xSpan ySpan zSpan
+#else
+ let backing = Array.zeroCreate (xSpan * ySpan * zSpan)
+ use ptr = fixed backing
+ let arr = Arr3D.zeroCreate ptr xSpan ySpan zSpan
+#endif
+
+ for i in 0 .. cubes.Count - 1 do
+ let struct (x, y, z) = cubes.[i]
+ Arr3D.set arr (x - minX) (y - minY) (z - minZ) 1
+
+ doPart1 cubes arr minX minY minZ maxX maxY maxZ
+
+ // Semantics:
+ // 3 means "in progress",
+ // 2 means "this definitely flood fills to the outside",
+ // 1 means "definitely full",
+ // 0 means "initially empty",
+ let floodFill (arr : Arr3D) maxX maxY maxZ (x : int) (y : int) (z : int) : unit =
+ /// Returns true if it hits the outside.
+ let rec go (x : int) (y : int) (z : int) : bool =
+ let mutable hitsOutside = false
+
+ match Arr3D.get arr x y z with
+ | 0 ->
+ Arr3D.set arr x y z 3
+
+ hitsOutside <- hitsOutside || (if x > 0 then go (x - 1) y z else true)
+
+ hitsOutside <- hitsOutside || (if y > 0 then go x (y - 1) z else true)
+
+ hitsOutside <- hitsOutside || (if z > 0 then go x y (z - 1) else true)
+
+ hitsOutside <- hitsOutside || (if x < maxX then go (x + 1) y z else true)
+
+ hitsOutside <- hitsOutside || (if y < maxY then go x (y + 1) z else true)
+
+ hitsOutside <- hitsOutside || (if z < maxZ then go x y (z + 1) else true)
+ | 2 -> hitsOutside <- true
+ | _ -> ()
+
+ hitsOutside
+
+ if go x y z then
+ // Convert all our "in progress" to "flood fills to outside".
+ for x in 0..maxX do
+ for y in 0..maxY do
+ for z in 0..maxZ do
+ if Arr3D.get arr x y z = 3 then
+ Arr3D.set arr x y z 2
+ else
+ // Convert all our "in progress" to "does not flood fill to outside".
+ for x in 0..maxX do
+ for y in 0..maxY do
+ for z in 0..maxZ do
+ if Arr3D.get arr x y z = 3 then
+ Arr3D.set arr x y z 1
+
+ let part2 (line : StringSplitEnumerator) : int =
+ let cubes, minX, minY, minZ, maxX, maxY, maxZ = parse line
+
+ let xSpan = maxX - minX + 1
+ let ySpan = maxY - minY + 1
+ let zSpan = maxZ - minZ + 1
+
+#if DEBUG
+ let arr = Arr3D.zeroCreate xSpan ySpan zSpan
+#else
+ let backing = Array.zeroCreate (xSpan * ySpan * zSpan)
+ use ptr = fixed backing
+ let arr = Arr3D.zeroCreate ptr xSpan ySpan zSpan
+#endif
+
+ for i in 0 .. cubes.Count - 1 do
+ let struct (x, y, z) = cubes.[i]
+ Arr3D.set arr (x - minX) (y - minY) (z - minZ) 1
+
+ // Flood-fill the internals.
+ for x in 0 .. maxX - minX do
+ for y in 0 .. maxY - minY do
+ for z in 0 .. maxZ - minZ do
+ floodFill arr (maxX - minX) (maxY - minY) (maxZ - minZ) x y z
+
+ doPart1 cubes arr minX minY minZ maxX maxY maxZ
diff --git a/AdventOfCode2022/IntSet.fs b/AdventOfCode2022/IntSet.fs
index 1f9eb85..ed4967e 100644
--- a/AdventOfCode2022/IntSet.fs
+++ b/AdventOfCode2022/IntSet.fs
@@ -8,6 +8,7 @@ module IntSet =
let inline set (set : IntSet) (nodeId : int) : IntSet = set ||| (1L <<< nodeId)
let inline contains (set : IntSet) (nodeId : int) : bool = set &&& (1L <<< nodeId) <> 0
let ofSeq (nodes : int seq) : IntSet = (0L, nodes) ||> Seq.fold set
+ let empty : IntSet = 0L
let toSeq (nodes : IntSet) : int seq =
seq {