123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- lines = [line.split() for line in open("17.input")]
- jets = lines[0][0]
- blocks = [
- [(0, 0), (1, 0), (2, 0), (3, 0)],
- [(1, 0), (0, 1), (1, 1), (2, 1), (1, 2)],
- [(2, 0), (2, 1), (0, 2), (1, 2), (2, 2)],
- [(0, 0), (0, 1), (0, 2), (0, 3)],
- [(0, 0), (0, 1), (1, 0), (1, 1)],
- ]
- def show(occupied):
- stack_height = min([pos[1] for pos in occupied] + [0])
- for y in range(stack_height, 0):
- print("|", end='')
- for x in range(7):
- if (x, y) in occupied:
- print("#", end='')
- else:
- print(".", end='')
- print("|")
- print("-" * 9)
- def add(a, b):
- return (a[0] + b[0], a[1] + b[1])
- def run(target_blocks):
- occupied = set([(x, 0) for x in range(9)])
- jet_idx = 0
- combos = set()
- target = None
- found = []
- block_count = 0
- time_skip = False
- while block_count < target_blocks:
- block_idx = block_count % len(blocks)
- stack_height = min([pos[1] for pos in occupied] + [0])
- if not found:
- if (jet_idx, block_idx) in combos:
- # Set our target for time skip
- target = (jet_idx, block_idx)
- found.append((block_count, stack_height))
- print("Found repetition after", block_count, "blocks")
- else:
- combos.add((jet_idx, block_idx))
- elif not time_skip:
- if (jet_idx, block_idx) == target:
- print("Found again after", block_count)
- found.append((block_count, stack_height))
- if len(found) == 2:
- chunk_blocks = found[-1][0] - found[-2][0]
- chunk_height = -(found[-1][1] - found[-2][1])
- extra_chunks = (target_blocks - block_count) // chunk_blocks
- extra_blocks = extra_chunks * chunk_blocks
- block_count += extra_blocks
- extra_height = extra_chunks * chunk_height
- print(f"Performing time-skip (+{extra_blocks} blocks, +{extra_height} height).")
- occupied = {add(pos, (0, -extra_height)) for pos in occupied}
- time_skip = True
- continue
- block = blocks[block_idx]
- b_height = max(pos[1] for pos in block)
- start_pos = (2, stack_height - b_height - 4)
- block = [add(pos, start_pos) for pos in block]
- #show(occupied.union(block))
- while True:
- # Jetting
- max_x = max(pos[0] for pos in block)
- min_x = min(pos[0] for pos in block)
- jet = jets[jet_idx]
- jet_idx += 1
- jet_idx = jet_idx % len(jets)
- if min_x > 0 and jet == '<':
- next_block = {add(pos, (-1, 0)) for pos in block}
- elif max_x < 6 and jet == '>':
- next_block = {add(pos, (1, 0)) for pos in block}
- if not next_block.intersection(occupied):
- block = next_block
- # Falling
- next_block = {add(pos, (0, 1)) for pos in block}
- if next_block.intersection(occupied):
- occupied = occupied.union(block)
- break
- else:
- block = next_block
- block_count += 1
- stack_height = min([pos[1] for pos in occupied] + [0])
- return -stack_height
- print("Part 1:", run(2022))
- print("Part 2:", run(1000000000000))
|