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.") }