aoc2024/day-12/internal/two/solve.go

113 lines
2.3 KiB
Go

package two
import (
"bytes"
log "github.com/sirupsen/logrus"
)
func Solve(buf []byte) (int, error) {
r := bytes.NewReader(buf)
graph, err := parseLines(r)
if err != nil {
return 0, err
}
var totalCost int
totalAreaVisited := make(map[point]struct{})
for y := range graph.data {
for x := range graph.data[y] {
start := newPoint(x, y)
if graph.isOutOfBounds(start) {
continue
}
_, ok := totalAreaVisited[start]
if ok {
continue
}
totalAreaVisited[start] = struct{}{}
path := exploreAreaSequentially(start, graph)
numSides := analyzeSides(graph.valueAt(firstPointFromMap(path.visited)), path, graph)
totalCost += len(path.visited) * numSides
for point := range path.visited {
totalAreaVisited[point] = struct{}{}
}
}
}
return totalCost, nil
}
const (
first = iota
second
diagonal
)
func analyzeSides(kind rune, path path, g *graph) int {
log.Debugf("graph for values %s\n%s\n", string(kind), g.debug(path.visited))
var corners int
for current := range path.visited {
ns := neighbours(current)
for _, points := range [][]point{
{ns[N], ns[E], point{current.x + 1, current.y - 1}},
{ns[N], ns[W], point{current.x - 1, current.y - 1}},
{ns[S], ns[E], point{current.x + 1, current.y + 1}},
{ns[S], ns[W], point{current.x - 1, current.y + 1}},
} {
if isCorner(current, points[first], points[second], g) {
corners++
}
if isInnerCorner(current, points[first], points[second], points[diagonal], g) {
corners++
}
}
}
log.Debugf("this path has %d corners", corners)
return corners
}
func isCorner(current, p, q point, g *graph) bool {
if g.isOutOfBounds(p) && g.isOutOfBounds(q) {
return true
}
if !g.isOutOfBounds(p) {
if g.isOutOfBounds(q) && !g.sameKind(p, current) {
return true
}
}
if !g.isOutOfBounds(q) {
if g.isOutOfBounds(p) && !g.sameKind(q, current) {
return true
}
}
if !g.isOutOfBounds(p) && !g.isOutOfBounds(q) {
if !g.sameKind(p, current) && !g.sameKind(q, current) {
return true
}
}
return false
}
func isInnerCorner(current, p, q, diagonal point, g *graph) bool {
if !g.isOutOfBounds(p) && !g.isOutOfBounds(q) {
if g.sameKind(p, current) && g.sameKind(q, current) &&
!g.sameKind(diagonal, current) {
return true
}
}
return false
}