Roderic Day vor 5 Jahren
Ursprung
Commit
d89b263db6
3 geänderte Dateien mit 32 neuen und 43 gelöschten Zeilen
  1. +13
    -15
      y2019/p18.py
  2. +9
    -14
      y2019/p20.py
  3. +10
    -14
      y2019/p24.py

+ 13
- 15
y2019/p18.py Datei anzeigen

@@ -10,7 +10,7 @@ def read_in(text):
grid = read_image(text)
elements = {v: k for k, v in grid.items()}
keys = {c for c in elements if c.isalpha() and c.islower()}
return dict(grid), elements, keys
return grid, elements, keys


def move(grid, pos):
@@ -23,25 +23,23 @@ def trim(states, metric):
groups = collections.defaultdict(list)
for state in states:
tips = frozenset(seq[-1] for seq in state)
bulk = frozenset(' '.join(state))
bulk = frozenset(''.join(state))
groups[bulk, tips].append(state)
return [min(groups[k], key=metric) for k in groups]


def precalc_moves(entrances, keys, elements, grid):
requirements = collections.defaultdict(dict)
reqs = collections.defaultdict(dict)
lengths = {}
for a, b in itertools.combinations(keys.union(entrances), 2):
try:
path = shortest_path(elements[a], elements[b], partial(move, grid))
*glyphs, = map(grid.get, path)
lengths[a, b] = lengths[b, a] = len(path) - 1
doors = {c for c in map(grid.get, path) if c.isupper()}
reqs[a][b] = reqs[b][a] = {d.lower() for d in doors}
except RuntimeError:
continue
lengths[a, b] = len(path) - 1
lengths[b, a] = len(path) - 1
requirements[a][b] = {c.lower() for c in glyphs if c.isupper()}
requirements[b][a] = {c.lower() for c in glyphs if c.isupper()}
return requirements, partial(calc_total, lengths)
return reqs, partial(calc_total, lengths)


def calc_total(lengths, state):
@@ -52,9 +50,9 @@ def mod_grid(text):
grid, elements, keys = read_in(text)
pos = elements['@']
grid[pos] = '#'
for char, ori in zip('*&^@', [1, -1, 1j, -1j]):
for i, ori in enumerate([1, -1, 1j, -1j]):
grid[pos + ori] = '#'
grid[pos + ori + ori * 1j] = char
grid[pos + ori * (1 + 1j)] = chr(ord('@') - i)
return render(grid)


@@ -63,13 +61,13 @@ def solve(text):
stacks = {k for k in elements if not k.isalnum()} - {'#', '.'}
requirements, metric = precalc_moves(stacks, keys, elements, grid)
states = [stacks]
for _ in range(len(keys)):
for _ in keys:
states = trim([
state - {seq} | {seq + b}
state ^ {seq, seq + new}
for state in states
for seq in state
for b, reqs in requirements[seq[-1]].items()
if b not in seq and reqs.issubset(''.join(state))
for new, reqs in requirements[seq[-1]].items()
if new not in seq and reqs.issubset(''.join(state))
], metric)
best = min(states, key=metric)
print(best)

+ 9
- 14
y2019/p20.py Datei anzeigen

@@ -5,8 +5,7 @@ from toolkit import read_image, shortest_path


def move(pos):
for ori in [1, -1, 1j, -1j]:
adj = pos + ori
for adj in (pos + ori for ori in [1, -1, 1j, -1j]):
if adj in grid:
yield adj
if adj in duals:
@@ -15,16 +14,13 @@ def move(pos):

def move_with_depth(state):
pos, level = state
for ori in [1, -1, 1j, -1j]:
adj = pos + ori
if adj in grid:
for adj in (pos + ori for ori in [1, -1, 1j, -1j]):
if adj in inner:
yield from move_with_depth((duals[adj], level + 1))
elif adj in outer and (level > 0) and (grid[adj] not in {'AA', 'ZZ'}):
yield from move_with_depth((duals[adj], level - 1))
elif adj in grid:
yield adj, level
if adj in duals:
name = grid[adj]
if adj in inner:
yield from move_with_depth((duals[adj], level + 1))
elif (level > 0) and (name not in {'AA', 'ZZ'}):
yield from move_with_depth((duals[adj], level - 1))


# base
@@ -34,10 +30,9 @@ for pos, val in grid.copy().items():
if val.isupper():
for im in [1, 1j]:
A, B, C = [pos - im, pos, pos + im]
seq = ''.join(grid.get(p, ' ') for p in [A, B, C])
if seq.endswith('.'):
if grid.get(C) == '.':
grid[B] = grid.pop(A) + grid.pop(B)
if seq.startswith('.'):
if grid.get(A) == '.':
grid[B] = grid.pop(B) + grid.pop(C)
elements = {v: k for k, v in grid.items()}


+ 10
- 14
y2019/p24.py Datei anzeigen

@@ -24,21 +24,17 @@ def recursive_adjace(level, pos, center=complex(2, 2)):


def evolve(bugs, adjacency, lim=None):
seen_states = set()
while lim is None or len(seen_states) < lim:
seen_states = {bugs}
while True:
affected = {nei for tile in bugs for nei in adjacency(*tile)} | bugs
infested = set()
dead = set()

for tile in affected:
count = sum(nei in bugs for nei in adjacency(*tile))
if tile in bugs and count != 1:
dead.add(tile)
elif tile not in bugs and count in [1, 2]:
infested.add(tile)

bugs = bugs - dead | infested
if bugs in seen_states:
will_change = {
tile for tile in affected
for count in [sum(nei in bugs for nei in adjacency(*tile))]
if tile in bugs and count != 1
or tile not in bugs and count in [1, 2]
}
bugs = bugs ^ will_change
if bugs in seen_states or len(seen_states) == lim:
break
seen_states.add(bugs)
return bugs

Laden…
Abbrechen
Speichern