···11+import re
22+import fileinput
33+from itertools import combinations
44+55+66+def complete(state):
77+ return all(f == 3 for f in state)
88+99+1010+def valid(state):
1111+ gens = set(state[::2])
1212+ for i, floor in enumerate(state):
1313+ # Element is a chip if it has an odd index
1414+ if i % 2 == 1:
1515+ # Its matching generator is on the same floor, so it's fine
1616+ if state[i-1] == floor:
1717+ continue
1818+1919+ # There is another generator on the floor
2020+ if floor in gens:
2121+ return False
2222+2323+ return True
2424+2525+2626+2727+def solve(state, start_floor=0):
2828+ if start_floor == 3 and complete(state):
2929+ return 0
3030+3131+ horizon = [(start_floor, state)]
3232+ steps = 0
3333+ seen = set()
3434+3535+ while horizon:
3636+ new_horizon = []
3737+3838+ for floor, state in horizon:
3939+ can_move = [i for i, f in enumerate(state) if f == floor]
4040+ moves = []
4141+4242+ if floor < 3:
4343+ moves.extend([(2, floor + 1), (1, floor + 1)])
4444+4545+ if floor > 0:
4646+ moves.extend([(1, floor - 1), (2, floor - 1)])
4747+4848+ moved_two_up = False
4949+ moved_one_down = False
5050+5151+ for n, new_floor in moves:
5252+ # Don't move one item up if you can move two,
5353+ # and don't move two items down if can move one
5454+ if n == 1 and new_floor > floor and moved_two_up:
5555+ continue
5656+ elif n == 2 and new_floor < floor and moved_one_down:
5757+ continue
5858+5959+ for move in combinations(can_move, n):
6060+ next_state = tuple(new_floor if i in move else f for i, f in enumerate(state))
6161+6262+ if complete(next_state):
6363+ return steps + 1
6464+6565+ if valid(next_state) and (new_floor, next_state) not in seen:
6666+ pair = (new_floor, next_state)
6767+ new_horizon.append(pair)
6868+ seen.add(pair)
6969+7070+ if n == 2 and new_floor > floor:
7171+ moved_two_up = True
7272+ if n == 1 and new_floor < floor:
7373+ moved_one_down = True
7474+7575+ horizon = new_horizon
7676+ steps += 1
7777+7878+7979+generators = {}
8080+microchips = {}
8181+8282+for i, line in enumerate(fileinput.input()):
8383+ for gen in re.findall(r'(\w+) generator', line):
8484+ generators[gen] = i
8585+ for chip in re.findall(r'(\w+)-compatible microchip', line):
8686+ microchips[chip] = i
8787+8888+8989+STATE = []
9090+9191+for key in generators:
9292+ STATE.append(generators[key])
9393+ STATE.append(microchips[key])
9494+9595+STATE = tuple(STATE)
9696+9797+print "Minimum number of steps:", solve(STATE)
9898+9999+STATE = tuple(list(STATE) + [0, 0, 0, 0])
100100+print "With four new objects:", solve(STATE)