From 3b0f5ab20ce312b2aa467425873cb178f670f99b Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Thu, 9 Dec 2021 18:09:22 +0100 Subject: [PATCH] 2021 - Day 9 --- 2021/9/go.mod | 9 ++++ 2021/9/go.sum | 2 + 2021/9/main.go | 127 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 2021/9/go.mod create mode 100644 2021/9/go.sum create mode 100644 2021/9/main.go diff --git a/2021/9/go.mod b/2021/9/go.mod new file mode 100644 index 0000000..226512f --- /dev/null +++ b/2021/9/go.mod @@ -0,0 +1,9 @@ +module AoC/2021/9 + +require AoC/2021/common v0.0.0 + +require github.com/joho/godotenv v1.4.0 // indirect + +replace AoC/2021/common v0.0.0 => ../common + +go 1.17 diff --git a/2021/9/go.sum b/2021/9/go.sum new file mode 100644 index 0000000..8c9f290 --- /dev/null +++ b/2021/9/go.sum @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/2021/9/main.go b/2021/9/main.go new file mode 100644 index 0000000..3a62e5d --- /dev/null +++ b/2021/9/main.go @@ -0,0 +1,127 @@ +package main + +import ( + aoc "AoC/2021/common" + "bufio" + "sort" + "strconv" + "strings" +) + +func processInput(input *bufio.Scanner) ([][]int, int, int) { + var heightmap [][]int + for input.Scan() { + heights := strings.Split(input.Text(), "") + + var row []int + for _, height := range heights { + // Ignore any errors + h, _ := strconv.Atoi(height) + row = append(row, h) + } + + heightmap = append(heightmap, row) + } + + ymax := len(heightmap) - 1 + // This assumes that at least one row exists and that all rows have the same length + xmax := len(heightmap[0]) - 1 + + return heightmap, xmax, ymax +} + +func floodFill(heightmap [][]int, marked []bool, size int, x int, y int, xmax int, ymax int) ([]bool, int) { + if heightmap[y][x] != 9 && !marked[y*(xmax+1) + x] { + marked[y*(xmax+1) + x] = true + size++ + + if (x != 0) { + marked, size = floodFill(heightmap, marked, size, x-1, y, xmax, ymax) + } + + if (x != xmax) { + marked, size = floodFill(heightmap, marked, size, x+1, y, xmax, ymax) + } + + if (y != 0) { + marked, size = floodFill(heightmap, marked, size, x, y-1, xmax, ymax) + } + + if (y != ymax) { + marked, size = floodFill(heightmap, marked, size, x, y+1, xmax, ymax) + } + } + + return marked, size +} + +func main() { + challenge := aoc.New(2021, 9) + + challenge.Test(`2199943210 +3987894921 +9856789892 +8767896789 +9899965678`, []int{15, 1134}) + + challenge.Solution(1, func (input *bufio.Scanner) int { + heightmap, xmax, ymax := processInput(input) + + sum := 0 + for y := 0; y <= ymax; y++ { + for x := 0; x <= xmax; x++ { + height := heightmap[y][x] + if (x != 0 && heightmap[y][x-1] <= height) || (x != xmax && heightmap[y][x+1] <= height) { + // Neighbour on the x-axis is lower + continue + } + + if (y != 0 && heightmap[y-1][x] <= height) || (y != ymax && heightmap[y+1][x] <= height) { + // Neighbour on the y-axis is lower + continue + } + + // Found a low point + sum += 1 + height + } + } + + return sum + }) + + challenge.Solution(2, func (input *bufio.Scanner) int { + heightmap, xmax, ymax := processInput(input) + + // Find the size of all basins + var sizes []int + for y := 0; y <= ymax; y++ { + for x := 0; x <= xmax; x++ { + height := heightmap[y][x] + if (x != 0 && heightmap[y][x-1] <= height) || (x != xmax && heightmap[y][x+1] <= height) { + // Neighbour on the x-axis is lower + continue + } + + if (y != 0 && heightmap[y-1][x] <= height) || (y != ymax && heightmap[y+1][x] <= height) { + // Neighbour on the y-axis is lower + continue + } + + // Found a low point, find the size of the basin using flood fill + _, size := floodFill(heightmap, make([]bool, (ymax+1)*(xmax+1)), 0, x, y, xmax, ymax) + sizes = append(sizes, size) + } + } + + // Sort the basin sizes + sort.Ints(sizes) + + // Multiply the largest three + answer := 1 + for _, size := range sizes[len(sizes)-3:] { + answer *= size + } + + return answer + }) +}