From 46d0aac72525ac653f78de79d57f91707fae8ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dobos=20=C3=81d=C3=A1m?= Date: Tue, 20 Dec 2022 08:08:43 +0100 Subject: [PATCH] Day16 --- day16/input.txt | 59 ++++++++ day16/pressure | Bin 0 -> 16456 bytes day16/pressure.c | 167 +++++++++++++++++++++++ day16/withelephant | Bin 0 -> 24536 bytes day16/withelephant.c | 314 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 540 insertions(+) create mode 100644 day16/input.txt create mode 100755 day16/pressure create mode 100644 day16/pressure.c create mode 100755 day16/withelephant create mode 100644 day16/withelephant.c diff --git a/day16/input.txt b/day16/input.txt new file mode 100644 index 0000000..e8e35c3 --- /dev/null +++ b/day16/input.txt @@ -0,0 +1,59 @@ +Valve AW has flow rate=0; tunnels lead to valves LG, TL +Valve OM has flow rate=0; tunnels lead to valves XK, IM +Valve BG has flow rate=0; tunnels lead to valves MP, SB +Valve XB has flow rate=0; tunnels lead to valves MA, TL +Valve CD has flow rate=0; tunnels lead to valves VL, OF +Valve VF has flow rate=0; tunnels lead to valves CS, XK +Valve HK has flow rate=0; tunnels lead to valves RL, QB +Valve QN has flow rate=0; tunnels lead to valves IV, QR +Valve OF has flow rate=4; tunnels lead to valves TQ, CD, IR, IM, JE +Valve QB has flow rate=14; tunnels lead to valves HK, XE, CS, VO +Valve ZE has flow rate=7; tunnels lead to valves JB, NC, SE, OI +Valve OW has flow rate=0; tunnels lead to valves MB, JB +Valve MA has flow rate=0; tunnels lead to valves XB, MB +Valve MP has flow rate=0; tunnels lead to valves VK, BG +Valve UE has flow rate=9; tunnels lead to valves ZM, RZ, WI, HO, FO +Valve QR has flow rate=24; tunnel leads to valve QN +Valve TQ has flow rate=0; tunnels lead to valves OF, AA +Valve SE has flow rate=0; tunnels lead to valves ZE, ZZ +Valve AQ has flow rate=20; tunnel leads to valve CX +Valve XE has flow rate=0; tunnels lead to valves JQ, QB +Valve DC has flow rate=8; tunnels lead to valves ZD, MJ, RZ +Valve ZM has flow rate=0; tunnels lead to valves YJ, UE +Valve VK has flow rate=21; tunnel leads to valve MP +Valve VR has flow rate=0; tunnels lead to valves WV, PS +Valve BH has flow rate=0; tunnels lead to valves AA, MB +Valve ZR has flow rate=0; tunnels lead to valves LG, AI +Valve JE has flow rate=0; tunnels lead to valves OF, HO +Valve IR has flow rate=0; tunnels lead to valves IV, OF +Valve FO has flow rate=0; tunnels lead to valves XQ, UE +Valve AA has flow rate=0; tunnels lead to valves NC, VY, BH, TQ, YJ +Valve ZZ has flow rate=0; tunnels lead to valves SE, TL +Valve XQ has flow rate=0; tunnels lead to valves IV, FO +Valve WI has flow rate=0; tunnels lead to valves UE, VO +Valve VY has flow rate=0; tunnels lead to valves AA, LG +Valve XK has flow rate=15; tunnels lead to valves VF, OM, ZD +Valve CX has flow rate=0; tunnels lead to valves AQ, MB +Valve JQ has flow rate=0; tunnels lead to valves XE, IV +Valve LG has flow rate=3; tunnels lead to valves VY, PS, ZR, AW, OI +Valve JB has flow rate=0; tunnels lead to valves ZE, OW +Valve OI has flow rate=0; tunnels lead to valves ZE, LG +Valve YJ has flow rate=0; tunnels lead to valves ZM, AA +Valve NC has flow rate=0; tunnels lead to valves AA, ZE +Valve KR has flow rate=0; tunnels lead to valves SB, MJ +Valve MB has flow rate=17; tunnels lead to valves CX, BH, AI, OW, MA +Valve AI has flow rate=0; tunnels lead to valves ZR, MB +Valve TL has flow rate=16; tunnels lead to valves ZZ, XB, AW +Valve RL has flow rate=0; tunnels lead to valves WV, HK +Valve CS has flow rate=0; tunnels lead to valves VF, QB +Valve WV has flow rate=25; tunnels lead to valves RL, VL, VR +Valve ZD has flow rate=0; tunnels lead to valves XK, DC +Valve IV has flow rate=23; tunnels lead to valves XQ, IR, JQ, QN +Valve PS has flow rate=0; tunnels lead to valves VR, LG +Valve RZ has flow rate=0; tunnels lead to valves DC, UE +Valve VO has flow rate=0; tunnels lead to valves WI, QB +Valve MJ has flow rate=0; tunnels lead to valves DC, KR +Valve IM has flow rate=0; tunnels lead to valves OM, OF +Valve VL has flow rate=0; tunnels lead to valves CD, WV +Valve SB has flow rate=18; tunnels lead to valves BG, KR +Valve HO has flow rate=0; tunnels lead to valves JE, UE diff --git a/day16/pressure b/day16/pressure new file mode 100755 index 0000000000000000000000000000000000000000..031146063207cca0ea955ba1ffec7fe2e1ad8103 GIT binary patch literal 16456 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 F@jqH+F|Ggr literal 0 HcmV?d00001 diff --git a/day16/pressure.c b/day16/pressure.c new file mode 100644 index 0000000..6b39339 --- /dev/null +++ b/day16/pressure.c @@ -0,0 +1,167 @@ +#include +#include +#include + +#define BUFFER_SIZE 128 +#define MAX_TUNNELS 16 +#define MAX_VALVES 128 +#define MAX_TIME 30 + +typedef struct valve { + char name[2]; + int ppm; + char nextValveNames[16][2]; + struct valve **nextValves; + int valve_count; +} VALVE; + +unsigned findBestPPM(VALVE, int, unsigned, VALVE*, int, VALVE*, int); + +unsigned bestMax = 0; +int bestPpm = 0; + +int solution[6][3] = { + {'D', 'D', 29}, + {'B', 'B', 26}, + {'J', 'J', 22}, + {'H', 'H', 15}, + {'E', 'E', 11}, + {'C', 'C', 7}, +}; + +int main() { + char buf[BUFFER_SIZE], *p, c; + memset(buf, 0, BUFFER_SIZE); + p = buf; + VALVE valves[MAX_VALVES], curr; + int valve_count = 0; + + while ((c = getchar()) != EOF) { + *p++ = c; + if (c == '\n') { + p = buf; + memset(&curr, 0, sizeof(VALVE)); + sscanf(p, "Valve %c%c has flow rate=%i; tunnels lead to valve", &curr.name[0], &curr.name[1], &curr.ppm); + if (curr.ppm > bestPpm) { + bestPpm = curr.ppm; + } + while(*p++ != 'v') {} + while(*p++ != 'v') {} + while(*p++ != ' ') {} + while(*p != 0) { + sscanf(p, "%c%c", &curr.nextValveNames[curr.valve_count][0], &curr.nextValveNames[curr.valve_count][1]); + curr.valve_count++; + while(*p != ',' && *p != 0) p++; + if (*p == ',') p+=2; + } + curr.nextValves = (VALVE**)malloc(curr.valve_count * sizeof(VALVE*)); + memset(curr.nextValves, 0, curr.valve_count * sizeof(VALVE*)); + valves[valve_count] = curr; + valve_count++; + memset(buf, 0, BUFFER_SIZE); + p = buf; + } + } + + // Create pointers instead of names + for (int i = 0; i < valve_count; i++) { + for (int j = 0; j < valves[i].valve_count; j++) { + for (int k = 0; k < valve_count; k++) { + if (valves[k].name[0] == valves[i].nextValveNames[j][0] && valves[k].name[1] == valves[i].nextValveNames[j][1]) { + valves[i].nextValves[j] = &valves[k]; + break; + } + } + } + } + + // Find the starting point 'AA' + for (int i = 0; i < valve_count; i++) { + if (valves[i].name[0] == 'A' && valves[i].name[1] == 'A') { + curr = valves[i]; + break; + } + } + + VALVE *opened = (VALVE*)malloc(MAX_TIME * sizeof(VALVE)); + memset(opened, 0, MAX_TIME * sizeof(VALVE)); + VALVE *walked = (VALVE*)malloc(MAX_TIME * sizeof(VALVE)); + memset(walked, 0, MAX_TIME * sizeof(VALVE)); + printf("%u\n", findBestPPM(curr, MAX_TIME, 0, opened, 0, walked, 0)); + free(opened); + free(walked); + for (int i = 0; i < valve_count; i++) { + free(valves[i].nextValves); + } +} + +unsigned findBestPPM(VALVE valve, int time, unsigned sum, VALVE* opened, int opened_count, VALVE* walked, int walk_length) { + unsigned max = 0, tmp = 0; + if (time <= 0) { + return sum; + } + + for (int i = 1; i < time; i++) { + tmp += bestPpm * (time - i); + } + // If we have no chance of beating the highScore, just skip + if (bestMax > sum + tmp) { + return sum; + } + tmp = 0; + + VALVE walked_copy[MAX_TIME]; + for (int i = 0; i < MAX_TIME; i++) { + walked_copy[i] = walked[i]; + } + + // Not opening, just running + // + // Shouldn't run in circles + // Magyarorszag elore megy nem hatra + for (int i = 0; i < walk_length; i++) { + if (walked[i].name[0] == valve.name[0] && walked[i].name[1] == valve.name[1]) { + return sum; + } + } + for (int i = 0; i < valve.valve_count; i++) { + walked[walk_length] = valve; + tmp = findBestPPM(*valve.nextValves[i], time - 1, sum, opened, opened_count, walked, walk_length + 1); + for (int k = 0; k < MAX_TIME; k++) { + walked[k] = walked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + + // Opening this valve if it was not opened before + // + // Only consider this if the flow rate here is > 0 + if (valve.ppm > 0) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == valve.name[0] && opened[i].name[1] == valve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = valve.ppm * (time-1); + for (int i = 0; i < valve.valve_count; i++) { + opened[opened_count] = valve; + walked[0] = valve; + tmp = findBestPPM(*valve.nextValves[i], time - 2, sum + openedPressure, opened, opened_count+1, walked, 1); + if (max < tmp) { + max = tmp; + } + } + } + } + + if (max > bestMax) { + bestMax = max; + } + + return max; +} diff --git a/day16/withelephant b/day16/withelephant new file mode 100755 index 0000000000000000000000000000000000000000..b48eda507e24ca9db9850d350c66d887f3c3b56c GIT binary patch literal 24536 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 +#include +#include + +#define BUFFER_SIZE 128 +#define MAX_TUNNELS 16 +#define MAX_VALVES 128 +#define MAX_TIME 26 + +typedef struct valve { + char name[2]; + int ppm; + char nextValveNames[16][2]; + struct valve **nextValves; + int valve_count; +} VALVE; + +unsigned findBestPPM(VALVE, VALVE, int, unsigned, VALVE*, int, VALVE*, int, VALVE*, int, int, int); +unsigned bestMax = 0; +int bestPpm = 0; + +int main() { + char buf[BUFFER_SIZE], *p, c; + memset(buf, 0, BUFFER_SIZE); + p = buf; + VALVE valves[MAX_VALVES], curr; + int valve_count = 0; + + while ((c = getchar()) != EOF) { + *p++ = c; + if (c == '\n') { + p = buf; + memset(&curr, 0, sizeof(VALVE)); + sscanf(p, "Valve %c%c has flow rate=%i; tunnels lead to valve", &curr.name[0], &curr.name[1], &curr.ppm); + if (curr.ppm > bestPpm) { + bestPpm = curr.ppm; + } + while(*p++ != 'v') {} + while(*p++ != 'v') {} + while(*p++ != ' ') {} + while(*p != 0) { + sscanf(p, "%c%c", &curr.nextValveNames[curr.valve_count][0], &curr.nextValveNames[curr.valve_count][1]); + curr.valve_count++; + while(*p != ',' && *p != 0) p++; + if (*p == ',') p+=2; + } + curr.nextValves = (VALVE**)malloc(curr.valve_count * sizeof(VALVE*)); + memset(curr.nextValves, 0, curr.valve_count * sizeof(VALVE*)); + valves[valve_count] = curr; + valve_count++; + memset(buf, 0, BUFFER_SIZE); + p = buf; + } + } + + // Create pointers instead of names + for (int i = 0; i < valve_count; i++) { + for (int j = 0; j < valves[i].valve_count; j++) { + for (int k = 0; k < valve_count; k++) { + if (valves[k].name[0] == valves[i].nextValveNames[j][0] && valves[k].name[1] == valves[i].nextValveNames[j][1]) { + valves[i].nextValves[j] = &valves[k]; + break; + } + } + } + } + + // Find the starting point 'AA' + for (int i = 0; i < valve_count; i++) { + if (valves[i].name[0] == 'A' && valves[i].name[1] == 'A') { + curr = valves[i]; + break; + } + } + + VALVE *opened = (VALVE*)malloc(2 * MAX_TIME * sizeof(VALVE)); + memset(opened, 0, 2 * MAX_TIME * sizeof(VALVE)); + VALVE *walked = (VALVE*)malloc(MAX_TIME * sizeof(VALVE)); + memset(walked, 0, MAX_TIME * sizeof(VALVE)); + VALVE *elephantWalked = (VALVE*)malloc(MAX_TIME * sizeof(VALVE)); + memset(elephantWalked, 0, MAX_TIME * sizeof(VALVE)); + printf("%u\n", findBestPPM(curr, curr, MAX_TIME, 0, opened, 0, walked, 0, elephantWalked, 0, 0, 0)); + free(opened); + free(walked); + free(elephantWalked); + for (int i = 0; i < valve_count; i++) { + free(valves[i].nextValves); + } +} + +unsigned findBestPPM(VALVE valve, VALVE elephantValve, int time, unsigned sum, VALVE* opened, int opened_count, VALVE* walked, int walk_length, VALVE* elephantWalked, int elephantWalk_length, int skipNext, int elephantSkipNext) { + unsigned max = 0, tmp = 0; + if (time <= 0) { + return sum; + } + + for (int i = 1; i < time; i++) { + tmp += bestPpm * (time - i); + } + // If we have no chance of beating the highScore, just skip + if (bestMax > sum + tmp) { + return sum; + } + tmp = 0; + + VALVE walked_copy[MAX_TIME]; + for (int i = 0; i < MAX_TIME; i++) { + walked_copy[i] = walked[i]; + } + VALVE elephantWalked_copy[MAX_TIME]; + for (int i = 0; i < MAX_TIME; i++) { + elephantWalked_copy[i] = elephantWalked[i]; + } + + // Shouldn't run in circles + // Magyarorszag elore megy nem hatra + for (int i = 0; i < walk_length; i++) { + if (walked[i].name[0] == valve.name[0] && walked[i].name[1] == valve.name[1]) { + return sum; + } + } + for (int i = 0; i < elephantWalk_length; i++) { + if (elephantWalked[i].name[0] == elephantValve.name[0] && elephantWalked[i].name[1] == elephantValve.name[1]) { + return sum; + } + } + + + // Both can move + if (!skipNext && !elephantSkipNext) { + // Not opening, just running on both + for (int i = 0; i < valve.valve_count; i++) { + for (int j = 0; j < elephantValve.valve_count; j++) { + walked[walk_length] = valve; + elephantWalked[elephantWalk_length] = elephantValve; + tmp = findBestPPM(*valve.nextValves[i], *elephantValve.nextValves[j], time - 1, sum, opened, opened_count, walked, walk_length + 1, elephantWalked, elephantWalk_length + 1, 0, 0); + for (int k = 0; k < MAX_TIME; k++) { + walked[k] = walked_copy[k]; + } + for (int k = 0; k < MAX_TIME; k++) { + elephantWalked[k] = elephantWalked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + } + + // Opening human valve only + if (valve.ppm > 0) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == valve.name[0] && opened[i].name[1] == valve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = valve.ppm * (time-1); + for (int i = 0; i < valve.valve_count; i++) { + opened[opened_count] = valve; + walked[0] = valve; + for (int j = 0; j < elephantValve.valve_count; j++) { + elephantWalked[elephantWalk_length] = elephantValve; + tmp = findBestPPM(*valve.nextValves[i], *elephantValve.nextValves[j], time - 1, sum + openedPressure, opened, opened_count+1, walked, 1, elephantWalked, elephantWalk_length + 1, 1, 0); + for (int k = 0; k < MAX_TIME; k++) { + elephantWalked[k] = elephantWalked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + } + } + } + + // Opening elephantValve only + if (elephantValve.ppm > 0) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == elephantValve.name[0] && opened[i].name[1] == elephantValve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = elephantValve.ppm * (time-1); + for (int i = 0; i < elephantValve.valve_count; i++) { + opened[opened_count] = elephantValve; + elephantWalked[0] = elephantValve; + for (int j = 0; j < valve.valve_count; j++) { + walked[walk_length] = valve; + tmp = findBestPPM(*valve.nextValves[j], *elephantValve.nextValves[i], time - 1, sum + openedPressure, opened, opened_count+1, walked, walk_length + 1, elephantWalked, 1, 0, 1); + for (int k = 0; k < MAX_TIME; k++) { + walked[k] = walked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + } + } + } + + // Both opening + if (elephantValve.ppm > 0 && valve.ppm > 0 && !(elephantValve.name[0] == valve.name[0] && elephantValve.name[1] == valve.name[1])) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == elephantValve.name[0] && opened[i].name[1] == elephantValve.name[1]) { + tmp = 1; + break; + } + } + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == valve.name[0] && opened[i].name[1] == valve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = elephantValve.ppm * (time-1) + valve.ppm * (time-1); + opened[opened_count] = elephantValve; + opened[opened_count+1] = valve; + elephantWalked[0] = elephantValve; + walked[0] = valve; + for (int i = 0; i < elephantValve.valve_count; i++) { + for (int j = 0; j < valve.valve_count; j++) { + tmp = findBestPPM(*valve.nextValves[j], *elephantValve.nextValves[i], time - 2, sum + openedPressure, opened, opened_count+2, walked, 1, elephantWalked, 1, 0, 0); + if (max < tmp) { + max = tmp; + } + } + } + } + } + } else if (skipNext && !elephantSkipNext) { + // Human is opening valve, only elephant has a choice + for (int i = 0; i < elephantValve.valve_count; i++) { + elephantWalked[elephantWalk_length] = elephantValve; + tmp = findBestPPM(valve, *elephantValve.nextValves[i], time - 1, sum, opened, opened_count, walked, walk_length, elephantWalked, elephantWalk_length + 1, 0, 0); + for (int k = 0; k < MAX_TIME; k++) { + elephantWalked[k] = elephantWalked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + + // Opening this valve if it was not opened before + // + // Only consider this if the flow rate here is > 0 + if (elephantValve.ppm > 0) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == elephantValve.name[0] && opened[i].name[1] == elephantValve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = elephantValve.ppm * (time-1); + for (int i = 0; i < elephantValve.valve_count; i++) { + opened[opened_count] = elephantValve; + elephantWalked[0] = elephantValve; + tmp = findBestPPM(valve, *elephantValve.nextValves[i], time - 1, sum + openedPressure, opened, opened_count+1, walked, walk_length, elephantWalked, 1, 0, 1); + if (max < tmp) { + max = tmp; + } + } + } + } + } else if (!skipNext && elephantSkipNext) { + // Elephant is opening valve???, only human has a choice + for (int i = 0; i < valve.valve_count; i++) { + walked[walk_length] = valve; + tmp = findBestPPM(*valve.nextValves[i], elephantValve, time - 1, sum, opened, opened_count, walked, walk_length + 1, elephantWalked, elephantWalk_length, 0, 0); + for (int k = 0; k < MAX_TIME; k++) { + walked[k] = walked_copy[k]; + } + if (max < tmp) { + max = tmp; + } + } + + // Opening this valve if it was not opened before + // + // Only consider this if the flow rate here is > 0 + if (valve.ppm > 0) { + tmp = 0; + for (int i = 0; i < opened_count; i++) { + if (opened[i].name[0] == valve.name[0] && opened[i].name[1] == valve.name[1]) { + tmp = 1; + break; + } + } + if (!tmp) { + unsigned openedPressure = valve.ppm * (time-1); + for (int i = 0; i < valve.valve_count; i++) { + opened[opened_count] = valve; + walked[0] = valve; + tmp = findBestPPM(*valve.nextValves[i], elephantValve, time - 1, sum + openedPressure, opened, opened_count+1, walked, 1, elephantWalked, elephantWalk_length, 1, 0); + if (max < tmp) { + max = tmp; + } + } + } + } + } + + if (max > bestMax) { + bestMax = max; + } + return max; +}