|
6 | 6 | "os"
|
7 | 7 |
|
8 | 8 | "github.com/kfarnung/advent-of-code/2024/lib"
|
| 9 | + "golang.org/x/exp/slices" |
9 | 10 | )
|
10 | 11 |
|
11 | 12 | type point struct {
|
@@ -33,8 +34,25 @@ func part1(input string) int64 {
|
33 | 34 | return sum
|
34 | 35 | }
|
35 | 36 |
|
36 |
| -func part2(_ string) int64 { |
37 |
| - return int64(0) |
| 37 | +func part2(input string) int64 { |
| 38 | + garden := parseInput(input) |
| 39 | + |
| 40 | + sum := int64(0) |
| 41 | + seen := make(map[point]bool) |
| 42 | + |
| 43 | + for i, row := range garden { |
| 44 | + for j, _ := range row { |
| 45 | + location := point{i, j} |
| 46 | + if seen[location] { |
| 47 | + continue |
| 48 | + } |
| 49 | + |
| 50 | + area, perimeter := findAreaAndSides(garden, i, j, seen) |
| 51 | + sum += area * perimeter |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + return sum |
38 | 56 | }
|
39 | 57 |
|
40 | 58 | func findAreaAndPerimeter(garden [][]rune, i, j int, seen map[point]bool) (int64, int64) {
|
@@ -84,6 +102,118 @@ func findAreaAndPerimeter(garden [][]rune, i, j int, seen map[point]bool) (int64
|
84 | 102 | return area, perimeter
|
85 | 103 | }
|
86 | 104 |
|
| 105 | +func findAreaAndSides(garden [][]rune, i, j int, seen map[point]bool) (int64, int64) { |
| 106 | + area := int64(0) |
| 107 | + region := garden[i][j] |
| 108 | + |
| 109 | + var queue []point |
| 110 | + queue = append(queue, point{x: i, y: j}) |
| 111 | + |
| 112 | + edgesTop := make(map[point]bool) |
| 113 | + edgesBottom := make(map[point]bool) |
| 114 | + edgesLeft := make(map[point]bool) |
| 115 | + edgesRight := make(map[point]bool) |
| 116 | + |
| 117 | + for len(queue) > 0 { |
| 118 | + current := queue[0] |
| 119 | + queue = queue[1:] |
| 120 | + |
| 121 | + if seen[current] { |
| 122 | + continue |
| 123 | + } |
| 124 | + |
| 125 | + seen[current] = true |
| 126 | + area++ |
| 127 | + |
| 128 | + if current.x > 0 && garden[current.x-1][current.y] == region { |
| 129 | + queue = append(queue, point{x: current.x - 1, y: current.y}) |
| 130 | + } else { |
| 131 | + edgesTop[current] = true |
| 132 | + } |
| 133 | + |
| 134 | + if current.x < len(garden)-1 && garden[current.x+1][current.y] == region { |
| 135 | + queue = append(queue, point{x: current.x + 1, y: current.y}) |
| 136 | + } else { |
| 137 | + edgesBottom[current] = true |
| 138 | + } |
| 139 | + |
| 140 | + if current.y > 0 && garden[current.x][current.y-1] == region { |
| 141 | + queue = append(queue, point{x: current.x, y: current.y - 1}) |
| 142 | + } else { |
| 143 | + edgesLeft[current] = true |
| 144 | + } |
| 145 | + |
| 146 | + if current.y < len(garden[0])-1 && garden[current.x][current.y+1] == region { |
| 147 | + queue = append(queue, point{x: current.x, y: current.y + 1}) |
| 148 | + } else { |
| 149 | + edgesRight[current] = true |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + return area, countEdges(edgesTop, false) + countEdges(edgesBottom, false) + countEdges(edgesLeft, true) + countEdges(edgesRight, true) |
| 154 | +} |
| 155 | + |
| 156 | +func countEdges(edges map[point]bool, leftRight bool) int64 { |
| 157 | + var keys []point |
| 158 | + for k := range edges { |
| 159 | + keys = append(keys, k) |
| 160 | + } |
| 161 | + |
| 162 | + slices.SortFunc(keys, func(i, j point) int { |
| 163 | + if leftRight { |
| 164 | + if i.y < j.y { |
| 165 | + return -1 |
| 166 | + } |
| 167 | + |
| 168 | + if i.y > j.y { |
| 169 | + return 1 |
| 170 | + } |
| 171 | + |
| 172 | + if i.x < j.x { |
| 173 | + return -1 |
| 174 | + } |
| 175 | + |
| 176 | + if i.x > j.x { |
| 177 | + return 1 |
| 178 | + } |
| 179 | + } else { |
| 180 | + if i.x < j.x { |
| 181 | + return -1 |
| 182 | + } |
| 183 | + |
| 184 | + if i.x > j.x { |
| 185 | + return 1 |
| 186 | + } |
| 187 | + |
| 188 | + if i.y < j.y { |
| 189 | + return -1 |
| 190 | + } |
| 191 | + |
| 192 | + if i.y > j.y { |
| 193 | + return 1 |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + return 0 |
| 198 | + }) |
| 199 | + |
| 200 | + x := -2 |
| 201 | + y := -2 |
| 202 | + sides := int64(0) |
| 203 | + for _, key := range keys { |
| 204 | + if !leftRight && (x != key.x || y+1 != key.y) { |
| 205 | + sides++ |
| 206 | + } else if leftRight && (y != key.y || x+1 != key.x) { |
| 207 | + sides++ |
| 208 | + } |
| 209 | + |
| 210 | + x = key.x |
| 211 | + y = key.y |
| 212 | + } |
| 213 | + |
| 214 | + return sides |
| 215 | +} |
| 216 | + |
87 | 217 | func parseInput(input string) [][]rune {
|
88 | 218 | var data [][]rune
|
89 | 219 | for _, line := range lib.SplitLines(input) {
|
|
0 commit comments