Solution to problem 11 in Python

This commit is contained in:
David Doblas Jiménez 2022-07-03 18:59:35 +02:00
parent 5e9a465064
commit 3c18e6d270

View File

@ -168,91 +168,115 @@
import re import re
from collections import defaultdict, deque, namedtuple from collections import defaultdict, deque, namedtuple
part1 = [1, 1, 2, 3, 2, 3, 2, 3, 2, 3] # part2 = [1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1]
part2 = [1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1]
floor_re = re.compile(r"The (\w+) floor contains")
gen_re = re.compile(r"a (\w+) generator")
chip_re = re.compile(r"a (\w+)-compatible microchip")
def parse_entry(): def parse_entry():
# floor_re = re.compile(r"The (\w+) floor contains")
gen_re = re.compile(r"a (\w+) generator")
chip_re = re.compile(r"a (\w+-compatible) microchip")
with open("files/P11.txt", "r") as f: with open("files/P11.txt", "r") as f:
my_list = [] entry = defaultdict(list)
for idx, my_input in enumerate(f.readlines()): for idx, my_input in enumerate(f.readlines(), start=1):
gens = gen_re.findall(my_input) generators = gen_re.findall(my_input)
chips = chip_re.findall(my_input) if generators:
my_list.append((idx + 1, gens, chips)) [entry[idx].append((idx, g)) for g in generators]
microchips = chip_re.findall(my_input)
if microchips:
[entry[idx].append((idx, m)) for m in microchips]
print(my_list) return entry
# # f - floors, e - elevator, s - steps def find_level_of_microchip(item, dic):
# State = namedtuple('State', ['f', 'e', 's']) for key in dic.keys():
for val in dic[key]:
# def valid(state): if f"{item}-compatible" in val:
# if not 1 <= state.e <= 4: return val[0]
# return False
# for idx, val in enumerate(state.f[1::2]):
# idx = idx * 2 + 1
# if val != state.f[idx - 1] and any(val == i for i in state.f[0::2]):
# return False
# return True
# def solved(state):
# return all(i == 4 for i in state.f)
# def generalize(state): def get_floor_config(dic):
# generators = [sum(1 for v in state.f[::2] if v == floor) for floor in range(1, 5)] floor_config = []
# microchips = [sum(1 for v in state.f[1::2] if v == floor) for floor in range(1, 5)] for lvl in dic.keys():
for items in dic[lvl]:
if "-compatible" not in items[1]:
floor_config.append(items[0])
lvl_comp = find_level_of_microchip(items[1], dic)
floor_config.append(lvl_comp)
# return ''.join(map(str, generators + microchips)) + str(state.e) return floor_config
# def bfs(floor_config): # f - floors, e - elevator, s - steps
# bfs_q = deque() State = namedtuple("State", ["f", "e", "s"])
# bfs_q.append(State(floor_config, 1, 0))
# seen = set()
# while bfs_q:
# state = bfs_q.popleft()
# if solved(state):
# print(f"We need {state.s} steps")
# return
# if generalize(state) in seen or not valid(state):
# continue
# seen.add(generalize(state))
# for idx in range(len(state.f)): def valid(state):
# i = state.f[idx] if not 1 <= state.e <= 4:
# if i != state.e: # item can't be moved bc not in elevator return False
# continue
# state.f[idx] -= 1
# bfs_q.append(State(list(state.f), state.e - 1, state.s + 1))
# state.f[idx] += 2
# bfs_q.append(State(list(state.f), state.e + 1, state.s + 1))
# state.f[idx] -= 1
# for jdx in range(idx + 1, len(state.f)): for idx, val in enumerate(state.f[1::2]):
# if state.f[jdx] != state.e: idx = idx * 2 + 1
# continue if val != state.f[idx - 1] and any(val == i for i in state.f[0::2]):
# state.f[jdx] -= 1 return False
# state.f[idx] -= 1 return True
# bfs_q.append(State(list(state.f), state.e - 1,
# state.s + 1))
# state.f[jdx] += 2
# state.f[idx] += 2
# bfs_q.append(State(list(state.f), state.e + 1,
# state.s + 1))
# state.f[jdx] -= 1
# state.f[idx] -= 1
# def part_1(): def solved(state):
# p1 = parse_entry() return all(i == 4 for i in state.f)
# bfs(p1)
def generalize(state):
generators = [
sum(1 for v in state.f[::2] if v == floor) for floor in range(1, 5)
]
microchips = [
sum(1 for v in state.f[1::2] if v == floor) for floor in range(1, 5)
]
return "".join(map(str, generators + microchips)) + str(state.e)
def bfs(floor_config):
bfs_q = deque()
bfs_q.append(State(floor_config, 1, 0))
seen = set()
while bfs_q:
state = bfs_q.popleft()
if solved(state):
# print(f"We need {state.s} steps")
return state.s
if generalize(state) in seen or not valid(state):
continue
seen.add(generalize(state))
for idx in range(len(state.f)):
i = state.f[idx]
if i != state.e: # item can't be moved bc not in elevator
continue
state.f[idx] -= 1
bfs_q.append(State(list(state.f), state.e - 1, state.s + 1))
state.f[idx] += 2
bfs_q.append(State(list(state.f), state.e + 1, state.s + 1))
state.f[idx] -= 1
for jdx in range(idx + 1, len(state.f)):
if state.f[jdx] != state.e:
continue
state.f[jdx] -= 1
state.f[idx] -= 1
bfs_q.append(State(list(state.f), state.e - 1, state.s + 1))
state.f[jdx] += 2
state.f[idx] += 2
bfs_q.append(State(list(state.f), state.e + 1, state.s + 1))
state.f[jdx] -= 1
state.f[idx] -= 1
def part_1():
p1 = get_floor_config(parse_entry())
print(f"We need {bfs(p1)} steps for part 1")
# # --- Part Two --- # # --- Part Two ---
@ -274,7 +298,13 @@ def parse_entry():
# # including these four new ones, to the fourth floor? # # including these four new ones, to the fourth floor?
# if __name__ == '__main__': def part_2():
# parse_entry() p2 = get_floor_config(parse_entry())
# # bfs(part1) # extra parts are on floor 1
# # bfs(part2) p2.extend([1, 1, 1, 1])
print(f"We need {bfs(p2)} steps for part 2")
if __name__ == "__main__":
part_1()
part_2()