diff --git a/src/Year_2016/P11.py b/src/Year_2016/P11.py index 56f9fc8..4f61c6b 100644 --- a/src/Year_2016/P11.py +++ b/src/Year_2016/P11.py @@ -168,91 +168,115 @@ import re 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] - -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") +# part2 = [1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1] 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: - my_list = [] - for idx, my_input in enumerate(f.readlines()): - gens = gen_re.findall(my_input) - chips = chip_re.findall(my_input) - my_list.append((idx + 1, gens, chips)) + entry = defaultdict(list) + for idx, my_input in enumerate(f.readlines(), start=1): + generators = gen_re.findall(my_input) + if generators: + [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 -# State = namedtuple('State', ['f', 'e', 's']) - -# def valid(state): -# if not 1 <= state.e <= 4: -# 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 find_level_of_microchip(item, dic): + for key in dic.keys(): + for val in dic[key]: + if f"{item}-compatible" in val: + return val[0] -# 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)] +def get_floor_config(dic): + floor_config = [] + 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): -# 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 -# if generalize(state) in seen or not valid(state): -# continue -# seen.add(generalize(state)) +# f - floors, e - elevator, s - steps +State = namedtuple("State", ["f", "e", "s"]) -# 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 +def valid(state): + if not 1 <= state.e <= 4: + return False -# 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 + 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 part_1(): -# p1 = parse_entry() -# bfs(p1) +def solved(state): + return all(i == 4 for i in state.f) + + +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 --- @@ -274,7 +298,13 @@ def parse_entry(): # # including these four new ones, to the fourth floor? -# if __name__ == '__main__': -# parse_entry() -# # bfs(part1) -# # bfs(part2) +def part_2(): + p2 = get_floor_config(parse_entry()) + # extra parts are on floor 1 + p2.extend([1, 1, 1, 1]) + print(f"We need {bfs(p2)} steps for part 2") + + +if __name__ == "__main__": + part_1() + part_2()