From e4e916d7bba9ef8c6c96d76cd1a17b54ad877709 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Fri, 16 Dec 2022 09:36:08 +0100 Subject: [PATCH] day16; p2 takes ~18min; have fun! :) --- day16.py | 152 ++++++++++++++++++++++++++++++++++++++++++++ inputs/input16 | 60 +++++++++++++++++ inputs/input16_test | 10 +++ 3 files changed, 222 insertions(+) create mode 100644 day16.py create mode 100644 inputs/input16 create mode 100644 inputs/input16_test diff --git a/day16.py b/day16.py new file mode 100644 index 0000000..6348a0e --- /dev/null +++ b/day16.py @@ -0,0 +1,152 @@ +from collections import deque +from itertools import product +from tools.aoc import AOCDay +from typing import Any +from tqdm import tqdm + + +class Valve: + def __init__(self, name: str, flowrate: int) -> None: + self.name = name + self.flowrate = flowrate + self.tunnels = [] + + +def get_openable_valve_tunnels(valve: Valve, open_valves: set, time_remaining: int) -> set: + tunnels = set() + queue = deque() + visited = set() + queue.append((0, valve)) + while queue: + d, v = queue.popleft() + if v.name in visited: + continue + visited.add(v.name) + if v.name not in open_valves and v.flowrate > 0 and d + 2 <= time_remaining: + tunnels.add((d, v)) + for x in v.tunnels: + queue.append((d + 1, x)) + + return tunnels + + +def get_max_flow(valve: Valve, open_valves: set, time_remaining: int = 30) -> int: + max_flow = 0 + + ov = get_openable_valve_tunnels(valve, open_valves, time_remaining) + if time_remaining <= 0 or not ov: + return 0 + + for d, v in ov: + this_open_valves = open_valves.copy() + if d + 2 > time_remaining: + continue + this_open_valves.add(v.name) + this_open_flow = v.flowrate * (time_remaining - d - 1) + this_flow = get_max_flow(v, this_open_valves, time_remaining - d - 1) + if this_flow + this_open_flow > max_flow: + max_flow = this_flow + this_open_flow + + return max_flow + + +def get_max_flow_double(valve1: Valve, valve2: Valve, open_valves: set, DP: dict, time_remaining_1: int = 26, time_remaining_2: int = 26, depth: int = 0) -> int: + dp_key = valve1.name + valve2.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(list(sorted(open_valves))) + dp_key2 = valve2.name + valve1.name + "%02d" % time_remaining_1 + "%02d" % time_remaining_2 + "".join(list(sorted(open_valves))) + if dp_key in DP: + return DP[dp_key] + + if time_remaining_1 <= 0 and time_remaining_2 <= 0: + return 0 + + ov1 = get_openable_valve_tunnels(valve1, open_valves, time_remaining_1) + ov2 = get_openable_valve_tunnels(valve2, open_valves, time_remaining_2) + + if not ov1 and not ov2: + return 0 + + if not ov1: + ov1 = {(99, valve1)} + + if not ov2: + ov2 = {(99, valve2)} + + permut = product(ov1, ov2) + + if depth == 0: + pbar = tqdm(total=210) + + max_flow = 0 + for v1, v2 in permut: + if v1[1].name == v2[1].name: + continue + if depth == 0: + pbar.update(1) + this_open_values = open_valves.copy() + d1, tv1 = v1 + d2, tv2 = v2 + this_open_flow = 0 + if d1 + 2 <= time_remaining_1: + this_open_values.add(tv1.name) + this_open_flow += tv1.flowrate * (time_remaining_1 - d1 - 1) + else: + tv1 = valve1 + if d2 + 2 <= time_remaining_2: + this_open_values.add(tv2.name) + this_open_flow += tv2.flowrate * (time_remaining_2 - d2 - 1) + else: + tv2 = valve2 + + this_flow_rate = get_max_flow_double(tv1, tv2, this_open_values, DP, time_remaining_1 - d1 - 1, time_remaining_2 - d2 - 1, depth + 1) + if this_flow_rate + this_open_flow > max_flow: + max_flow = this_flow_rate + this_open_flow + + if depth == 0: + pbar.close() + DP[dp_key] = max_flow + DP[dp_key2] = max_flow + return max_flow + + +class Day(AOCDay): + inputs = [ + [ + (1651, "input16_test"), + (1850, "input16"), + ], + [ + (1707, "input16_test"), + (2306, "input16"), + ] + ] + + def get_valve_graph(self) -> Valve: + valves = {} + for line in self.getInput(): + p = line.split(" ") + valve_name = p[1] + flowrate = int(p[4][5:-1]) + tunnels = "".join(p[9:]).split(",") + valves[valve_name] = Valve(valve_name, flowrate) + valves[valve_name].tunnels = tunnels + + for valve in valves.values(): + valve.tunnels = [valves[x] for x in valve.tunnels] + for valve in valves.values(): + for v in valve.tunnels: + if valve not in v.tunnels: + v.tunnels.append(valve) + + return valves["AA"] + + def part1(self) -> Any: + return get_max_flow(self.get_valve_graph(), set()) + + def part2(self) -> Any: + root = self.get_valve_graph() + return get_max_flow_double(root, root, set(), {}) + + +if __name__ == '__main__': + day = Day(2022, 16) + day.run(verbose=True) diff --git a/inputs/input16 b/inputs/input16 new file mode 100644 index 0000000..9c44169 --- /dev/null +++ b/inputs/input16 @@ -0,0 +1,60 @@ +Valve DR has flow rate=22; tunnels lead to valves DC, YA +Valve IO has flow rate=14; tunnels lead to valves GE, CK, HY, XB +Valve XY has flow rate=0; tunnels lead to valves IP, AR +Valve UQ has flow rate=0; tunnels lead to valves XU, PD +Valve FO has flow rate=0; tunnels lead to valves DL, NC +Valve PU has flow rate=0; tunnels lead to valves ZJ, AN +Valve MK has flow rate=0; tunnels lead to valves ZS, SB +Valve HN has flow rate=0; tunnels lead to valves AA, DV +Valve XF has flow rate=0; tunnels lead to valves XB, AA +Valve OD has flow rate=13; tunnels lead to valves ZS, AF, SY, QQ, AR +Valve GE has flow rate=0; tunnels lead to valves KR, IO +Valve UF has flow rate=18; tunnels lead to valves QQ, AN, YE, GY +Valve WK has flow rate=19; tunnel leads to valve PQ +Valve PQ has flow rate=0; tunnels lead to valves WK, CW +Valve XU has flow rate=0; tunnels lead to valves DV, UQ +Valve SH has flow rate=0; tunnels lead to valves IP, AA +Valve SY has flow rate=0; tunnels lead to valves ZJ, OD +Valve OU has flow rate=0; tunnels lead to valves CK, DL +Valve IP has flow rate=8; tunnels lead to valves CY, ML, YI, XY, SH +Valve XZ has flow rate=0; tunnels lead to valves AM, PD +Valve ZU has flow rate=0; tunnels lead to valves CW, SB +Valve DC has flow rate=0; tunnels lead to valves CF, DR +Valve QY has flow rate=0; tunnels lead to valves CW, MQ +Valve XB has flow rate=0; tunnels lead to valves IO, XF +Valve AF has flow rate=0; tunnels lead to valves PD, OD +Valve GY has flow rate=0; tunnels lead to valves UF, ZC +Valve ZC has flow rate=0; tunnels lead to valves GY, CW +Valve ZJ has flow rate=25; tunnels lead to valves SY, PU +Valve NC has flow rate=6; tunnels lead to valves HY, ML, NJ, AT, FO +Valve DS has flow rate=0; tunnels lead to valves AT, DV +Valve DV has flow rate=7; tunnels lead to valves FD, KR, HN, DS, XU +Valve HY has flow rate=0; tunnels lead to valves NC, IO +Valve WF has flow rate=0; tunnels lead to valves NJ, AA +Valve CK has flow rate=0; tunnels lead to valves IO, OU +Valve YE has flow rate=0; tunnels lead to valves CY, UF +Valve LA has flow rate=0; tunnels lead to valves DL, ZM +Valve QQ has flow rate=0; tunnels lead to valves OD, UF +Valve AM has flow rate=0; tunnels lead to valves XZ, SB +Valve AN has flow rate=0; tunnels lead to valves UF, PU +Valve CL has flow rate=16; tunnels lead to valves YA, LD +Valve CF has flow rate=12; tunnel leads to valve DC +Valve FD has flow rate=0; tunnels lead to valves DV, DL +Valve QU has flow rate=0; tunnels lead to valves LD, PD +Valve AT has flow rate=0; tunnels lead to valves DS, NC +Valve SB has flow rate=24; tunnels lead to valves MK, AM, ZU +Valve YI has flow rate=0; tunnels lead to valves DL, IP +Valve ZM has flow rate=0; tunnels lead to valves AA, LA +Valve LD has flow rate=0; tunnels lead to valves CL, QU +Valve AR has flow rate=0; tunnels lead to valves OD, XY +Valve DL has flow rate=5; tunnels lead to valves FO, LA, YI, OU, FD +Valve MQ has flow rate=0; tunnels lead to valves QY, PD +Valve PD has flow rate=9; tunnels lead to valves MQ, QU, XZ, AF, UQ +Valve KR has flow rate=0; tunnels lead to valves GE, DV +Valve CY has flow rate=0; tunnels lead to valves YE, IP +Valve AA has flow rate=0; tunnels lead to valves SH, XF, ZM, HN, WF +Valve NJ has flow rate=0; tunnels lead to valves NC, WF +Valve YA has flow rate=0; tunnels lead to valves CL, DR +Valve ML has flow rate=0; tunnels lead to valves NC, IP +Valve CW has flow rate=15; tunnels lead to valves QY, PQ, ZC, ZU +Valve ZS has flow rate=0; tunnels lead to valves MK, OD diff --git a/inputs/input16_test b/inputs/input16_test new file mode 100644 index 0000000..85fa5b0 --- /dev/null +++ b/inputs/input16_test @@ -0,0 +1,10 @@ +Valve AA has flow rate=0; tunnels lead to valves DD, II, BB +Valve BB has flow rate=13; tunnels lead to valves CC, AA +Valve CC has flow rate=2; tunnels lead to valves DD, BB +Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE +Valve EE has flow rate=3; tunnels lead to valves FF, DD +Valve FF has flow rate=0; tunnels lead to valves EE, GG +Valve GG has flow rate=0; tunnels lead to valves FF, HH +Valve HH has flow rate=22; tunnel leads to valve GG +Valve II has flow rate=0; tunnels lead to valves AA, JJ +Valve JJ has flow rate=21; tunnel leads to valve II \ No newline at end of file