AOC2022/day18/day18.go
2022-12-18 19:39:49 +01:00

159 lines
3.6 KiB
Go

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
}