90 lines
2.4 KiB
Python
90 lines
2.4 KiB
Python
import sys
|
|
from itertools import combinations
|
|
from lib import *
|
|
|
|
TOP_FLOOR = 3
|
|
part_1 = False
|
|
if part_1:
|
|
# g0, c0, g1, c1, ... elevator
|
|
state = [0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0]
|
|
else:
|
|
state = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0]
|
|
|
|
|
|
def is_state_valid(state):
|
|
for floor in range(0, TOP_FLOOR + 1):
|
|
gens_on_floor = [i // 2 for i in range(0, len(state) - 1, 2) if state[i] == floor]
|
|
chips_on_floor = [i // 2 for i in range(1, len(state) - 1, 2) if state[i] == floor]
|
|
if len(gens_on_floor) > 0:
|
|
for c in chips_on_floor:
|
|
if not c in gens_on_floor:
|
|
return False
|
|
return True
|
|
|
|
assert is_state_valid([0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0]) == True
|
|
assert is_state_valid([0, 0, 1, 0, 1, 2, 1, 2, 1, 2, 0]) == False
|
|
|
|
|
|
def is_end_state(state):
|
|
return all([o == TOP_FLOOR for o in state])
|
|
|
|
assert is_end_state([0, 0, 1, 0, 1, 2, 1, 2, 1, 2, 0]) == False
|
|
assert is_end_state([3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]) == True
|
|
|
|
|
|
def next_states(state):
|
|
floor = state[-1]
|
|
objects_on_floor = [i for i in range(len(state) - 1) if state[i] == floor]
|
|
|
|
nstates = []
|
|
for o in objects_on_floor:
|
|
if floor > 0:
|
|
nstate = list(state)
|
|
nstate[o] -= 1
|
|
nstate[-1] -= 1
|
|
nstates.append(nstate)
|
|
if floor < TOP_FLOOR:
|
|
nstate = list(state)
|
|
nstate[o] += 1
|
|
nstate[-1] += 1
|
|
nstates.append(nstate)
|
|
|
|
for os in combinations(objects_on_floor, 2):
|
|
if floor > 0:
|
|
nstate = list(state)
|
|
for o in os:
|
|
nstate[o] -= 1
|
|
nstate[-1] -= 1
|
|
nstates.append(nstate)
|
|
if floor < TOP_FLOOR:
|
|
nstate = list(state)
|
|
for o in os:
|
|
nstate[o] += 1
|
|
nstate[-1] += 1
|
|
nstates.append(nstate)
|
|
return nstates
|
|
|
|
|
|
states = [state]
|
|
for step in range(1000):
|
|
nstates = []
|
|
seen = set()
|
|
for state in states:
|
|
|
|
statet = tuple(state)
|
|
if statet in seen:
|
|
continue
|
|
seen.add(statet)
|
|
|
|
for nstate in next_states(state):
|
|
if not is_state_valid(nstate):
|
|
continue
|
|
if is_end_state(nstate):
|
|
print(step + 1)
|
|
sys.exit(0)
|
|
nstates.append(nstate)
|
|
|
|
# Keep search space manageable with pretty bad pruning.
|
|
nstates.sort(reverse=True)
|
|
states = nstates[:20000]
|