Day 18: WIP
This commit is contained in:
parent
be6b265446
commit
c1540f2096
104
2019/day18.py
104
2019/day18.py
|
@ -1,13 +1,59 @@
|
||||||
|
import string
|
||||||
|
|
||||||
from grid import Grid
|
from grid import Grid
|
||||||
|
from vector import v2a
|
||||||
|
|
||||||
|
|
||||||
|
EX1 = [
|
||||||
|
"#########",
|
||||||
|
"#b.A.@.a#",
|
||||||
|
"#########",
|
||||||
|
]
|
||||||
|
# reqs:
|
||||||
|
# a: []
|
||||||
|
# b: [a]
|
||||||
|
EX2 = [
|
||||||
|
"########################",
|
||||||
|
"#f.D.E.e.C.b.A.@.a.B.c.#",
|
||||||
|
"######################.#",
|
||||||
|
"#d.....................#",
|
||||||
|
"########################",
|
||||||
|
]
|
||||||
|
# reqs:
|
||||||
|
# a: []
|
||||||
|
# b: [a]
|
||||||
|
# c: [b]
|
||||||
|
# d: [b]
|
||||||
|
# e: [a, c]
|
||||||
|
# f: [a, c, e, d]
|
||||||
|
#
|
||||||
|
# - get a
|
||||||
|
# - get b
|
||||||
|
# - get c or d?
|
||||||
|
# - get c
|
||||||
|
# - get d or e?
|
||||||
|
# - d
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with open("day18.txt", "rt") as input_file:
|
with open("day18.txt", "rt") as input_file:
|
||||||
lines = input_file.readlines()
|
lines = input_file.readlines()
|
||||||
|
|
||||||
lab = Lab(lines)
|
lab = Lab(lines=EX1)
|
||||||
lab.dumb_print()
|
lab.dumb_print()
|
||||||
|
|
||||||
|
lab.find_positions()
|
||||||
|
pos = lab.start
|
||||||
|
missing_keys = list(lab.key_pos.keys())
|
||||||
|
obtained_keys = set("a")
|
||||||
|
while missing_keys:
|
||||||
|
|
||||||
|
for key, bt in lab.get_all_backtracks(pos).items():
|
||||||
|
steps, reqs, founds = bt
|
||||||
|
if len(reqs - obtained_keys) == 0:
|
||||||
|
print(key, "is accessible")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
class Lab(Grid):
|
class Lab(Grid):
|
||||||
|
|
||||||
|
@ -15,6 +61,62 @@ class Lab(Grid):
|
||||||
TILE_WALL = "#"
|
TILE_WALL = "#"
|
||||||
TILE_START = "@"
|
TILE_START = "@"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs, value_factory=lambda: " ")
|
||||||
|
self.start = None
|
||||||
|
self.key_pos = {}
|
||||||
|
self.door_pos = {}
|
||||||
|
|
||||||
|
def find_positions(self):
|
||||||
|
for x, y, v in self.values_gen():
|
||||||
|
if v == Lab.TILE_START:
|
||||||
|
self.start = (x, y)
|
||||||
|
if v in string.ascii_lowercase:
|
||||||
|
self.key_pos[v] = (x, y)
|
||||||
|
if v in string.ascii_uppercase:
|
||||||
|
self.door_pos[v] = (x, y)
|
||||||
|
self.setv(self.start[0], self.start[1], Lab.TILE_PATH)
|
||||||
|
|
||||||
|
def get_all_backtracks(self, start):
|
||||||
|
return {
|
||||||
|
kname: self.backtrack(self.path(start, kpos), kpos, start)
|
||||||
|
for kname, kpos in self.key_pos.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
def path(self, s, e):
|
||||||
|
discovered = Grid(value_factory=bool)
|
||||||
|
discovered.setv(s[0], s[1], True)
|
||||||
|
parents = {}
|
||||||
|
q = [s]
|
||||||
|
while q:
|
||||||
|
pos = q.pop(0)
|
||||||
|
if pos == e:
|
||||||
|
return parents
|
||||||
|
nears = self.near_objects(pos)
|
||||||
|
for near_pos, near_tile in nears.items():
|
||||||
|
if near_tile == Lab.TILE_WALL:
|
||||||
|
continue
|
||||||
|
if discovered.getv(near_pos[0], near_pos[1]):
|
||||||
|
continue
|
||||||
|
discovered.setv(near_pos[0], near_pos[1], True)
|
||||||
|
parents[near_pos] = pos
|
||||||
|
q.append(near_pos)
|
||||||
|
return parents
|
||||||
|
|
||||||
|
def backtrack(self, parents, pos, end):
|
||||||
|
count = 0
|
||||||
|
requirements = set()
|
||||||
|
keys_found = set()
|
||||||
|
while pos != end:
|
||||||
|
pos = parents[pos]
|
||||||
|
count += 1
|
||||||
|
tile = self.getv(pos[0], pos[1])
|
||||||
|
if tile in string.ascii_uppercase:
|
||||||
|
requirements.add(tile.lower())
|
||||||
|
elif tile in string.ascii_lowercase:
|
||||||
|
keys_found.add(tile)
|
||||||
|
return count, requirements, keys_found
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
41
2019/grid.py
41
2019/grid.py
|
@ -5,25 +5,30 @@ from collections import defaultdict
|
||||||
|
|
||||||
class Grid:
|
class Grid:
|
||||||
|
|
||||||
def __init__(self, lines=None):
|
def __init__(self, value_factory=int, lines=None):
|
||||||
self.g = defaultdict(lambda: defaultdict(int))
|
self.g = defaultdict(lambda: defaultdict(value_factory))
|
||||||
if lines:
|
if lines:
|
||||||
self.load(lines)
|
self.load(lines)
|
||||||
|
|
||||||
def load(self, lines, f=lambda v: v):
|
|
||||||
for y, line in enumerate(lines):
|
|
||||||
for x, c in enumerate(line.rstrip()):
|
|
||||||
self.g[y][x] = f(c)
|
|
||||||
|
|
||||||
def getv(self, x, y):
|
def getv(self, x, y):
|
||||||
return self.g[y][x]
|
return self.g[y][x]
|
||||||
|
|
||||||
def setv(self, x, y, value):
|
def setv(self, x, y, value):
|
||||||
self.g[y][x] = value
|
self.g[y][x] = value
|
||||||
|
|
||||||
def near_items(self, p):
|
def load(self, lines, f=lambda v: v):
|
||||||
|
for y, line in enumerate(lines):
|
||||||
|
for x, c in enumerate(line.rstrip()):
|
||||||
|
self.g[y][x] = f(c)
|
||||||
|
|
||||||
|
def values_gen(self):
|
||||||
|
for y, row in self.g.items():
|
||||||
|
for x, v in row.items():
|
||||||
|
yield (x, y, v)
|
||||||
|
|
||||||
|
def near_objects(self, p):
|
||||||
"""Return a dict of neighbor positions to values (U, L, D, R)."""
|
"""Return a dict of neighbor positions to values (U, L, D, R)."""
|
||||||
return {pos: self.g[pos[1]][pos[0]] for pos in Grid.near(p)}
|
return {q: self.g[q[1]][q[0]] for q in Grid.near(p)}
|
||||||
|
|
||||||
def dumb_print(self, f=lambda v: v):
|
def dumb_print(self, f=lambda v: v):
|
||||||
for row in self.g.values():
|
for row in self.g.values():
|
||||||
|
@ -31,21 +36,11 @@ class Grid:
|
||||||
print(f(x), end="")
|
print(f(x), end="")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
def print_near(self, p):
|
def print_near(self, p, view_size=2):
|
||||||
|
for dy in range(-view_size, view_size + 1):
|
||||||
print("".join([
|
print("".join([
|
||||||
chr(self.g[p[1] - 1][p[0] - 1]),
|
self.g[p[1] + dy][p[0] + dx]
|
||||||
chr(self.g[p[1] - 1][p[0]]),
|
for dx in range(-view_size, view_size + 1)
|
||||||
chr(self.g[p[1] - 1][p[0] + 1]),
|
|
||||||
]))
|
|
||||||
print("".join([
|
|
||||||
chr(self.g[p[1] ][p[0] - 1]),
|
|
||||||
chr(self.g[p[1] ][p[0]]),
|
|
||||||
chr(self.g[p[1] ][p[0] + 1]),
|
|
||||||
]))
|
|
||||||
print("".join([
|
|
||||||
chr(self.g[p[1] + 1][p[0] - 1]),
|
|
||||||
chr(self.g[p[1] + 1][p[0]]),
|
|
||||||
chr(self.g[p[1] + 1][p[0] + 1]),
|
|
||||||
]))
|
]))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
Loading…
Reference in a new issue