177 lines
2.8 KiB
Go
177 lines
2.8 KiB
Go
package nine
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type vents struct {
|
|
floor [][]int
|
|
counted [][]bool
|
|
lowPoints *[]basin
|
|
}
|
|
|
|
type basin struct {
|
|
lowPoint int
|
|
size int
|
|
}
|
|
|
|
func (v *vents) load(filename string) error {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
v.floor = [][]int{}
|
|
v.counted = [][]bool{}
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
elements := []int{}
|
|
|
|
heights := strings.Split(scanner.Text(), "")
|
|
|
|
counts := make([]bool, len(heights))
|
|
|
|
for _, h := range heights {
|
|
v, err := strconv.Atoi(h)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
elements = append(elements, v)
|
|
}
|
|
|
|
v.floor = append(v.floor, elements)
|
|
v.counted = append(v.counted, counts)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *vents) findLowPoints() []basin {
|
|
if v.lowPoints != nil {
|
|
return *v.lowPoints
|
|
}
|
|
|
|
lowPoints := []basin{}
|
|
|
|
if len(v.floor) == 0 || len(v.floor[0]) == 0 {
|
|
return lowPoints
|
|
}
|
|
|
|
horizontal := len(v.floor[0])
|
|
vertical := len(v.floor)
|
|
|
|
for y := 0; y < vertical; y++ {
|
|
for x := 0; x < horizontal; x++ {
|
|
minimum := true
|
|
//Check above
|
|
if y > 0 {
|
|
if v.floor[y][x] >= v.floor[y-1][x] {
|
|
minimum = false
|
|
}
|
|
}
|
|
|
|
//Check below
|
|
if y < vertical-1 {
|
|
if v.floor[y][x] >= v.floor[y+1][x] {
|
|
minimum = false
|
|
}
|
|
}
|
|
|
|
//Check left
|
|
if x > 0 {
|
|
if v.floor[y][x] >= v.floor[y][x-1] {
|
|
minimum = false
|
|
}
|
|
}
|
|
|
|
//Check left
|
|
if x < horizontal-1 {
|
|
if v.floor[y][x] >= v.floor[y][x+1] {
|
|
minimum = false
|
|
}
|
|
}
|
|
|
|
if minimum {
|
|
b := basin{
|
|
lowPoint: v.floor[y][x],
|
|
size: v.basinSize(x, y),
|
|
}
|
|
lowPoints = append(lowPoints, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
v.lowPoints = &lowPoints
|
|
return lowPoints
|
|
}
|
|
|
|
func (v *vents) basinSize(x int, y int) int {
|
|
size := 1
|
|
|
|
v.counted[y][x] = true
|
|
|
|
if v.floor[y][x] == 9 {
|
|
return 0
|
|
}
|
|
|
|
horizontal := len(v.floor[0])
|
|
vertical := len(v.floor)
|
|
|
|
//Check above
|
|
if y > 0 && !v.counted[y-1][x] {
|
|
if v.floor[y][x] < v.floor[y-1][x] {
|
|
size += v.basinSize(x, y-1)
|
|
}
|
|
}
|
|
|
|
//Check below
|
|
if y < vertical-1 && !v.counted[y+1][x] {
|
|
if v.floor[y][x] < v.floor[y+1][x] {
|
|
size += v.basinSize(x, y+1)
|
|
}
|
|
}
|
|
|
|
//Check left
|
|
if x > 0 && !v.counted[y][x-1] {
|
|
if v.floor[y][x] < v.floor[y][x-1] {
|
|
size += v.basinSize(x-1, y)
|
|
}
|
|
}
|
|
|
|
//Check left
|
|
if x < horizontal-1 && !v.counted[y][x+1] {
|
|
if v.floor[y][x] < v.floor[y][x+1] {
|
|
size += v.basinSize(x+1, y)
|
|
}
|
|
}
|
|
|
|
return size
|
|
}
|
|
|
|
func (v *vents) sumLowPointRisk() (sum int) {
|
|
for _, b := range v.findLowPoints() {
|
|
sum += (b.lowPoint + 1)
|
|
}
|
|
|
|
return sum
|
|
}
|
|
|
|
func (v *vents) productLargestBasins() int {
|
|
sizes := sort.IntSlice{}
|
|
for _, b := range v.findLowPoints() {
|
|
sizes = append(sizes, b.size)
|
|
}
|
|
|
|
sort.Sort(sizes)
|
|
|
|
if len(sizes) < 3 {
|
|
return 0
|
|
}
|
|
|
|
return sizes[len(sizes)-1] * sizes[len(sizes)-2] * sizes[len(sizes)-3]
|
|
}
|