mirror of
https://github.com/onyx-and-iris/aoc2024.git
synced 2025-01-10 06:40:47 +00:00
113 lines
2.4 KiB
Go
113 lines
2.4 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 i := 0; i < len(graph.data); i++ {
|
|
for j := 0; j < len(graph.data[i]); j++ {
|
|
start := newPoint(j, i)
|
|
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)), graph, path)
|
|
|
|
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, graph *graph, path path) int {
|
|
log.Debugf("graph for values %s\n%s\n", string(kind), graph.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(graph, current, points[first], points[second]) {
|
|
corners++
|
|
}
|
|
|
|
if isInnerCorner(graph, current, points[first], points[second], points[diagonal]) {
|
|
corners++
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Debugf("this path has %d corners", corners)
|
|
|
|
return corners
|
|
}
|
|
|
|
func isCorner(graph *graph, current, p, q point) bool {
|
|
if graph.isOutOfBounds(p) && graph.isOutOfBounds(q) {
|
|
return true
|
|
}
|
|
|
|
if !graph.isOutOfBounds(p) {
|
|
if graph.isOutOfBounds(q) && !graph.sameKind(p, current) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
if !graph.isOutOfBounds(q) {
|
|
if graph.isOutOfBounds(p) && !graph.sameKind(q, current) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
if !graph.isOutOfBounds(p) && !graph.isOutOfBounds(q) {
|
|
if !graph.sameKind(p, current) && !graph.sameKind(q, current) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func isInnerCorner(graph *graph, current, p, q, diagonal point) bool {
|
|
if !graph.isOutOfBounds(p) && !graph.isOutOfBounds(q) {
|
|
if graph.sameKind(p, current) && graph.sameKind(q, current) &&
|
|
!graph.sameKind(diagonal, current) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|