adventofcode/2018/day23/day23.go

93 lines
2.0 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
inp := StdinToStringSlice()
fmt.Printf("# Part 1\nIn Range of Strongest: %d\n", StrongestReachable(NewBots(inp)))
// Part 2: 94270682 is too low
// 94481123 is too low
fmt.Printf("# Part 2\nClosest Success: %d\n", ClosestSuccess(NewBots(inp)))
}
func StrongestReachable(bots Bots) int {
var largestRadius, count int
var largestPos Coordinate
for c, rs := range bots {
for _, r := range rs {
if r > largestRadius {
largestPos = c
largestRadius = r
}
}
}
for c, rs := range bots {
if largestPos.Distance(c) <= largestRadius {
count += len(rs)
}
}
return count
}
func ClosestSuccess(bots Bots) int {
var cur, topLeft, bottomRight Coordinate
zoom := 1 << (strconv.IntSize - 2)
for {
zoomedBots := make(Bots)
best := struct {
pos Coordinate
count int
}{}
for c, rs := range bots {
for _, r := range rs {
zc := Coordinate{c.X / zoom, c.Y / zoom, c.Z / zoom}
zoomedBots[zc] = append(zoomedBots[zc], r/zoom)
}
}
for cur.X = topLeft.X; cur.X <= bottomRight.X; cur.X++ {
for cur.Y = topLeft.Y; cur.Y <= bottomRight.Y; cur.Y++ {
for cur.Z = topLeft.Z; cur.Z <= bottomRight.Z; cur.Z++ {
c := zoomedBots.HaveInRange(cur)
// skip less bots
if c < best.count {
continue
}
// skip same amount of bots but Distance from Zero is the same or more
if c == best.count && Zero.Distance(cur) >= Zero.Distance(best.pos) {
continue
}
// more bots or same and closer to Zero
best.pos, best.count = cur, c
}
}
}
// zoom in
topLeft.X, topLeft.Y, topLeft.Z = (best.pos.X-1)<<1, (best.pos.Y-1)<<1, (best.pos.Z-1)<<1
bottomRight.X, bottomRight.Y, bottomRight.Z = (best.pos.X+1)<<1, (best.pos.Y+1)<<1, (best.pos.Z+1)<<1
zoom >>= 1
if zoom == 0 {
return Zero.Distance(best.pos)
}
}
}
func StdinToStringSlice() []string {
var input []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input = append(input, scanner.Text())
}
return input
}