package main import ( "AOC2022/helper" "fmt" "os" "strings" ) func main() { args := os.Args[1:] lines := helper.ReadTextFile(args[0]) points := make(map[[3]int]bool, len(lines)) for _, line := range lines { point := [3]int{} for j, number := range helper.StringSliceToIntSlice(strings.Split(line, ",")) { point[j] = number } points[point] = true } fmt.Println(removeOpenSurfacePointsWhichHaveNoConnectionToOutside(points)) same := false pastLenPoints := len(points) for !same { removeOpenSurfacePointsWhichHaveNoConnectionToOutside(points) if pastLenPoints != len(points) { pastLenPoints = len(points) } else { same = true } } openSurfacesSum := 0 for point, _ := range points { openSurfacesPoint := 6 neighbors := getNeighbors(point) for _, neighbor := range neighbors { if points[neighbor] { openSurfacesPoint-- } } openSurfacesSum += openSurfacesPoint } fmt.Println(openSurfacesSum) } func removeOpenSurfacePointsWhichHaveNoConnectionToOutside(points map[[3]int]bool) int { openSurfacesSum := 0 openSurfacesPoints := make(map[[3]int]bool) for point, _ := range points { openSurfacesPoint := 6 neighbors := getNeighbors(point) for _, neighbor := range neighbors { if points[neighbor] { openSurfacesPoint-- } else { openSurfacesPoints[neighbor] = true } } openSurfacesSum += openSurfacesPoint } for point, _ := range openSurfacesPoints { if !checkIfPathToOutSideExists(points, point) { points[point] = true } } return openSurfacesSum } func getNeighbors(point [3]int) (neighbors [6][3]int) { directions := [][3]int{{0, -1, 0}, {+1, 0, 0}, {0, 1, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}} for i, direction := range directions { neighbors[i] = [3]int{point[0] + direction[0], point[1] + direction[1], point[2] + direction[2]} } return } func checkIfPathToOutSideExists(points map[[3]int]bool, startPoint [3]int) bool { activePoints := make(map[[3]int]bool) pointsCopy := deepCopyMap(points) activePoints[startPoint] = true foundAWay := false areaLimits := getAreaLimits(points) for !foundAWay && len(activePoints) > 0 { step(&pointsCopy, &activePoints, &foundAWay, areaLimits) } return foundAWay } func step(points *map[[3]int]bool, activePoints *map[[3]int]bool, foundAWay *bool, areaLimits [6]int) { activePoint := get_some_key(*activePoints) delete(*activePoints, activePoint) if (activePoint[0] > areaLimits[0] || activePoint[0] < areaLimits[1]) && (activePoint[1] > areaLimits[2] || activePoint[1] < areaLimits[3]) && (activePoint[2] > areaLimits[4] || activePoint[2] < areaLimits[5]) { *foundAWay = true return } (*points)[activePoint] = true neighbors := getNeighbors(activePoint) for _, neighbor := range neighbors { if !(*points)[neighbor] { (*activePoints)[neighbor] = true } } } func getAreaLimits(points map[[3]int]bool) [6]int { highestX := -1 lowestX := 999999 highestY := -1 lowestY := 999999 highestZ := -1 lowestZ := 999999 for point, _ := range points { if point[0] > highestX { highestX = point[0] } if point[0] < lowestX { lowestX = point[0] } if point[1] > highestY { highestY = point[1] } if point[1] < lowestY { lowestY = point[1] } if point[2] > highestZ { highestZ = point[2] } if point[2] < lowestZ { lowestZ = point[2] } } return [6]int{highestX, lowestX, highestY, lowestY, highestZ, lowestZ} } func get_some_key[T any](m map[[3]int]T) [3]int { for k := range m { return k } return [3]int{-1, -1, -1} } func deepCopyMap(points map[[3]int]bool) map[[3]int]bool { tmpValves := make(map[[3]int]bool) for k, v := range points { tmpValves[k] = v } return tmpValves }