package main
import (
"bufio"
"log"
"os"
"sort"
"strconv"
)
var directions = [][2]int{
{-1, 0}, {1, 0}, {0, -1}, {0, 1}, }
type Matrix [][]int
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
matrix, err := parseInput("input.txt")
if err != nil {
return err
}
log.Println(solveFirst(matrix))
log.Println(solveSecond(matrix))
return nil
}
type Seen map[[2]int]bool
func solveSecond(m Matrix) int {
lows := m.getLows()
var ret = make([]int, len(lows))
var seen = Seen{}
for i, item := range lows {
ret[i] = seen.getBasinSize(m, item)
}
sort.Ints(ret)
return ret[len(ret)-1] * ret[len(ret)-2] * ret[len(ret)-3]
}
func (seen Seen) getBasinSize(m Matrix, item [2]int) int {
var ret int
row, col := item[0], item[1]
if seen[item] || m[row][col] == 9 {
return 0
}
seen[item] = true
ret++
for _, d := range directions {
if row+d[0] >= 0 && row+d[0] < len(m) &&
col+d[1] >= 0 && col+d[1] < len(m[0]) {
if m[row+d[0]][col+d[1]] != 9 {
ret += seen.getBasinSize(m, [2]int{row + d[0], col + d[1]})
}
}
}
return ret
}
func (m Matrix) getLows() [][2]int {
var ret [][2]int
for row, line := range m {
for col := range line {
if m.checkLow(row, col) {
ret = append(ret, [2]int{row, col})
}
}
}
return ret
}
func solveFirst(m Matrix) int {
var ret int
for row, line := range m {
for col, item := range line {
if m.checkLow(row, col) {
ret += item + 1
}
}
}
return ret
}
func (m Matrix) checkLow(row, col int) bool {
for _, d := range directions {
if row+d[0] >= 0 && row+d[0] < len(m) &&
col+d[1] >= 0 && col+d[1] < len(m[0]) {
if m[row+d[0]][col+d[1]] <= m[row][col] {
return false
}
}
}
return true
}
func parseInput(fileName string) (Matrix, error) {
var ret = Matrix{}
fd, err := os.Open(fileName)
if err != nil {
return ret, err
}
defer fd.Close()
buf := bufio.NewScanner(fd)
var line []int
for buf.Scan() {
for _, ch := range buf.Text() {
tmp, err := strconv.Atoi(string(ch))
if err != nil {
return nil, err
}
line = append(line, tmp)
}
ret = append(ret, line)
line = []int{}
}
return ret, nil
}