aboutsummaryrefslogtreecommitdiff
path: root/aoc-2022-dotnet/Day14/Program.fs
diff options
context:
space:
mode:
authorTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2022-12-15 21:55:28 +0100
committerTomasz Chojnacki <tomaszchojnacki2001@gmail.com>2022-12-15 21:55:28 +0100
commit7ce938ea4d40e9a631bfe11795f3d9f74855ceb5 (patch)
tree2ce00c913332b378ebc1b7a5a8d9d3504a4a8734 /aoc-2022-dotnet/Day14/Program.fs
parent6fc820cd0cb61a4bacda5f5b40c98dda850d75da (diff)
downloadgleam_aoc2020-7ce938ea4d40e9a631bfe11795f3d9f74855ceb5.tar.gz
gleam_aoc2020-7ce938ea4d40e9a631bfe11795f3d9f74855ceb5.zip
Finish day 14
Diffstat (limited to 'aoc-2022-dotnet/Day14/Program.fs')
-rw-r--r--aoc-2022-dotnet/Day14/Program.fs80
1 files changed, 80 insertions, 0 deletions
diff --git a/aoc-2022-dotnet/Day14/Program.fs b/aoc-2022-dotnet/Day14/Program.fs
new file mode 100644
index 0000000..02e028c
--- /dev/null
+++ b/aoc-2022-dotnet/Day14/Program.fs
@@ -0,0 +1,80 @@
+module Day14
+
+open System.IO
+open FParsec
+open Common
+
+let sandSpawnPos = Vec2(500, 0)
+
+let sandMoveOffsets =
+ [ Vec2.down
+ Vec2.downLeft
+ Vec2.downRight ]
+
+let notIn set element = not <| Set.contains element set
+
+let buildCaveScan =
+ let parsePath =
+ let py = pint32 |>> (~-) // mirror Y coordinate
+ let ppoint = pint32 .>> (pchar ',') .>>. py |>> Vec2
+ let ppath = sepBy ppoint (pstring " -> ")
+ Util.parse ppath
+
+ let pathToPositions =
+ Seq.pairwise
+ >> Seq.collect Vec2.lineBetween
+ >> Set
+
+ Seq.map (parsePath >> pathToPositions)
+ >> Seq.reduce (+)
+
+let solution1 input =
+ let initialCaveScan = buildCaveScan input
+ let voidY = initialCaveScan |> Seq.map Vec2.y |> Seq.min
+
+ let settleNewUnit caveScan =
+ let rec fall pos =
+ if Vec2.y pos <= voidY then
+ None
+ else
+ sandMoveOffsets
+ |> Seq.map ((+) pos)
+ |> Seq.tryFind (notIn caveScan)
+ |> function
+ | Some (nextPos) -> fall nextPos
+ | None -> Some(pos)
+
+ caveScan
+ |> match fall sandSpawnPos with
+ | Some (settledPos) -> Set.add settledPos
+ | None -> id
+
+ initialCaveScan
+ |> Seq.unfold (fun caveScan -> Some(caveScan, settleNewUnit caveScan))
+ |> Seq.pairwise
+ |> Seq.takeWhile (fun (a, b) -> a <> b)
+ |> Seq.length
+
+let solution2 input =
+ let caveScan = buildCaveScan input
+ let floorY = caveScan |> Seq.map Vec2.y |> Seq.min |> (+) -2
+
+ let neighbours pos =
+ sandMoveOffsets
+ |> List.map ((+) pos)
+ |> List.filter (fun pos -> notIn caveScan pos && Vec2.y pos <> floorY)
+
+ let rec dfs stack visited =
+ match stack with
+ | h :: t -> dfs (List.filter (notIn visited) (neighbours h) @ t) (Set.add h visited)
+ | [] -> Set.count visited
+
+ dfs [ sandSpawnPos ] Set.empty
+
+let test = File.ReadLines("test.txt")
+assert (solution1 test = 24)
+assert (solution2 test = 93)
+
+let input = File.ReadLines("input.txt")
+printfn "%d" <| solution1 input
+printfn "%d" <| solution2 input