adventofcode2022/day22/sol.py

180 lines
4.8 KiB
Python

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())