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 0000000..0311460 Binary files /dev/null and b/day16/pressure differ 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 0000000..b48eda5 Binary files /dev/null and b/day16/withelephant differ diff --git a/day16/withelephant.c b/day16/withelephant.c new file mode 100644 index 0000000..4b73cff --- /dev/null +++ b/day16/withelephant.c @@ -0,0 +1,314 @@ +#include +#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; +}