浏览代码

mountain

master
Roderic Day 3 年前
父节点
当前提交
694f74cb3a
共有 1 个文件被更改,包括 77 次插入0 次删除
  1. +77
    -0
      y2021/p23.py

+ 77
- 0
y2021/p23.py 查看文件

@@ -0,0 +1,77 @@
from functools import lru_cache


@lru_cache(maxsize=None)
def find_min_dist(valid, a, b, DX=[1, -1, 1j, -1j]):
dist = 0
state = {a}
seen = state.copy()
while state:
dist += 1
state = {x + dx for x in state for dx in DX} & valid - seen
seen.update(state)
if b in state:
return dist


def evolve(old, pinned):
valid = frozenset({p for p, c in old if c == '.'})
for x, k in old:
if x not in pinned and k.isalpha():
xi = 'ABCD'.index(k) * 2 + 3
cost = 10 ** 'ABCD'.index(k)

# rule: if you're in the hall, you can only end up in your room
if x.imag == 1:
ys = {complex(xi, y) for y in slots}
# rule: if you're in a wrong spot, you can only end up in the hall
else:
ys = {complex(x, 1) for x in (1, 2, 4, 6, 8, 10, 11)}

for y in ys & valid:
# heuristic: assume only A can waste time with alcove
if y.real in {1, 2} and k != 'A':
continue

# rule: you only get one move
new_pinned = pinned
if y.imag > 1:
new_pinned |= {y}

if dist := find_min_dist(valid, x, y):
new = old - {(x, k), (y, '.')} | {(x, '.'), (y, k)}
options = {scores.get(new), scores[old] + cost * dist}
scores[new] = min(options - {None})
yield new, new_pinned


text = open(0).read()
expansion = '''
#D#C#B#A#
#D#B#A#C#
'''
expanded_text = text.replace('#\n ', '#' + expansion + ' ', 1)
for text in [text, expanded_text]:
slots = list(range(2, len(text.splitlines()) - 1))
init = frozenset(
(complex(x, y), ch)
for y, ln in enumerate(text.splitlines())
for x, ch in enumerate(ln)
)
goal = {
(complex(i * 2 + 3, y), ch)
for i, ch in enumerate('ABCD')
for y in slots
}
scores = {init: 0}
states = {(init, frozenset())}
wins = set()
seen = set()
i = 0
while states:
i += 1; print(i, len(states))
states = {new for old in states for new in evolve(*old)} - seen
seen |= states
if wins := {old[0] for old in states if goal < old[0]}:
print('end', scores[min(wins, key=scores.get)])
break

正在加载...
取消
保存