diff options
author | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2022-12-15 21:55:28 +0100 |
---|---|---|
committer | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2022-12-15 21:55:28 +0100 |
commit | 7ce938ea4d40e9a631bfe11795f3d9f74855ceb5 (patch) | |
tree | 2ce00c913332b378ebc1b7a5a8d9d3504a4a8734 /aoc-2022-dotnet/Day14/Program.fs | |
parent | 6fc820cd0cb61a4bacda5f5b40c98dda850d75da (diff) | |
download | gleam_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.fs | 80 |
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 |