day_18.jl (3369B)
1 #!/usr/bin/env julia 2 # https://adventofcode.com/2022/day/18 3 using AdventOfCode 4 5 # I've been avoiding list comprehensions because, idk, I'm a nerd who tries to 6 # use `map`. But I remembered how expressive comprehensions can be, so it was 7 # nice to use them here! 8 9 example = readlines(IOBuffer(""" 10 2,2,2 11 1,2,2 12 3,2,2 13 2,1,2 14 2,3,2 15 2,2,1 16 2,2,3 17 2,2,4 18 2,2,6 19 1,2,5 20 3,2,5 21 2,1,5 22 2,3,5""")) 23 input = readlines("data/day_18.txt") 24 25 Cube = Tuple{Int, Int, Int} 26 27 """ 28 Read the puzzle input and return a map from cubes to exposed faces. 29 30 We initialize each cube with six exposed faces and update them on a subsequent 31 step. 32 """ 33 function parse_input(input::Vector{<:AbstractString}) 34 Dict(Tuple(parse.(Int, split(x, ","))) => 6 for x in input) 35 end 36 37 """ 38 Return the six-connected neighborhood of the given cube. 39 """ 40 function neighbors(cube::Cube) 41 cubeneighbors = Set{Cube}() 42 for ax = 1:3, Δ = (-1, 1) 43 push!(cubeneighbors, 44 Tuple(i==ax ? cube[i]+Δ : cube[i] for i = eachindex(cube))) 45 end 46 cubeneighbors 47 end 48 49 """ 50 Loop through the cubes to find the droplet surface area. 51 52 This updates the dictionary of (exposed) surface area values and also returns 53 it (for convenience). 54 """ 55 function updatecubes!(cubemap::Dict{Cube, Int}) 56 cubes = Set(keys(cubemap)) 57 while !isempty(cubes) 58 cube = pop!(cubes) 59 for neighbor in neighbors(cube) ∩ cubes 60 cubemap[cube] -= 1 61 cubemap[neighbor] -= 1 62 end 63 end 64 cubemap 65 end 66 67 function part_1(input) 68 input |> parse_input |> updatecubes! |> values |> sum 69 end 70 @assert part_1(example) == 64 71 @info part_1(input) 72 73 """ 74 Recursively calculate the surface area of the lava droplet. 75 76 Pretty different than the part 1 approach--where we started in the droplet and 77 worked outward, this starts in the steam and works toward the droplet. This 78 function returns the surface area touched by the given cube and all heretofore 79 unexplored cubes. 80 """ 81 function lavasurface!(steamarea::Dict{Cube, Int}, 82 lavacubes::AbstractSet{Cube}, 83 cube::Cube, 84 xrange::Tuple{Int, Int} = extrema(x -> x[1], lavacubes), 85 yrange::Tuple{Int, Int} = extrema(x -> x[2], lavacubes), 86 zrange::Tuple{Int, Int} = extrema(x -> x[3], lavacubes)) 87 @assert cube ∉ lavacubes 88 @assert cube ∉ keys(steamarea) 89 steamarea[cube] = 0 90 for neighbor = neighbors(cube) 91 if neighbor ∈ lavacubes 92 steamarea[cube] += 1 93 elseif neighbor ∉ keys(steamarea) && 94 xrange[1]-1 <= neighbor[1] <= xrange[2]+1 && 95 yrange[1]-1 <= neighbor[2] <= yrange[2]+1 && 96 zrange[1]-1 <= neighbor[3] <= zrange[2]+1 97 steamarea[cube] += lavasurface!(steamarea, lavacubes, neighbor, 98 xrange, yrange, zrange) 99 end 100 end 101 steamarea[cube] 102 end 103 104 function part_2(input) 105 steamarea = Dict{Cube, Int}() 106 lavacubes = keys(parse_input(input)) 107 108 xrange = extrema(x -> x[1], lavacubes) 109 yrange = extrema(x -> x[2], lavacubes) 110 zrange = extrema(x -> x[3], lavacubes) 111 112 lavasurface!(steamarea, lavacubes, (xrange[1]-1, yrange[1]-1, zrange[1]-1), 113 xrange, yrange, zrange) 114 end 115 @assert part_2(example) == 58 116 @info part_2(input)