Browse Source

🚧

master
Roderic Day 2 years ago
parent
commit
f7764708b5
3 changed files with 197 additions and 27 deletions
  1. +39
    -27
      y2022/p15.py
  2. +61
    -0
      y2022/p16.py
  3. +97
    -0
      y2022/p17.py

+ 39
- 27
y2022/p15.py View File

@@ -1,33 +1,45 @@
import functools
import itertools
import collections
import re

text = open(0).read()
grid = {}
match = {}
for x, y, a, b in [[int(n) for n in re.findall(r'-?\d+', ln)] for ln in text.splitlines()]:
match[complex(x, y)] = complex(a, b)
ns = [int(n) for n in ''.join(n if n.isdigit() else ' ' for n in text).split()]
circles = {(x, y, abs(x - a) + abs(y - b)) for x, y , a, b in zip(*[iter(ns)] * 4)}

goal = 2000000
bop = 4000000
seen = set()
count = collections.Counter()
for aa, bb in match.items():
diff = bb - aa
reach = int(abs(diff.real) + abs(diff.imag))
dist = int(abs(aa.imag - goal))
if reach > dist:
df = reach - dist
seen |= set(range(int(aa.real - df), int(aa.real + df)))

for rot in [1j ** i for i in range(4)]:
for dx in range(reach):
dy = reach - dx
edgy = aa + complex(dx, dy) * rot
for dot in [rot, rot * 1j]:
bip = edgy + dot
if 0 <= bip.real <= bop and 0 <= bip.imag <= bop:
count[bip] += 1

y_lim = 2_000_000
seen = set()
for x, y, r in circles:
dy = abs(y_lim - y)
dx = r - dy
seen |= set(range(x - dx, x + dx))
print(len(seen))
fin = count.most_common()[0][0]
print(fin, int(fin.real * bop + fin.imag))


criss = []
cross = []
for x, y, r in circles:
p = complex(x, y)
for i in range(4):
line = (p + r * 1j ** i), (1j ** (i + 1) + 1j ** (i + 2) ), r + 1
if i % 2:
criss.append(line)
else:
cross.append(line)


def intersection(l1, l2):
(p1, d1, r1), (p2, d2, r2) = l1, l2
for x in range(r1 + 1):
# (p1 + d1 * x) = (p2 + d2 * ?)
if (p1 + d1 * x) - p2 == d2:
if ((p1 + d1 * x - p2) / d2).real <= r2:
yield p1 + d1 * x


counter = collections.Counter()
for l1, l2 in itertools.product(criss, cross):
for p in intersection(l1, l2):
counter[p] += 1
print(max(counter, key=counter.get))

+ 61
- 0
y2022/p16.py View File

@@ -0,0 +1,61 @@
import collections
import itertools
import re

text = open(0).read()


graph = collections.defaultdict(dict)
rates = {}
for ln in text.splitlines():
source, rate, *leads_to = re.findall(r'[A-Z]{2}|\d+', ln)
for out in leads_to:
graph[out][source] = 1
graph[source][out] = 1
rates[source] = int(rate)


costs = {}
for k in graph:
edge = set(graph[k])
seen = set()
cost = 1
while True:
for e in edge:
if (k, e) in costs:
costs[k, e] = min(costs[k, e], cost)
else:
costs[k, e] = cost
cost += 1
edge = {n for e in edge for n in graph[e]} - seen
if seen == set(graph):
break
seen |= edge


def for_one(combo, lim):
tt = 0
bob = [0]
for a, b in zip(('AA',) + combo, combo):
tt = costs[a, b]
for _ in range(tt):
bob.append(bob[-1])
bob.append(bob[-1] + rates[b])
pending = max(0, lim - len(bob))
bob += [bob[-1]] * pending
return sum(bob[:lim])


def generate_combos(pending, left, carry=('AA',)):
if left < 0 or not pending:
yield carry[1:]
else:
for k in pending:
yield from generate_combos(pending - {k}, left - costs[carry[-1], k], carry + (k,))


combos = generate_combos({k for k, v in rates.items() if v}, lim=30)
best = max(combos, key=for_one)
print(best)
print(for_one(best))
# 2615

+ 97
- 0
y2022/p17.py View File

@@ -0,0 +1,97 @@
from itertools import cycle


SCHEME = '''
####

.#.
###
.#.

..#
..#
###

#
#
#
#

##
##
'''


def generate_blocks(scheme):
blocks = []
for block in scheme.strip().split('\n\n'):
blocks.append(set())
lns = block.splitlines()
for y, row in enumerate(lns[::-1]):
for x, v in enumerate(row, 2):
if v == '#':
blocks[-1].add(complex(x, y))
return blocks


def play_tetris(width, gusts, blocks, lim=None):
top = 0
solid = {j for j in range(width)}
contribs = []

block_cycle = cycle(enumerate(blocks))
gust_cycle = cycle(enumerate(gusts))
states = {}

gust_idx = None
for block_idx, block in block_cycle:
# position block 4 up from top
block = {(p + 1j * top) + 4j for p in block}

# identify cycle
if lim is None:
state = tuple(complex(x, top - dy) in solid for x in range(7) for dy in range(1))
key = block_idx, gust_idx, state
if key in states:
cycle_idx = states.get(key)
return contribs[:cycle_idx], contribs[cycle_idx:]
states[key] = len(states)

# play
for gust_idx, gust in gust_cycle:
# move sideways
dx = {'<': -1, '>': 1}[gust]
new = {p + dx for p in block}
if not any(p in solid or p.real in {-1, width} for p in new):
block = new

# move down
dy = -1j
new = {p + dy for p in block}
if any(p in solid for p in new):
solid |= block
break
else:
block = new

contribs.append(int(max(abs(p.imag) for p in solid)) - top)
top = sum(contribs)

if len(contribs) == lim:
return contribs


def main():
width = 7
gusts = open(0).read().strip()
blocks = generate_blocks(SCHEME)

contribs = play_tetris(width, gusts, blocks, lim=2022)
print(sum(contribs))

head, tail = play_tetris(width, gusts, blocks)
N = 1_000_000_000_000 - len(head)
print(sum(head) + sum(tail) * N // len(tail) + sum(tail[:N % len(tail)]))


main()

Loading…
Cancel
Save