Files
aoc2024/day12/main.go
2024-12-20 15:33:15 +01:00

182 lines
3.7 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
fmt.Println("Part 1")
fmt.Println(part1(readData("example1.txt")), 140)
fmt.Println(part1(readData("example2.txt")), 772)
fmt.Println(part1(readData("example3.txt")), 1930)
fmt.Println(part1(readData("data.txt")))
fmt.Println()
fmt.Println("Part 2")
fmt.Println(part2(readData("example1.txt")), 80)
fmt.Println(part2(readData("example2.txt")), 436)
fmt.Println(part2(readData("example3.txt")), 1206)
fmt.Println(part2(readData("example4.txt")), 236)
fmt.Println(part2(readData("example5.txt")), 368)
fmt.Println(part2(readData("data.txt")))
}
func part2(plots [][]byte) (totalPrice int) {
visited := make([][]int, len(plots))
for i, line := range plots {
visited[i] = make([]int, len(line))
}
nextPlotId := 1
areas := make([]int, 1)
for y := range len(plots) {
for x := range len(plots[y]) {
if visited[y][x] > 0 {
continue
}
area := visitPlot2(plots, visited, nextPlotId, x, y)
areas = append(areas, area)
nextPlotId += 1
}
}
sides := make([]int, len(areas))
for y := range len(plots) + 1 {
p0, p1 := 0, 0
for x := range len(plots[0]) + 1 {
p0Next := getPlotIdOrZero(visited, x, y-1)
p1Next := getPlotIdOrZero(visited, x, y)
scanSides(visited, sides, p0, p1, p0Next, p1Next)
p0, p1 = p0Next, p1Next
}
}
for x := range len(plots[0]) + 1 {
p0, p1 := 0, 0
for y := range len(plots) + 1 {
p0Next := getPlotIdOrZero(visited, x-1, y)
p1Next := getPlotIdOrZero(visited, x, y)
scanSides(visited, sides, p0, p1, p0Next, p1Next)
p0, p1 = p0Next, p1Next
}
}
for i := range areas {
totalPrice += areas[i] * sides[i]
}
return
}
func scanSides(visited [][]int, sides []int, p0, p1, p0Next, p1Next int) {
if p0Next != p1Next {
if p0 == p1 {
sides[p0Next] += 1
sides[p1Next] += 1
} else {
if p0 != p0Next {
sides[p0Next] += 1
}
if p1 != p1Next {
sides[p1Next] += 1
}
}
}
}
var DIR = [4][2]int{{0, -1}, {-1, 0}, {0, 1}, {1, 0}}
func visitPlot2(plots [][]byte, visited [][]int, plotId int, x, y int) (area int) {
if visited[y][x] > 0 {
return
}
visited[y][x] = plotId
area += 1
p := plots[y][x]
for _, dir := range DIR {
other := getPlotOrZero(plots, x+dir[0], y+dir[1])
if other == p {
area += visitPlot2(plots, visited, plotId, x+dir[0], y+dir[1])
}
}
return
}
func getPlotOrZero(plots [][]byte, x, y int) byte {
if x < 0 || y < 0 || y >= len(plots) || x >= len(plots[y]) {
return 0
} else {
return plots[y][x]
}
}
func getPlotIdOrZero(plots [][]int, x, y int) int {
if x < 0 || y < 0 || y >= len(plots) || x >= len(plots[y]) {
return 0
} else {
return plots[y][x]
}
}
func part1(plots [][]byte) (totalPrice int) {
visited := make([][]bool, len(plots))
for i, line := range plots {
visited[i] = make([]bool, len(line))
}
for y := range len(plots) {
for x := range len(plots[y]) {
area, perimeter := visitPlot1(plots, visited, x, y)
totalPrice += area * perimeter
}
}
return
}
func visitPlot1(plots [][]byte, visited [][]bool, x, y int) (area, perimeter int) {
if visited[y][x] {
return
}
visited[y][x] = true
area += 1
p := plots[y][x]
for _, dir := range DIR {
other := getPlotOrZero(plots, x+dir[0], y+dir[1])
if other == p {
otherArea, otherPerimeter := visitPlot1(plots, visited, x+dir[0], y+dir[1])
area += otherArea
perimeter += otherPerimeter
} else {
perimeter += 1
}
}
return
}
func readData(fileName string) (plots [][]byte) {
fp, err := os.Open(fileName)
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
plots = append(plots, []byte(line))
}
return
}