diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/AdventOfCode2023.FSharp.Lib.fsproj b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/AdventOfCode2023.FSharp.Lib.fsproj
index 73ba81f..e728483 100644
--- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/AdventOfCode2023.FSharp.Lib.fsproj
+++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/AdventOfCode2023.FSharp.Lib.fsproj
@@ -18,6 +18,7 @@
+
diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day9.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day9.fs
new file mode 100644
index 0000000..81c2855
--- /dev/null
+++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day9.fs
@@ -0,0 +1,37 @@
+namespace AdventOfCode2023
+
+open System
+open System.Collections.Generic
+
+[]
+module Day9 =
+
+ let parse (s : string) =
+ use mutable lines = StringSplitEnumerator.make '\n' s
+
+ lines.MoveNext () |> ignore
+
+ let stepsLine = lines.Current.TrimEnd ()
+ let steps = Array.zeroCreate stepsLine.Length
+
+ for i = 0 to stepsLine.Length - 1 do
+ steps.[i] <- (stepsLine.[i] = 'R')
+
+ let dict = Dictionary ()
+
+ while lines.MoveNext () do
+ if not lines.Current.IsEmpty then
+ use mutable line = StringSplitEnumerator.make' ' ' lines.Current
+ line.MoveNext () |> ignore
+ {
+ Steps = steps
+ Nodes = dict
+ }
+
+ let part1 (s : string) =
+ let data = parse s
+ answer
+
+ let part2 (s : string) =
+ let data = parse s
+ 0
diff --git a/AdventOfCode2023.FSharp/Test/Test.fsproj b/AdventOfCode2023.FSharp/Test/Test.fsproj
index 9a4c538..b6ff897 100644
--- a/AdventOfCode2023.FSharp/Test/Test.fsproj
+++ b/AdventOfCode2023.FSharp/Test/Test.fsproj
@@ -17,6 +17,7 @@
+
diff --git a/AdventOfCode2023.FSharp/Test/TestDay9.fs b/AdventOfCode2023.FSharp/Test/TestDay9.fs
new file mode 100644
index 0000000..ff243f0
--- /dev/null
+++ b/AdventOfCode2023.FSharp/Test/TestDay9.fs
@@ -0,0 +1,49 @@
+namespace AdventOfCode2023.Test
+
+open AdventOfCode2023
+open NUnit.Framework
+open FsUnitTyped
+open System.IO
+
+[]
+module TestDay9 =
+
+ let sample = Assembly.getEmbeddedResource typeof.Assembly "day9.txt"
+
+ []
+ let part1Sample () =
+ sample
+ |> Day9.part1
+ |> shouldEqual 2
+
+ []
+ let part2Sample () =
+ Assembly.getEmbeddedResource typeof.Assembly "day9.txt"
+ |> Day9.part2
+ |> shouldEqual 0
+
+ []
+ let part1Actual () =
+ let s =
+ try
+ File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day9.txt"))
+ with
+ | :? DirectoryNotFoundException
+ | :? FileNotFoundException ->
+ Assert.Inconclusive ()
+ failwith "unreachable"
+
+ Day8.part1 s |> shouldEqual 0
+
+ []
+ let part2Actual () =
+ let s =
+ try
+ File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day9.txt"))
+ with
+ | :? DirectoryNotFoundException
+ | :? FileNotFoundException ->
+ Assert.Inconclusive ()
+ failwith "unreachable"
+
+ Day8.part2 s |> shouldEqual 0