163 lines
3.7 KiB
Go
163 lines
3.7 KiB
Go
|
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
|
||
|
}
|