2022 Day 18 Complete
This commit is contained in:
parent
c4d5dae456
commit
667c3a4dc9
2831
2022/day18/input
Normal file
2831
2022/day18/input
Normal file
File diff suppressed because it is too large
Load Diff
205
2022/day18/main.go
Normal file
205
2022/day18/main.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
inp := h.StdinToStringSlice()
|
||||||
|
part1(inp)
|
||||||
|
part2(inp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func part1(inp []string) {
|
||||||
|
scan := ParseSurface(inp)
|
||||||
|
var surface int
|
||||||
|
for k := range scan {
|
||||||
|
for _, chk := range []pos{k.Top(), k.Bottom(), k.Left(), k.Right(), k.Front(), k.Back()} {
|
||||||
|
if _, ok := scan[chk]; !ok {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("# Part 1")
|
||||||
|
fmt.Println("Surface Area:", surface)
|
||||||
|
}
|
||||||
|
func part2(inp []string) {
|
||||||
|
scan := ParseCubes(inp)
|
||||||
|
scanExternal(scan)
|
||||||
|
|
||||||
|
var surface int
|
||||||
|
for _, cb := range scan {
|
||||||
|
if cb.top == nil && !cb.topInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
if cb.bottom == nil && !cb.bottomInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
if cb.right == nil && !cb.rightInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
if cb.left == nil && !cb.leftInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
if cb.front == nil && !cb.frontInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
if cb.back == nil && !cb.backInt {
|
||||||
|
surface++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("# Part 2")
|
||||||
|
fmt.Println("External Surface Area:", surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanExternal(m map[pos]*cube) {
|
||||||
|
min := pos{x: math.MaxInt, y: math.MaxInt, z: math.MaxInt}
|
||||||
|
max := pos{x: math.MinInt, y: math.MinInt, z: math.MinInt}
|
||||||
|
for k := range m {
|
||||||
|
min.x = h.Min(min.x, k.x)
|
||||||
|
min.y = h.Min(min.y, k.y)
|
||||||
|
min.z = h.Min(min.z, k.z)
|
||||||
|
max.x = h.Max(max.x, k.x)
|
||||||
|
max.y = h.Max(max.y, k.y)
|
||||||
|
max.z = h.Max(max.z, k.z)
|
||||||
|
}
|
||||||
|
edges := make(map[pos]bool)
|
||||||
|
for z := min.z - 1; z < max.z+1; z++ {
|
||||||
|
for y := min.y - 1; y < max.y+1; y++ {
|
||||||
|
for x := min.x - 1; x < max.x+1; x++ {
|
||||||
|
edges[pos{min.x, y, z}] = true
|
||||||
|
edges[pos{x, min.y, z}] = true
|
||||||
|
edges[pos{x, y, min.z}] = true
|
||||||
|
edges[pos{max.x, y, z}] = true
|
||||||
|
edges[pos{x, max.y, z}] = true
|
||||||
|
edges[pos{x, y, max.z}] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
if v.left == nil && !canPath(k.Left(), edges, m) {
|
||||||
|
v.leftInt = true
|
||||||
|
}
|
||||||
|
if v.right == nil && !canPath(k.Right(), edges, m) {
|
||||||
|
v.rightInt = true
|
||||||
|
}
|
||||||
|
if v.top == nil && !canPath(k.Top(), edges, m) {
|
||||||
|
v.topInt = true
|
||||||
|
}
|
||||||
|
if v.bottom == nil && !canPath(k.Bottom(), edges, m) {
|
||||||
|
v.bottomInt = true
|
||||||
|
}
|
||||||
|
if v.front == nil && !canPath(k.Front(), edges, m) {
|
||||||
|
v.frontInt = true
|
||||||
|
}
|
||||||
|
if v.back == nil && !canPath(k.Back(), edges, m) {
|
||||||
|
v.backInt = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func canPath(from pos, to map[pos]bool, scan map[pos]*cube) bool {
|
||||||
|
queue := []pos{from}
|
||||||
|
visit := make(map[pos]bool)
|
||||||
|
result := false
|
||||||
|
for len(queue) > 0 {
|
||||||
|
cur := queue[0]
|
||||||
|
queue = queue[1:]
|
||||||
|
if _, ok := to[cur]; ok {
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, ok := visit[cur]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visit[cur] = true
|
||||||
|
moves := []pos{
|
||||||
|
cur.Top(), cur.Bottom(),
|
||||||
|
cur.Left(), cur.Right(),
|
||||||
|
cur.Front(), cur.Back(),
|
||||||
|
}
|
||||||
|
for _, mv := range moves {
|
||||||
|
if _, ok := scan[mv]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
queue = append(queue, mv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseSurface(inp []string) map[pos]bool {
|
||||||
|
m := make(map[pos]bool)
|
||||||
|
for i := range inp {
|
||||||
|
pts := strings.Split(inp[i], ",")
|
||||||
|
m[pos{
|
||||||
|
x: h.Atoi(pts[0]),
|
||||||
|
y: h.Atoi(pts[1]),
|
||||||
|
z: h.Atoi(pts[2]),
|
||||||
|
}] = true
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func ParseCubes(inp []string) map[pos]*cube {
|
||||||
|
m := make(map[pos]*cube)
|
||||||
|
for i := range inp {
|
||||||
|
pts := strings.Split(inp[i], ",")
|
||||||
|
pos := pos{
|
||||||
|
x: h.Atoi(pts[0]),
|
||||||
|
y: h.Atoi(pts[1]),
|
||||||
|
z: h.Atoi(pts[2]),
|
||||||
|
}
|
||||||
|
m[pos] = &cube{position: pos}
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
if _, ok := m[k.Top()]; ok {
|
||||||
|
m[k.Top()].bottom = v
|
||||||
|
v.top = m[k.Top()]
|
||||||
|
}
|
||||||
|
if _, ok := m[k.Bottom()]; ok {
|
||||||
|
m[k.Bottom()].top = v
|
||||||
|
v.bottom = m[k.Bottom()]
|
||||||
|
}
|
||||||
|
if _, ok := m[k.Left()]; ok {
|
||||||
|
m[k.Left()].right = v
|
||||||
|
v.left = m[k.Left()]
|
||||||
|
}
|
||||||
|
if _, ok := m[k.Right()]; ok {
|
||||||
|
m[k.Right()].left = v
|
||||||
|
v.right = m[k.Right()]
|
||||||
|
}
|
||||||
|
if _, ok := m[k.Front()]; ok {
|
||||||
|
m[k.Front()].back = v
|
||||||
|
v.front = m[k.Front()]
|
||||||
|
}
|
||||||
|
if _, ok := m[k.Back()]; ok {
|
||||||
|
m[k.Back()].front = v
|
||||||
|
v.back = m[k.Back()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type pos struct{ x, y, z int }
|
||||||
|
|
||||||
|
func (p pos) Top() pos { return pos{x: p.x, y: p.y + 1, z: p.z} }
|
||||||
|
func (p pos) Bottom() pos { return pos{x: p.x, y: p.y - 1, z: p.z} }
|
||||||
|
func (p pos) Left() pos { return pos{x: p.x - 1, y: p.y, z: p.z} }
|
||||||
|
func (p pos) Right() pos { return pos{x: p.x + 1, y: p.y, z: p.z} }
|
||||||
|
func (p pos) Front() pos { return pos{x: p.x, y: p.y, z: p.z - 1} }
|
||||||
|
func (p pos) Back() pos { return pos{x: p.x, y: p.y, z: p.z + 1} }
|
||||||
|
|
||||||
|
type cube struct {
|
||||||
|
position pos
|
||||||
|
top, bottom *cube
|
||||||
|
front, back *cube
|
||||||
|
left, right *cube
|
||||||
|
|
||||||
|
topInt, bottomInt bool
|
||||||
|
frontInt, backInt bool
|
||||||
|
leftInt, rightInt bool
|
||||||
|
}
|
93
2022/day18/problem
Normal file
93
2022/day18/problem
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
Advent of Code
|
||||||
|
br0xen (AoC++) 35*
|
||||||
|
|
||||||
|
--- Day 18: Boiling Boulders ---
|
||||||
|
|
||||||
|
You and the elephants finally reach fresh air. You've emerged near the
|
||||||
|
base of a large volcano that seems to be actively erupting! Fortunately,
|
||||||
|
the lava seems to be flowing away from you and toward the ocean.
|
||||||
|
|
||||||
|
Bits of lava are still being ejected toward you, so you're sheltering in
|
||||||
|
the cavern exit a little longer. Outside the cave, you can see the lava
|
||||||
|
landing in a pond and hear it loudly hissing as it solidifies.
|
||||||
|
|
||||||
|
Depending on the specific compounds in the lava and speed at which it
|
||||||
|
cools, it might be forming obsidian! The cooling rate should be based on
|
||||||
|
the surface area of the lava droplets, so you take a quick scan of a
|
||||||
|
droplet as it flies past you (your puzzle input).
|
||||||
|
|
||||||
|
Because of how quickly the lava is moving, the scan isn't very good; its
|
||||||
|
resolution is quite low and, as a result, it approximates the shape of the
|
||||||
|
lava droplet with 1x1x1 cubes on a 3D grid, each given as its x,y,z
|
||||||
|
position.
|
||||||
|
|
||||||
|
To approximate the surface area, count the number of sides of each cube
|
||||||
|
that are not immediately connected to another cube. So, if your scan were
|
||||||
|
only two adjacent cubes like 1,1,1 and 2,1,1, each cube would have a
|
||||||
|
single side covered and five sides exposed, a total surface area of 10
|
||||||
|
sides.
|
||||||
|
|
||||||
|
Here's a larger example:
|
||||||
|
|
||||||
|
2,2,2
|
||||||
|
1,2,2
|
||||||
|
3,2,2
|
||||||
|
2,1,2
|
||||||
|
2,3,2
|
||||||
|
2,2,1
|
||||||
|
2,2,3
|
||||||
|
2,2,4
|
||||||
|
2,2,6
|
||||||
|
1,2,5
|
||||||
|
3,2,5
|
||||||
|
2,1,5
|
||||||
|
2,3,5
|
||||||
|
|
||||||
|
In the above example, after counting up all the sides that aren't
|
||||||
|
connected to another cube, the total surface area is 64.
|
||||||
|
|
||||||
|
What is the surface area of your scanned lava droplet?
|
||||||
|
|
||||||
|
Your puzzle answer was 4548.
|
||||||
|
|
||||||
|
--- Part Two ---
|
||||||
|
|
||||||
|
Something seems off about your calculation. The cooling rate depends on
|
||||||
|
exterior surface area, but your calculation also included the surface area
|
||||||
|
of air pockets trapped in the lava droplet.
|
||||||
|
|
||||||
|
Instead, consider only cube sides that could be reached by the water and
|
||||||
|
steam as the lava droplet tumbles into the pond. The steam will expand to
|
||||||
|
reach as much as possible, completely displacing any air on the outside of
|
||||||
|
the lava droplet but never expanding diagonally.
|
||||||
|
|
||||||
|
In the larger example above, exactly one cube of air is trapped within the
|
||||||
|
lava droplet (at 2,2,5), so the exterior surface area of the lava droplet
|
||||||
|
is 58.
|
||||||
|
|
||||||
|
What is the exterior surface area of your scanned lava droplet?
|
||||||
|
|
||||||
|
Your puzzle answer was 2588.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links
|
||||||
|
. https://adventofcode.com/
|
||||||
|
. https://adventofcode.com/2022/about
|
||||||
|
. https://adventofcode.com/2022/events
|
||||||
|
. https://adventofcode.com/2022/settings
|
||||||
|
. https://adventofcode.com/2022/auth/logout
|
||||||
|
. Advent of Code Supporter
|
||||||
|
https://adventofcode.com/2022/support
|
||||||
|
. https://adventofcode.com/2022
|
||||||
|
. https://adventofcode.com/2022
|
||||||
|
. https://adventofcode.com/2022/support
|
||||||
|
. https://adventofcode.com/2022/sponsors
|
||||||
|
. https://adventofcode.com/2022/leaderboard
|
||||||
|
. https://adventofcode.com/2022/stats
|
||||||
|
. https://adventofcode.com/2022/sponsors
|
||||||
|
. https://en.wikipedia.org/wiki/Obsidian
|
||||||
|
. https://adventofcode.com/2022
|
||||||
|
. https://adventofcode.com/2022/day/18/input
|
13
2022/day18/testinput
Normal file
13
2022/day18/testinput
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
2,2,2
|
||||||
|
1,2,2
|
||||||
|
3,2,2
|
||||||
|
2,1,2
|
||||||
|
2,3,2
|
||||||
|
2,2,1
|
||||||
|
2,2,3
|
||||||
|
2,2,4
|
||||||
|
2,2,6
|
||||||
|
1,2,5
|
||||||
|
3,2,5
|
||||||
|
2,1,5
|
||||||
|
2,3,5
|
Loading…
Reference in New Issue
Block a user