Created
December 18, 2022 10:43
-
-
Save lydell/71b222812922c0ad5cf0f04974e6c1dd to your computer and use it in GitHub Desktop.
Advent of Code 2022 Day 18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
echo 'module Input' | |
echo 'let input =' | |
echo ' [' | |
cat | string replace -r ^ ' ' | |
echo ' ]' | |
end >Input.fsx | |
dotnet fsi ab.fsx |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#load "Input.fsx" | |
open Input | |
let moves = | |
[ | |
-1, 0, 0 | |
1, 0, 0 | |
0, -1, 0 | |
0, 1, 0 | |
0, 0, -1 | |
0, 0, 1 | |
] | |
let droplet = Set.ofList input | |
let surfaceArea cluster = | |
cluster | |
|> Set.toList | |
|> List.map (fun (x, y, z) -> | |
moves | |
|> List.filter (fun (dx, dy, dz) -> | |
not (Set.contains (x + dx, y + dy, z + dz) cluster) | |
) | |
|> List.length | |
) | |
|> List.sum | |
let xs = input |> List.map (fun (x, _, _) -> x) | |
let ys = input |> List.map (fun (_, y, _) -> y) | |
let zs = input |> List.map (fun (_, _, z) -> z) | |
let minX = xs |> List.min | |
let maxX = xs |> List.max | |
let minY = ys |> List.min | |
let maxY = ys |> List.max | |
let minZ = zs |> List.min | |
let maxZ = zs |> List.max | |
let xRange = [minX..maxX] | |
let yRange = [minY..maxY] | |
let zRange = [minZ..maxZ] | |
let solidCube = | |
xRange | |
|> List.collect (fun x -> | |
yRange | |
|> List.collect (fun y -> | |
zRange | |
|> List.map (fun z -> x, y, z) | |
) | |
) | |
|> Set.ofList | |
let air = | |
Set.difference solidCube droplet | |
let rec findAirCluster (x, y, z) remainingAir = | |
let candidates = | |
moves | |
|> List.map (fun (dx, dy, dz) -> | |
x + dx, y + dy, z + dz | |
) | |
|> List.filter (fun coordinate -> | |
Set.contains coordinate remainingAir | |
) | |
let startCluster = (x, y, z) :: candidates |> Set.ofList | |
candidates | |
|> List.fold | |
(fun (accCluster, accAir) coordinate -> | |
let newCluster, newAir = | |
findAirCluster coordinate accAir | |
Set.union accCluster newCluster, newAir | |
) | |
(startCluster, Set.difference remainingAir startCluster) | |
let rec findAllAirClusters remainingAir = | |
if Set.isEmpty remainingAir then | |
[] | |
else | |
let coordinate = Set.minElement remainingAir | |
let cluster, newAir = findAirCluster coordinate remainingAir | |
cluster :: findAllAirClusters newAir | |
let airPockets = | |
air | |
|> findAllAirClusters | |
|> List.filter ( | |
Set.toList | |
>> List.forall (fun (x, y, z) -> | |
not (x = minX || x = maxX || y = minY || y = maxY || z = minZ || z = maxZ) | |
) | |
) | |
let dropletArea = surfaceArea droplet | |
let airPocketsArea = | |
airPockets | |
|> List.map surfaceArea | |
|> List.sum | |
printfn "a: %i" dropletArea | |
printfn "b: %i" (dropletArea - airPocketsArea) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment