map = [] moves = "" with open("input") as f: for line in f: if line == "\n": break map.append(line.rstrip("\n")) moves = f.readline().strip() # 0 - E # 1 - S # 2 - W # 3 - N F = { 0: (+1, 0), 1: (0, +1), 2: (-1, 0), 3: (0, -1), } #assert len(set(len(l) for l in map)) == 1 class Map: def __init__(self, map, region_size=50): self.map = map self.row = 0 self.col = 0 self.face = 0 self.region_size = region_size while self.map[self.row][self.col] == ' ': self.col += 1 # 9' # 1 2 # \ 4 \ # 6 7 # 9 \ self.region_map = { # R D L U 1: [(2,0), (4, 0), (6,2), (9, 1)], 4: [(2,-1), (7,0), (6,-1), (1, 0)], 7: [(2,2), (9,+1), (6,0), (4,0)], 6: [(7,0), (9,0), (1,2), (4,+1)], 9: [(7,-1), (2,0), (1,-1), (6,0)], 2: [(7,2), (4,+1), (1, 0), (9,0)], } ok = True for f in range(4): for r in self.region_map: orig = (r,f) s = repr(orig) for _ in range(4): r, h = self.region_map[r][f] f = (f+h)%4 s += "-> {} {}".format(r, f) if (r,f) != orig: print("!!", s) ok = False assert ok, "topology failure" def set_simple_region_map(self): R = self.region_size def exists(x,y): return 0 <= y < len(self.map) and 0 <= x < len(self.map[y]) and self.map[y][x] != ' ' for y in range(0,len(self.map), R): for x in range(0, len(self.map[y]), R): if exists(x,y): warps = [] for f in range(4): dx, dy = F[f] dx, dy = dx*R, dy*R x1, y1 = x+dx, y+dy if exists(x1, y1): dest = self.region(x1,y1) else: if dy: y1 %= len(self.map) while not exists(x1, y1): y1 = (y1+dy)%len(self.map) if dx: x1 %= len(self.map[y1]) while not exists(x1, y1): x1 = (x1+dx)%len(self.map[y1]) dest = self.region(x1, y1) warps.append((dest, 0)) r = self.region(x,y) self.region_map[r] = warps print(self.region_map) def nextTile(self, x, y, face): R = self.region_size dx, dy = F[face] if 0 <= (x%R + dx) < R and 0 <= (y%R + dy) < R: x, y = x+dx, y+dy else: r = self.region(x,y) u = (x+dx) % R v = (y+dy) % R new_r, rotate = self.region_map[r][face] if rotate == 0: pass elif rotate == -1: u, v = v, R-u-1 elif rotate == 1: u, v = R-v-1, u elif rotate == 2: u, v = R-u-1, R-v-1 x, y = self.to_abs(u, v, new_r) face = (face + rotate) % 4 c = self.map[y][x] assert c != ' ' return x, y, face, c def to_abs(self, u, v, r): """returns the absolute coords of the local point (u,v) in region r""" R = self.region_size u %= R v %= R rx = r % 3 ry = r // 3 return (rx*R + u), (ry*R + v) def region(self, x, y): R = self.region_size return y//R * 3 + x//R def turnLeft(self): self.face = (self.face - 1) % 4 def turnRight(self): self.face = (self.face + 1) % 4 def walk(self, n, noclip=True): x, y, face = self.col, self.row, self.face while n > 0: x,y,face,c = self.nextTile(x, y, face) if c == '#' and noclip: break n -= 1 self.row = y self.col = x self.face = face #print(self.pos()) def pos(self): return self.row+1, self.col+1 def score(self): r, c = self.pos() return r*1000 + c*4 + self.face #print(moves) m = Map(map) #m.set_simple_region_map() i = 0 while i < len(moves): if moves[i].isdigit(): j = i+1 while j < len(moves) and moves[j].isdigit(): j += 1 n = int(moves[i:j]) m.walk(n) i = j elif moves[i] == 'L': m.turnLeft() i += 1 elif moves[i] == 'R': m.turnRight() i += 1 else: print("invalid move", moves[i], "at", i) i += 1 print(m.row, m.col) print(m.score())