package main import ( "bufio" "fmt" "log" "math" "os" "strconv" "strings" ) const MaxInt = int(^uint(0) >> 1) func main() { inp := StdinToStringSlice() start(inp) part1() part2() } var points []RegionPos var boundaries []RegionPos var allPoints []RegionPos var maxX, maxY, minX, minY int func start(inp []string) { maxX, maxY = 0, 0 minX, minY = MaxInt, MaxInt for _, v := range inp { pts := strings.Split(v, ", ") x, y := Atoi(pts[0]), Atoi(pts[1]) p := RegionPos{x: x, y: y} points = append(points, p) if x < minX { minX = x } if x > maxX { maxX = x } if y < minY { minY = y } if y > maxY { maxY = y } } // Find the points that are the closest to the boundaries for x := minX; x <= maxX; x++ { boundaries = append(boundaries, *NewRegionPos(x, minY)) boundaries = append(boundaries, *NewRegionPos(x, maxY)) } for y := minY; y <= maxY; y++ { boundaries = append(boundaries, *NewRegionPos(minX, y)) boundaries = append(boundaries, *NewRegionPos(maxX, y)) } for i := range boundaries { closest := boundaries[i].findClosest(points) if len(closest) == 1 { for j := range points { if points[j].x == closest[0].x && points[j].y == closest[0].y { points[j].ignored = true } } } else { boundaries[i].ignored = true } } } func part1() { for x := minX; x <= maxX; x++ { for y := minY; y <= maxY; y++ { p := NewRegionPos(x, y) closest := p.findClosest(points) if len(closest) == 1 { c := closest[0] for i := range points { if points[i].ignored { continue } if points[i].x == c.x && points[i].y == c.y { points[i].regionSize++ break } } } } } var largestSize int for _, v := range points { if !v.ignored { if v.regionSize > largestSize { largestSize = v.regionSize } } } fmt.Println("= Part 1 =") fmt.Println(largestSize) } func part2() { minDistance := 10000 var regionCount int for y := minY - minDistance; y <= maxY+minDistance; y++ { for x := minX - minDistance; x <= maxX+minDistance; x++ { p := NewRegionPos(x, y) if p.sumOfDistances(minDistance, points) < minDistance { regionCount++ } } } fmt.Println("= Part 2 =") fmt.Println(regionCount) } func manhattanDistance(x1, y1, x2, y2 int) int { return int(math.Abs(float64(x1)-float64(x2)) + math.Abs(float64(y1)-float64(y2))) } type RegionPos struct { x, y int regionSize int closestPos *RegionPos ignored bool } func NewRegionPos(x, y int) *RegionPos { b := &RegionPos{} b.x = x b.y = y return b } func (p *RegionPos) distanceToPos(o *RegionPos) int { return manhattanDistance(p.x, p.y, o.x, o.y) } func (b *RegionPos) sumOfDistances(d int, list []RegionPos) int { var ret int for _, p := range list { ret += b.distanceToPos(&p) } return ret } func (b *RegionPos) findClosest(list []RegionPos) []RegionPos { var ret []RegionPos minD := MaxInt for _, p := range list { test := b.distanceToPos(&p) if test < minD { minD = test ret = ret[:0] ret = append(ret, p) } else if test == minD { ret = append(ret, p) } } return ret } func (b *RegionPos) string() string { return fmt.Sprintf("%d;%d", b.x, b.y) } func StdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi") } return ret }