Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import itertools
- import random
- import time
- X = [l for l in open('input.txt', 'r') if l.strip()]
- _map = {}
- for i, l in enumerate(X):
- instrs = []
- if l[0] in ' .#':
- for j, c in enumerate(l):
- if c in '#.':
- _map[complex(j, i)] = c
- else:
- l = l.strip()
- b = ''
- for c in l + ' ':
- if c.isdigit():
- b = b + c
- else:
- if b:
- instrs.append(int(b))
- b = ''
- if c in 'LR':
- instrs.append(c)
- W = int((len(_map) / 6) ** 0.5)
- facing_scores = {1 + 0j: 0, 0 - 1j: 1, -1 + 0j: 2, 0 + 1j: 3}
- base = [None] * 6
- labels = {}
- label = 0
- by_label = [[] for _ in range(6)]
- while True:
- try:
- base[label] = p0 = min([p for p in _map if p not in labels], key=lambda p: (p.imag, p.real))
- except:
- break
- for di in range(W):
- for dj in range(W):
- p = p0 + complex(di, dj)
- labels[p] = label
- by_label[label].append(p)
- label += 1
- pos_3d = {}
- def assign_faces(label, assigned_faces):
- if label == 6:
- return True
- for f in itertools.product(range(3), range(2)):
- if f in assigned_faces:
- continue
- assigned_faces.add(f)
- for r in itertools.product(range(2), repeat=3):
- added = []
- good = True
- for p in by_label[label]:
- z = p - base[label]
- z = (int(z.imag), int(z.real))
- if r[0]:
- z = z[::-1]
- if r[1]:
- z = (z[0], (W - 1) - z[1])
- if r[2]:
- z = ((W - 1) - z[0], z[1])
- z = z[:f[0]] + ((-1, W)[f[1]],) + z[f[0]:]
- pos_3d[p] = z
- added.append(p)
- for di, dj in itertools.product(range(-1, 2), repeat=2):
- if (di == 0) == (dj == 0):
- continue
- q = p + complex(di, dj)
- if q in pos_3d:
- if int(sum(abs(a - b) for a, b in zip(pos_3d[p], pos_3d[q]))) != 1 + (labels[p] != labels[q]):
- good = False
- break
- else:
- pass
- if not good:
- break
- if good and assign_faces(label + 1, assigned_faces):
- return True
- for p in added:
- pos_3d.pop(p)
- assigned_faces.remove(f)
- return False
- assigned_faces = set()
- assert assign_faces(0, assigned_faces)
- by_pos_3d = {}
- for p, z in pos_3d.items():
- by_pos_3d[z] = p
- for part2 in range(2):
- j = base[0].real
- facing = 1 + 0j
- position = complex(j, 0)
- for inst in instrs:
- if type(inst) == int:
- for _ in range(inst):
- p1 = position + facing
- f1 = None
- if p1 not in _map:
- if part2:
- z1 = pos_3d[position]
- z0 = pos_3d[position - facing]
- z2 = tuple(b + (b - a) for a, b in zip(z0, z1)) # step forwards
- z3 = tuple(b + {-1: 1, W: -1}.get(a, 0) for a, b in zip(z1, z2)) #project back onto the cube
- z4 = tuple(b + (b - a) for a, b in zip(z2, z3)) # move one step further along the new face
- p1 = by_pos_3d[z3]
- f1 = by_pos_3d[z4] - p1 # get the new facing direction
- else:
- p1 = position
- while p1 - facing in _map:
- p1 -= facing
- if _map[p1] == '#':
- break
- position = p1
- if f1 is not None:
- facing = f1
- else:
- facing *= {'R': 1j, 'L': -1j}[inst]
- position += 1 + 1j
- print(int(1000 * position.imag + 4 * position.real + facing_scores[facing]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement