141 lines
2.9 KiB
Go
141 lines
2.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func mustAtoi(line string) int {
|
||
|
i, _ := strconv.Atoi(line)
|
||
|
return i
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
start := time.Now()
|
||
|
partOne()
|
||
|
duration := time.Since(start)
|
||
|
partTwo()
|
||
|
duration2 := time.Since(start)
|
||
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
||
|
}
|
||
|
|
||
|
func makeScanner(test bool) *bufio.Scanner {
|
||
|
var f *os.File
|
||
|
if test {
|
||
|
f, _ = os.Open("inputs/testinput")
|
||
|
} else {
|
||
|
f, _ = os.Open("inputs/input")
|
||
|
}
|
||
|
reader := bufio.NewReader(f)
|
||
|
return bufio.NewScanner(reader)
|
||
|
}
|
||
|
|
||
|
type floor []int
|
||
|
|
||
|
func partOne() {
|
||
|
scanner := makeScanner(false)
|
||
|
width := 100
|
||
|
height := 100
|
||
|
|
||
|
caveFloor := make([]int, width*height)
|
||
|
i := 0
|
||
|
for scanner.Scan() {
|
||
|
row := strings.Split(scanner.Text(), "")
|
||
|
for j, v := range row {
|
||
|
caveFloor[j+(width*i)] = mustAtoi(v)
|
||
|
}
|
||
|
i++
|
||
|
}
|
||
|
// find low points
|
||
|
points := 0
|
||
|
for row := 0; row < i; row++ {
|
||
|
for col := 0; col < width; col++ {
|
||
|
islow := 0
|
||
|
curr := caveFloor[col+(width*row)]
|
||
|
if col == 0 || curr < caveFloor[(col-1)+(width*row)] { // check left edge
|
||
|
islow++
|
||
|
}
|
||
|
if col+1 == width || curr < caveFloor[(col+1)+(width*row)] { // check right edge
|
||
|
islow++
|
||
|
}
|
||
|
if row == 0 || curr < caveFloor[col+(width*(row-1))] { // top
|
||
|
islow++
|
||
|
}
|
||
|
if row+1 == i || curr < caveFloor[col+(width*(row+1))] { // bottom
|
||
|
islow++
|
||
|
}
|
||
|
if islow == 4 {
|
||
|
points += curr + 1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fmt.Println(points)
|
||
|
}
|
||
|
|
||
|
func downhill(caveFloor []int, width int, col, row int) (int, int) {
|
||
|
curr := caveFloor[col+(width*row)]
|
||
|
nextcol := col
|
||
|
nextrow := row
|
||
|
if col > 0 && curr > caveFloor[(col-1)+(width*row)] { // check left edge
|
||
|
nextcol = (col - 1)
|
||
|
nextrow = row
|
||
|
}
|
||
|
if col < width-1 && curr > caveFloor[(col+1)+(width*row)] { // check right edge
|
||
|
nextcol = (col + 1)
|
||
|
nextrow = row
|
||
|
}
|
||
|
if row > 0 && curr > caveFloor[col+(width*(row-1))] { // top
|
||
|
nextcol = col
|
||
|
nextrow = row - 1
|
||
|
}
|
||
|
if col+(width*(row+1)) < len(caveFloor) && curr > caveFloor[col+(width*(row+1))] { // bottom
|
||
|
nextcol = col
|
||
|
nextrow = row + 1
|
||
|
}
|
||
|
if nextcol == col && nextrow == row { // found our low point
|
||
|
return col, row
|
||
|
}
|
||
|
return downhill(caveFloor, width, nextcol, nextrow)
|
||
|
}
|
||
|
|
||
|
func partTwo() {
|
||
|
scanner := makeScanner(false)
|
||
|
width := 100
|
||
|
height := 100
|
||
|
|
||
|
caveFloor := make([]int, width*height)
|
||
|
i := 0
|
||
|
for scanner.Scan() {
|
||
|
row := strings.Split(scanner.Text(), "")
|
||
|
for j, v := range row {
|
||
|
caveFloor[j+(width*i)] = mustAtoi(v)
|
||
|
}
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
basins := map[int]int{} // map from low-point location to size of basin
|
||
|
for row := 0; row < height; row++ {
|
||
|
for col := 0; col < width; col++ {
|
||
|
if caveFloor[col+row*width] < 9 {
|
||
|
lowcol, lowrow := downhill(caveFloor, width, col, row)
|
||
|
basins[lowcol+lowrow*width]++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
one, two, three := 0, 0, 0
|
||
|
for _, v := range basins {
|
||
|
if v >= one {
|
||
|
one, two, three = v, one, two
|
||
|
} else if v >= two {
|
||
|
two, three = v, two
|
||
|
} else if v >= three {
|
||
|
three = v
|
||
|
}
|
||
|
}
|
||
|
fmt.Println(one * two * three)
|
||
|
}
|