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:
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))
|
||||
Reference in New Issue
Block a user