adventofcode/2024/day12/main.go

163 lines
3.7 KiB
Go
Raw Normal View History

2024-12-12 14:46:54 +00:00
package main
import (
"fmt"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToCoordMap()
part1(inp)
fmt.Println("")
part2(inp)
}
func part1(inp h.CoordByteMap) {
fmt.Println("# Part 1")
var total int
trackedPlots := make(map[h.Coordinate]bool)
for y := inp.TLY; y <= inp.BRY; y++ {
for x := inp.TLX; x <= inp.BRX; x++ {
c := h.Coordinate{X: x, Y: y}
if trackedPlots[c] {
continue
}
plant := inp.Get(c)
region := findRegion(inp, c, make(map[h.Coordinate]bool))
area := len(region)
var perimeter int
for k := range region {
trackedPlots[k] = true
for _, chk := range []h.Coordinate{k.North(), k.East(), k.South(), k.West()} {
if inp.Get(chk) != plant {
perimeter++
}
}
}
total = total + (area * perimeter)
}
}
fmt.Println("Total Price:", total)
}
func part2(inp h.CoordByteMap) {
fmt.Println("# Part 2")
var total int
trackedPlots := make(map[h.Coordinate]bool)
for y := inp.TLY; y <= inp.BRY; y++ {
for x := inp.TLX; x <= inp.BRX; x++ {
c := h.Coordinate{X: x, Y: y}
if trackedPlots[c] {
continue
}
region := findRegion(inp, c, make(map[h.Coordinate]bool))
area := len(region)
for k := range region {
trackedPlots[k] = true
}
sides := findSides(region)
total = total + (area * sides)
}
}
fmt.Println("Total Price:", total)
}
func findRegion(inp h.CoordByteMap, start h.Coordinate, checked map[h.Coordinate]bool) map[h.Coordinate]bool {
ret := make(map[h.Coordinate]bool)
bt := inp.Get(start)
ret[start] = true
for _, chk := range []h.Coordinate{start.North(), start.East(), start.South(), start.West()} {
if checked[chk] {
continue
}
if inp.Get(chk) == bt {
checked[chk] = true
ret[chk] = true
for k := range findRegion(inp, chk, checked) {
ret[k] = true
}
}
}
return ret
}
var (
N = h.Coordinate{X: 0, Y: -1}
NE = h.Coordinate{X: 1, Y: -1}
E = h.Coordinate{X: 1, Y: 0}
SE = h.Coordinate{X: 1, Y: 1}
S = h.Coordinate{X: 0, Y: 1}
SW = h.Coordinate{X: -1, Y: 1}
W = h.Coordinate{X: -1, Y: 0}
NW = h.Coordinate{X: -1, Y: -1}
)
func findSides(region map[h.Coordinate]bool) int {
var sides int
for chk := range region {
sides = sides + checkForExteriorCorner(chk, region)
sides = sides + checkForInteriorCorner(chk, region)
}
return sides
}
// checkForExteriorCorner returns how many exterior corners 'chk' is a part of
func checkForExteriorCorner(chk h.Coordinate, region map[h.Coordinate]bool) int {
var ret int
// Check orthoganal neighbor pairs (N/E, E/S, S/W, W/N) for an exterior corner
if checkDiff(chk, N, region) {
if checkDiff(chk, E, region) {
ret++
}
if checkDiff(chk, W, region) {
ret++
}
}
if checkDiff(chk, S, region) {
if checkDiff(chk, E, region) {
ret++
}
if checkDiff(chk, W, region) {
ret++
}
}
return ret
}
// checkForInteriorCorner returns how many interior corners 'chk' is a part of
func checkForInteriorCorner(chk h.Coordinate, region map[h.Coordinate]bool) int {
var ret int
// Check for interior corner (N/E != NE, E/S != SE, S/W != SW, W/N != NW)
if checkDiff(chk, NE, region) {
if checkSame(chk, N, region) && checkSame(chk, E, region) {
ret++
}
}
if checkDiff(chk, SE, region) {
if checkSame(chk, S, region) && checkSame(chk, E, region) {
ret++
}
}
if checkDiff(chk, SW, region) {
if checkSame(chk, S, region) && checkSame(chk, W, region) {
ret++
}
}
if checkDiff(chk, NW, region) {
if checkSame(chk, N, region) && checkSame(chk, W, region) {
ret++
}
}
return ret
}
func checkDiff(chk, dir h.Coordinate, region map[h.Coordinate]bool) bool {
return !checkSame(chk, dir, region)
}
func checkSame(chk, dir h.Coordinate, region map[h.Coordinate]bool) bool {
_, ok := region[chk.Add(dir)]
return ok
}