Last active
December 19, 2022 10:25
-
-
Save grey-area/b002b9e99bc2cb2ab2eec26660e8e241 to your computer and use it in GitHub Desktop.
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
require "matrix" | |
require "set" | |
# Flood fill from min (up until max) stopping when we hit a cube. | |
def count_outward_faces(cubes, min, max) | |
# To avoid stack overflow, we aren't recursive, instead we have a list of squares to check. | |
to_check = [min] | |
to_check_set = Set[min] | |
# Keep track of squares we have tested (as you can get to the same square multiple ways). | |
visited = Set[] | |
# Our return. | |
count = 0 | |
# From the current cube we go move by the vector below and to a bounds check on the axis index below. | |
operations = [ | |
[ Vector[ 1, 0, 0], 0 ], | |
[ Vector[-1, 0, 0], 0 ], | |
[ Vector[ 0, 1, 0], 1 ], | |
[ Vector[ 0, -1, 0], 1 ], | |
[ Vector[ 0, 0, 1], 2 ], | |
[ Vector[ 0, 0, -1], 2 ], | |
] | |
while to_check.length > 0 | |
t = to_check.pop() | |
to_check_set.delete(t) | |
visited << t | |
operations.each { |op| | |
test = t + op[0] | |
if test[op[1]] >= min[op[1]] && test[op[1]] <= max[op[1]] | |
if cubes.include? test | |
count += 1 | |
elsif !to_check_set.include?(test) && !visited.include?(test) | |
to_check << test | |
to_check_set << test | |
end | |
end | |
} | |
end | |
return count | |
end | |
def count_all_faces(cubes) | |
all_faces = {} | |
cubes.each { |cube| | |
x0 = cube[0] - 1 | |
x1 = cube[0] | |
y0 = cube[1] - 1 | |
y1 = cube[1] | |
z0 = cube[2] - 1 | |
z1 = cube[2] | |
# Create the 6 faces of this cube. | |
faces = [ | |
# Left | |
[ | |
Vector[x0, y0, z0], | |
Vector[x0, y0, z1], | |
Vector[x0, y1, z1], | |
Vector[x0, y1, z0], | |
], | |
# Right | |
[ | |
Vector[x1, y0, z0], | |
Vector[x1, y0, z1], | |
Vector[x1, y1, z1], | |
Vector[x1, y1, z0], | |
], | |
# Top | |
[ | |
Vector[x0, y1, z0], | |
Vector[x0, y1, z1], | |
Vector[x1, y1, z1], | |
Vector[x1, y1, z0], | |
], | |
# Bottom | |
[ | |
Vector[x0, y0, z0], | |
Vector[x0, y0, z1], | |
Vector[x1, y0, z1], | |
Vector[x1, y0, z0], | |
], | |
# Front | |
[ | |
Vector[x0, y0, z0], | |
Vector[x0, y1, z0], | |
Vector[x1, y1, z0], | |
Vector[x1, y0, z0], | |
], | |
# Back | |
[ | |
Vector[x0, y0, z1], | |
Vector[x0, y1, z1], | |
Vector[x1, y1, z1], | |
Vector[x1, y0, z1], | |
], | |
] | |
# Our faces are the keys to the dictionary, the value is how many things use that face. | |
faces.each { |face| | |
if !all_faces.include? face | |
all_faces[face] = 1 | |
else | |
all_faces[face] += 1 | |
end | |
} | |
} | |
# We want unique faces, so sum the keys that have a value of 1 (only one cube uses that face). | |
return all_faces.count { |element| element[1] == 1 } | |
end | |
if __FILE__ == $0 | |
next_dir = 0 | |
min = Vector[1000000, 1000000, 1000000] | |
max = Vector[-1000000, -1000000, -1000000] | |
cubes = Set[] | |
File.readlines("input.txt").each { |line| | |
v = line.strip.split(",") | |
x1 = v[0].to_i | |
y1 = v[1].to_i | |
z1 = v[2].to_i | |
cubes << Vector[x1, y1, z1] | |
min = Vector[[min[0], x1].min, [min[1], y1].min, [min[2], z1].min] | |
max = Vector[[max[0], x1].max, [max[1], y1].max, [max[2], z1].max] | |
} | |
p1 = count_all_faces(cubes) | |
puts("Part 1: #{p1}") | |
p2 = count_outward_faces(cubes, min - Vector[1,1,1], max + Vector[1,1,1]) | |
puts("Part 2: #{p2}") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment