Brian Buller
1ec6280623
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.
82 lines
3.1 KiB
Python
Executable File
82 lines
3.1 KiB
Python
Executable File
#!/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))
|