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 }