-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
292 lines (267 loc) · 8.33 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Define values for open and closed valves
#define VALVEOPEN 0
#define VALVECLOSE 1
// Definea valve
struct Valve {
char name[3];
int rate;
int leads[5];
int num_leads;
int state;
};
// Define a list of valves
struct ValveList {
struct Valve* list;
int size;
};
// Function to return a deepcopy of a ValveList
struct ValveList deepcopy(struct ValveList src) {
// Copy the stack elements
struct ValveList dst = src;
// Allocate new memoory for our ValveList
dst.list = (struct Valve*)malloc(sizeof(struct Valve)*dst.size);
// Copy each value in the list
for (int i=0; i<dst.size; i++) {
dst.list[i] = src.list[i];
}
// Return the new ValveList
return dst;
}
// Function to pre-compute the costs of each traversal
void calculatecost(struct ValveList valves, int** costtable) {
// Define a stack var for later
int new_val = 1;
// Set costs of depth 1
for (int i=0; i<valves.size; i++) {
for (int j=0; j<valves.list[i].num_leads; j++) {
costtable[i][valves.list[i].leads[j]] = 1;
}
}
// Calculate until we're confident we've found the shortest path
while (new_val) {
new_val = 0;
// Iterate over the costtable
for (int i=0; i<valves.size; i++) {
for (int j=0; j<valves.size; j++) {
// Check if the cost exists
if (costtable[i][j]) {
// If it does iterate over every lead in j
for (int k=0; k<valves.list[j].num_leads; k++) {
// For every lead check if the distance exists and that i is not equal to the lead
if(!costtable[i][valves.list[j].leads[k]] && i != valves.list[j].leads[k]) {
// Otherwise the shortest distance to this lead is the cost of i to j plus one
costtable[i][valves.list[j].leads[k]] = costtable[i][j] + 1;
new_val = 1;
}
// Check if our way is faster
else if (costtable[i][j]+1 < costtable[i][valves.list[j].leads[k]]) {
// If it is set it as the new shortest distance
costtable[i][valves.list[j].leads[k]] = costtable[i][j] + 1;
new_val = 1;
}
}
}
}
}
}
return;
}
// Recursive solution for part1
int part1(struct ValveList prev, int** costtable, int time, int curr) {
// If time is out then we can't get any more pressure released
if (time <= 0) {
return 0;
}
// Create a deepcopy of the valvelist to work with
struct ValveList valves = deepcopy(prev);
// Set the current valve to open
valves.list[curr].state = VALVEOPEN;
// Create variables to hold the potential costs
int best_cost = 0;
int curr_cost = 0;
// Iterate over all of our valves
for (int i=0; i<valves.size; i++) {
// Check if it has a good pressure release rate and that the valve
// can be opened
if (valves.list[i].rate > 0 && valves.list[i].state == VALVECLOSE) {
// Try this valve as the next one, reducing time by the cost to
// get to that valve minus one to open the valve
curr_cost = part1(valves, costtable, time-1-costtable[curr][i], i);
// Check if that releases more pressure than our previous best
if (curr_cost > best_cost) {
best_cost = curr_cost;
}
}
}
// Free our deepcopy memory
free(valves.list);
// Return the best path plus the current amount of pressure that
// would be released at the current valve
return best_cost+prev.list[curr].rate*time;
}
// Recursive solution for part2
int part2(struct ValveList prev, int** costtable, int time, int time2, int curr, int curr2) {
// If time is out then we can't get any more pressure released
if (time2 <= 0) {
return 0;
}
// Create a deepcopy of our valvelist
struct ValveList valves = deepcopy(prev);
// Set the current valve to open
valves.list[curr2].state = VALVEOPEN;
// Create variables to hold the potential costs
int best_cost = 0;
int curr_cost = 0;
// Iterate over all of our valves
for (int i=0; i<valves.size; i++) {
// Check if it has a good pressure release rate and that the valve
// can be opened
if (valves.list[i].rate > 0 && valves.list[i].state == VALVECLOSE) {
// Call this function again, but set the secondary variables to primary and set
// our next valve as the new secondary variables
// This allows the elephant to run concurrently to us
curr_cost = part2(valves, costtable, time2, time-1-costtable[curr][i], curr2, i);
// Check if that releases more pressure than our previous best
if (curr_cost > best_cost) {
best_cost = curr_cost;
}
}
}
// Free our deepcopy memory
free(valves.list);
// Return the best path plus the current amount of pressure that
// would be released at the current valve
return best_cost+prev.list[curr2].rate*time2;
}
// Finds the index of the specified named valve
int findvalveindex(char name[3], struct ValveList valves) {
// Iterate until we find the valve
int index = 0;
for (int i=0; i<valves.size; i++) {
if (strcmp(name, valves.list[i].name) == 0) {
index = i;
break;
}
}
// Return the valve index
return index;
}
// Debug function that prints out the cost table
void printcosttable(struct ValveList valves, int** costtable) {
// Print out valve names
for (int i=0; i<valves.size; i++) {
printf("%s ", valves.list[i].name);
}
printf("\n");
// Print out the costs
for (int i=0; i<valves.size; i++) {
for (int j=0; j<valves.size; j++) {
printf("%2d ", costtable[i][j]);
}
printf("\n");
}
return;
}
// Function to parse the input file and return
// a valvelist
struct ValveList processinput(FILE *in_file) {
// Create our stack vars
char buffer[100];
char* tmp;
char tmp2[3];
int curr = 0;
struct ValveList valves = {.size = 0};
// Get number of sensor/beacon pairs in file
while(fgets(buffer, sizeof(buffer), in_file) != NULL) {
if (buffer[0] != '\n') {
valves.size++;
}
}
// Go back to beginning of the file
rewind(in_file);
valves.list = (struct Valve*)malloc(sizeof(struct Valve)*valves.size);
// Get all of our valves and flow rates
while(fgets(buffer, sizeof(buffer), in_file) != NULL) {
// Check if the line is blank
if (buffer[0] != '\n') {
// Get the name of the valve
valves.list[curr].name[0] = buffer[6];
valves.list[curr].name[1] = buffer[7];
valves.list[curr].name[2] = 0;
// Set the valve to closed
valves.list[curr].state = VALVECLOSE;
// Get the rate of the valve
tmp = strtok(buffer, ";");
tmp = strtok(tmp, "=");
tmp = strtok(NULL, "=");
sscanf(tmp, "%d", &valves.list[curr].rate);
// Move to the next valve in the valve list
curr++;
}
}
rewind(in_file);
// Set our tunnel leads
curr = 0;
while(fgets(buffer, sizeof(buffer), in_file) != NULL) {
// Check if the line is blank
if (buffer[0] != '\n') {
tmp = strtok(buffer, ";");
tmp = strtok(NULL, ";");
// Get all of the leads for that valve
valves.list[curr].num_leads = 0;
for (int i=strlen(tmp)-1; i>0; i--) {
if (tmp[i] == '\n' || tmp[i] == ',') {
// Set a tmp name to locate the valve
tmp2[0] = tmp[i-2];
tmp2[1] = tmp[i-1];
tmp2[2] = 0;
// Find the valve indexand store it as a lead
valves.list[curr].leads[valves.list[curr].num_leads] = findvalveindex(tmp2, valves);
// Increase oour number of leaves
valves.list[curr].num_leads++;
}
}
// Keep going through our valve list
curr++;
}
}
// return the valve list
return valves;
}
int main(int argc, char *argv[])
{
// Read in our input file
FILE *in_file = fopen("input.txt", "r");
if (in_file == NULL) {
printf("Could not open input file!");
exit(-1);
}
// Declare stack vars
// Get our valvelist from the input file
struct ValveList valves = processinput(in_file);
// Find our starting valve index
int start_index = findvalveindex("AA", valves);
// Allocate memory for our costtable and zero out the 2d array
int** costtable = (int**)malloc(sizeof(int*)*valves.size+sizeof(int)*valves.size*valves.size);
for (int i=0;i<valves.size;i++) {
costtable[i] = (int*)((int*)(costtable+valves.size)+valves.size*i);
for (int j=0;j<valves.size;j++) {
costtable[i][j] = 0;
}
}
// Calculate the cost to get to each vertex
calculatecost(valves, costtable);
// Solve part 1
printf("The most pressure by ourself that can be released is %d\n", part1(valves, costtable, 30, start_index));
// Solve part 2
printf("The most pressure with the elephant that can be released is %d\n", part2(valves, costtable, 26, 26, start_index, start_index));
// Clean up memory
free(valves.list);
free(costtable);
// Close our file
fclose(in_file);
return EXIT_SUCCESS;
}