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) }