2018 Day 23*
Had to find someone else's python solution to get an answer. Need to pull it apart and figure out what's wrong with my solution.
This commit is contained in:
parent
7c9742fb73
commit
1ec6280623
31
2018/day23/bots.go
Normal file
31
2018/day23/bots.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Bots map[Coordinate][]int
|
||||||
|
|
||||||
|
func NewBots(input []string) Bots {
|
||||||
|
m := make(Bots)
|
||||||
|
for _, data := range input {
|
||||||
|
var r int
|
||||||
|
var c Coordinate
|
||||||
|
_, err := fmt.Sscanf(data, "pos=<%d,%d,%d>, r=%d", &c.X, &c.Y, &c.Z, &r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
m[c] = append(m[c], r)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Bots) HaveInRange(pos Coordinate) int {
|
||||||
|
var sum int
|
||||||
|
for c, rs := range m {
|
||||||
|
for _, r := range rs {
|
||||||
|
if pos.Distance(c) <= r {
|
||||||
|
sum++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
18
2018/day23/coord.go
Normal file
18
2018/day23/coord.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type Coordinate struct {
|
||||||
|
X, Y, Z int
|
||||||
|
}
|
||||||
|
|
||||||
|
var Zero = Coordinate{X: 0, Y: 0, Z: 0}
|
||||||
|
|
||||||
|
func (c Coordinate) Distance(a Coordinate) int {
|
||||||
|
return abs(c.X-a.X) + abs(c.Y-a.Y) + abs(c.Z-a.Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs(v int) int {
|
||||||
|
if v < 0 {
|
||||||
|
return v * -1
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
@ -3,88 +3,86 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var collective *Collective
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
input := stdinToStringSlice()
|
inp := StdinToStringSlice()
|
||||||
|
fmt.Printf("# Part 1\nIn Range of Strongest: %d\n", StrongestReachable(NewBots(inp)))
|
||||||
collective = &Collective{}
|
// Part 2: 94270682 is too low
|
||||||
for _, v := range input {
|
// 94481123 is too low
|
||||||
collective.bots = append(collective.bots, NewBot(v))
|
fmt.Printf("# Part 2\nClosest Success: %d\n", ClosestSuccess(NewBots(inp)))
|
||||||
}
|
|
||||||
part1()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func part1() {
|
func StrongestReachable(bots Bots) int {
|
||||||
s := collective.strongest()
|
var largestRadius, count int
|
||||||
fmt.Println("= Part 1 =")
|
var largestPos Coordinate
|
||||||
fmt.Println(len(collective.inRange(s)))
|
for c, rs := range bots {
|
||||||
}
|
for _, r := range rs {
|
||||||
|
if r > largestRadius {
|
||||||
func part2() {
|
largestPos = c
|
||||||
finder := &Bot{}
|
largestRadius = r
|
||||||
}
|
|
||||||
|
|
||||||
type Collective struct {
|
|
||||||
bots []*Bot
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collective) inRange(b *Bot) []*Bot {
|
|
||||||
var ret []*Bot
|
|
||||||
for _, v := range c.bots {
|
|
||||||
if c.distance(b, v) <= b.radius {
|
|
||||||
ret = append(ret, v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
}
|
||||||
}
|
for c, rs := range bots {
|
||||||
|
if largestPos.Distance(c) <= largestRadius {
|
||||||
func (c *Collective) strongest() *Bot {
|
count += len(rs)
|
||||||
strongest := c.bots[0]
|
|
||||||
for _, v := range c.bots {
|
|
||||||
if v.radius > strongest.radius {
|
|
||||||
strongest = v
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strongest
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collective) distance(b1, b2 *Bot) int {
|
func ClosestSuccess(bots Bots) int {
|
||||||
xs := math.Abs(float64(b1.x) - float64(b2.x))
|
var cur, topLeft, bottomRight Coordinate
|
||||||
ys := math.Abs(float64(b1.y) - float64(b2.y))
|
zoom := 1 << (strconv.IntSize - 2)
|
||||||
zs := math.Abs(float64(b1.z) - float64(b2.z))
|
|
||||||
return int(xs + ys + zs)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bot struct {
|
for {
|
||||||
x, y, z int
|
zoomedBots := make(Bots)
|
||||||
radius int
|
best := struct {
|
||||||
}
|
pos Coordinate
|
||||||
|
count int
|
||||||
|
}{}
|
||||||
|
|
||||||
func NewBot(args string) *Bot {
|
for c, rs := range bots {
|
||||||
pts := strings.Split(args, ", ")
|
for _, r := range rs {
|
||||||
pos := strings.Split(pts[0][5:len(pts[0])-1], ",")
|
zc := Coordinate{c.X / zoom, c.Y / zoom, c.Z / zoom}
|
||||||
r := strings.Split(pts[1], "=")[1]
|
zoomedBots[zc] = append(zoomedBots[zc], r/zoom)
|
||||||
return &Bot{
|
}
|
||||||
x: atoi(pos[0]),
|
}
|
||||||
y: atoi(pos[1]),
|
|
||||||
z: atoi(pos[2]),
|
for cur.X = topLeft.X; cur.X <= bottomRight.X; cur.X++ {
|
||||||
radius: atoi(r),
|
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 (b *Bot) string() string {
|
func StdinToStringSlice() []string {
|
||||||
return fmt.Sprintf("(%d,%d,%d : %d)", b.x, b.y, b.z, b.radius)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stdinToStringSlice() []string {
|
|
||||||
var input []string
|
var input []string
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
@ -92,12 +90,3 @@ func stdinToStringSlice() []string {
|
|||||||
}
|
}
|
||||||
return input
|
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
|
|
||||||
}
|
|
||||||
|
81
2018/day23/day23.py
Executable file
81
2018/day23/day23.py
Executable file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
from collections import OrderedDict, defaultdict, namedtuple
|
||||||
|
from functools import total_ordering
|
||||||
|
from heapq import heappop, heappush
|
||||||
|
from itertools import chain
|
||||||
|
import re
|
||||||
|
|
||||||
|
Bot = namedtuple('Bot', 'x y z r')
|
||||||
|
|
||||||
|
with open('day23.txt') as puzzle_file:
|
||||||
|
pattern = re.compile(r'pos=<(-?\d+),(-?\d+),(-?\d+)>, r=(\d+)')
|
||||||
|
bots = [Bot(*map(int, pattern.match(line).groups())) for line in puzzle_file]
|
||||||
|
|
||||||
|
max_r = max(bot.r for bot in bots)
|
||||||
|
print(
|
||||||
|
max(
|
||||||
|
sum(abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z) <= a.r for b in bots) for a in bots
|
||||||
|
if a.r == max_r))
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
|
class Octa_ordering(object):
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.min < other.min or self.min == other.min and other.max < self.max
|
||||||
|
|
||||||
|
class Octa(Octa_ordering, namedtuple('Octa', ('min', 'max'))):
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
if 'bot' in kwargs:
|
||||||
|
x, y, z, r = kwargs['bot']
|
||||||
|
t, u, v, w = x + y + z, x + y - z, x - y - z, x - y + z
|
||||||
|
return super(Octa, cls).__new__(cls, (t - r, u - r, v - r, w - r),
|
||||||
|
(t + r, u + r, v + r, w + r))
|
||||||
|
return super(Octa, cls).__new__(cls, *args, **kwargs)
|
||||||
|
|
||||||
|
def intersect(self, other):
|
||||||
|
c, d, e, f = self.min
|
||||||
|
g, h, i, j = other.min
|
||||||
|
k, l, m, n = self.max
|
||||||
|
o, p, q, r = other.max
|
||||||
|
s, t, u, v = max(c, g), max(d, h), max(e, i), max(f, j)
|
||||||
|
w, x, y, z = min(k, o), min(l, p), min(m, q), min(n, r)
|
||||||
|
return None if s > w or t > x or u > y or v > z else Octa((s, t, u, v), (w, x, y, z))
|
||||||
|
|
||||||
|
def distance_to_origin(self):
|
||||||
|
o, p, q, r = self.min
|
||||||
|
s, t, u, v = self.max
|
||||||
|
if o < s and p < t and q < u and r < v:
|
||||||
|
w = min(abs(o), abs(s)) if o * s >= 0 else 0
|
||||||
|
x = min(abs(p), abs(t)) if p * t >= 0 else 0
|
||||||
|
y = min(abs(q), abs(u)) if q * u >= 0 else 0
|
||||||
|
z = min(abs(r), abs(v)) if r * v >= 0 else 0
|
||||||
|
return max(w, x, y, z)
|
||||||
|
return min(
|
||||||
|
abs((x + z) // 2) + abs((y - z) // 2) + abs((x - y) // 2)
|
||||||
|
for x in range(o, s + 1) for y in range(p + ((p ^ x) & 1), t + 1, 2)
|
||||||
|
for z in range(q + ((q ^ x) & 1), u + 1, 2) if r <= x - y + z <= v)
|
||||||
|
|
||||||
|
best_count = 0
|
||||||
|
octs = defaultdict(set)
|
||||||
|
for i, bot in enumerate(bots):
|
||||||
|
octs[Octa(bot=bot)].add(i)
|
||||||
|
queue = [(0, (), OrderedDict((k, octs[k]) for k in sorted(octs)))]
|
||||||
|
while queue:
|
||||||
|
n, _, rest = heappop(queue)
|
||||||
|
if -n < best_count:
|
||||||
|
break
|
||||||
|
octa, n = rest.popitem()
|
||||||
|
sub = defaultdict(set)
|
||||||
|
for octa2, m in rest.items():
|
||||||
|
octa3 = octa.intersect(octa2)
|
||||||
|
if octa3 is not None:
|
||||||
|
(n if octa == octa3 else sub[octa3]).update(m)
|
||||||
|
if len(n) > best_count:
|
||||||
|
best_count, best_distance = len(n), [octa]
|
||||||
|
elif len(n) == best_count:
|
||||||
|
best_distance.append(octa)
|
||||||
|
m = frozenset(chain.from_iterable(rest.values()))
|
||||||
|
heappush(queue, (-len(m), m, rest))
|
||||||
|
rest = OrderedDict((k, sub[k].union(n)) for k in sorted(sub))
|
||||||
|
m = frozenset(chain.from_iterable(rest.values()))
|
||||||
|
heappush(queue, (-len(m), m, rest))
|
||||||
|
print(min(octa.distance_to_origin() for octa in best_distance))
|
1000
2018/day23/day23.txt
Normal file
1000
2018/day23/day23.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,6 @@
|
|||||||
pos=<0,0,0>, r=4
|
pos=<10,12,12>, r=2
|
||||||
pos=<1,0,0>, r=1
|
pos=<12,14,12>, r=2
|
||||||
pos=<4,0,0>, r=3
|
pos=<16,12,12>, r=4
|
||||||
pos=<0,2,0>, r=1
|
pos=<14,14,14>, r=6
|
||||||
pos=<0,5,0>, r=3
|
pos=<50,50,50>, r=200
|
||||||
pos=<0,0,3>, r=1
|
pos=<10,10,10>, r=5
|
||||||
pos=<1,1,1>, r=1
|
|
||||||
pos=<1,1,2>, r=1
|
|
||||||
pos=<1,3,1>, r=1
|
|
||||||
|
Loading…
Reference in New Issue
Block a user