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 }