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 } 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) if isCorner(graph, current, ns[N], ns[E]) { corners++ } if isCorner(graph, current, ns[S], ns[E]) { corners++ } if isCorner(graph, current, ns[N], ns[W]) { corners++ } if isCorner(graph, current, ns[S], ns[W]) { corners++ } corners += numInnerCorner(graph, current, ns) } 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 numInnerCorner(graph *graph, current point, ns [4]point) int { var corners int if isInnerCorner(graph, current, ns[N], ns[E], point{current.x + 1, current.y - 1}) { corners++ } if isInnerCorner(graph, current, ns[N], ns[W], point{current.x - 1, current.y - 1}) { corners++ } if isInnerCorner(graph, current, ns[S], ns[E], point{current.x + 1, current.y + 1}) { corners++ } if isInnerCorner(graph, current, ns[S], ns[W], point{current.x - 1, current.y + 1}) { corners++ } return corners } 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 }