| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #!/usr/bin/env python3
- import sys
- from collections import defaultdict, deque
- from operator import add, mul, lt, eq
- from time import sleep
- def run(p, get_input, memsize=0):
- def decode_param(offset):
- return p[pc + offset], modes // (10 ** (offset - 1)) % 10
- def pload(offset):
- param, mode = decode_param(offset)
- return param if mode == 1 else p[param + relbase * mode // 2]
- def pstore(offset, value):
- param, mode = decode_param(offset)
- p[param + relbase * mode // 2] = value
- opmap = {1: add, 2: mul, 7: lt, 8: eq}
- p = p + [0] * memsize
- pc = relbase = 0
- while p[pc] != 99:
- modes, opcode = divmod(p[pc], 100)
- if opcode in (1, 2, 7, 8):
- pstore(3, opmap[opcode](pload(1), pload(2)))
- pc += 4
- elif opcode == 3:
- pstore(1, get_input())
- pc += 2
- elif opcode == 4:
- yield pload(1)
- pc += 2
- elif opcode == 5:
- pc = pload(2) if pload(1) else pc + 3
- elif opcode == 6:
- pc = pload(2) if not pload(1) else pc + 3
- elif opcode == 9:
- relbase += pload(1)
- pc += 2
- NORTH, SOUTH, EAST, WEST = range(1, 5)
- WALL, SPACE, OXYGEN, UNKOWN = range(4)
- DX = [0, 0, -1, 1]
- DY = [-1, 1, 0, 0]
- def draw(mapped, robot):
- if '-v' not in sys.argv:
- return
- def draw_pos(pos):
- return 'D' if pos == robot else '#.O '[mapped.get(pos, UNKOWN)]
- minx = min(x for x, y in mapped)
- maxx = max(x for x, y in mapped)
- miny = min(y for y, y in mapped)
- maxy = max(y for y, y in mapped)
- print('\033c', end='')
- for y in range(miny, maxy + 1):
- print(''.join(draw_pos((x, y)) for x in range(minx, maxx + 1)))
- sleep(.001)
- def map_area(program):
- reverse_dir = [SOUTH, NORTH, WEST, EAST]
- pos = 0, 0
- direction = NORTH
- control = run(program, lambda: direction, 0)
- mapped = {pos: SPACE}
- path = [(NORTH, pos)]
- oxygen_distance = None
- def pick_direction():
- x, y = pos
- for d in (NORTH, SOUTH, EAST, WEST):
- newpos = x + DX[d - 1], y + DY[d - 1]
- if newpos not in mapped:
- return False, (d, newpos)
- return True, path.pop()
- while len(path):
- backtrack, (direction, newpos) = pick_direction()
- status = next(control)
- mapped[newpos] = status
- if status != WALL:
- if not backtrack:
- path.append((reverse_dir[direction - 1], pos))
- pos = newpos
- if status == OXYGEN:
- oxygen_distance = len(path) - 1
- draw(mapped, pos)
- return oxygen_distance, mapped
- def spread_oxygen(mapped):
- frontier = set(pos for pos, status in mapped.items() if status == OXYGEN)
- minutes = -1
- while frontier:
- newfrontier = set()
- for x, y in frontier:
- mapped[(x, y)] = OXYGEN
- for d in range(4):
- nb = x + DX[d], y + DY[d]
- if mapped[nb] == SPACE:
- newfrontier.add(nb)
- minutes += 1
- frontier = newfrontier
- draw(mapped, None)
- return minutes
- program = list(map(int, sys.stdin.readline().split(',')))
- oxygen_distance, mapped = map_area(program)
- print(oxygen_distance)
- print(spread_oxygen(mapped))
|