149 lines
3.0 KiB
Go
149 lines
3.0 KiB
Go
package day18
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
type Point struct {
|
|
x int
|
|
y int
|
|
z int
|
|
}
|
|
|
|
const (
|
|
Lava int = iota
|
|
Air
|
|
Steam
|
|
)
|
|
|
|
func surroundingPoints(point Point) []Point {
|
|
return []Point{
|
|
{point.x - 1, point.y, point.z},
|
|
{point.x + 1, point.y, point.z},
|
|
{point.x, point.y - 1, point.z},
|
|
{point.x, point.y + 1, point.z},
|
|
{point.x, point.y, point.z - 1},
|
|
{point.x, point.y, point.z + 1},
|
|
}
|
|
}
|
|
|
|
func countBlankSides(points map[Point]int, against int) int {
|
|
blankSides := 0
|
|
for point, original := range points {
|
|
if original == Lava {
|
|
pointBlankSides := 0
|
|
for _, surrounding := range surroundingPoints(point) {
|
|
if points[surrounding] == against {
|
|
pointBlankSides += 1
|
|
}
|
|
}
|
|
//fmt.Println("Point", point, "had", pointBlankSides, "blank sides.")
|
|
blankSides += pointBlankSides
|
|
}
|
|
}
|
|
return blankSides
|
|
}
|
|
|
|
func inUniverse(point Point, min Point, max Point) bool {
|
|
return point.x >= min.x && point.x <= max.x &&
|
|
point.y >= min.y && point.y <= max.y &&
|
|
point.z >= min.z && point.z <= max.x
|
|
}
|
|
|
|
func floodSteam(minPoint Point, maxPoint Point, points map[Point]int) {
|
|
stack := []Point{minPoint}
|
|
|
|
for len(stack) > 0 {
|
|
nextIdx := len(stack) - 1
|
|
next := stack[nextIdx]
|
|
stack = stack[0:nextIdx]
|
|
|
|
if inUniverse(next, minPoint, maxPoint) && points[next] == Air {
|
|
points[next] = Steam
|
|
stack = append(stack, surroundingPoints(next)...)
|
|
}
|
|
}
|
|
}
|
|
|
|
func findExtendedBoundingBox(points map[Point]int) (minPoint Point, maxPoint Point) {
|
|
minPoint = Point{1000000, 100000, 100000}
|
|
maxPoint = Point{0, 0, 0}
|
|
|
|
for point := range points {
|
|
if point.x < minPoint.x {
|
|
minPoint.x = point.x
|
|
}
|
|
if point.x > maxPoint.x {
|
|
maxPoint.x = point.x
|
|
}
|
|
if point.y < minPoint.y {
|
|
minPoint.y = point.y
|
|
}
|
|
if point.y > maxPoint.y {
|
|
maxPoint.y = point.y
|
|
}
|
|
if point.z < minPoint.z {
|
|
minPoint.z = point.z
|
|
}
|
|
if point.z > maxPoint.z {
|
|
maxPoint.z = point.z
|
|
}
|
|
}
|
|
|
|
fmt.Println("Min point", minPoint)
|
|
fmt.Println("Max point", maxPoint)
|
|
|
|
minPoint.x -= 1
|
|
minPoint.y -= 1
|
|
minPoint.z -= 1
|
|
maxPoint.x += 1
|
|
maxPoint.y += 1
|
|
maxPoint.z += 1
|
|
|
|
return
|
|
}
|
|
|
|
func Run(filename string) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
fmt.Println("Error opening file:", err)
|
|
return
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Split(bufio.ScanLines)
|
|
points := map[Point]int{}
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
var x int
|
|
var y int
|
|
var z int
|
|
fmt.Sscanf(line, "%d,%d,%d", &x, &y, &z)
|
|
point := Point{x, y, z}
|
|
points[point] = Lava
|
|
}
|
|
file.Close()
|
|
|
|
minPoint, maxPoint := findExtendedBoundingBox(points)
|
|
|
|
for x := minPoint.x; x <= maxPoint.x; x++ {
|
|
for y := minPoint.y; y <= maxPoint.y; y++ {
|
|
for z := minPoint.z; z <= maxPoint.z; z++ {
|
|
point := Point{x, y, z}
|
|
_, exists := points[point]
|
|
if !exists {
|
|
points[point] = Air
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Println("Found", countBlankSides(points, Air), "blank sides in base solid.")
|
|
floodSteam(minPoint, maxPoint, points)
|
|
fmt.Println("Found", countBlankSides(points, Steam), "blank sides after filling interior.")
|
|
|
|
}
|