Solution for Day 9
This commit is contained in:
176
nine/vents.go
Normal file
176
nine/vents.go
Normal file
@@ -0,0 +1,176 @@
|
||||
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]
|
||||
}
|
Reference in New Issue
Block a user