| import functools | |||||
| import itertools | |||||
| import collections | import collections | ||||
| import re | |||||
| text = open(0).read() | 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)) | 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)) |
| 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 |
| 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() |