adventofcode/2018/day06/day06.go

186 lines
3.5 KiB
Go

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
}