-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
246 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
module day16; | ||
import std::io; | ||
import std::math; | ||
import std::map; | ||
import std::array::list; | ||
|
||
define ValveMap = HashMap<char[], int>; | ||
define IntPairList = List<int[<2>]>; | ||
ValveMap v; | ||
|
||
struct Valve | ||
{ | ||
int id; | ||
char[] name; | ||
int rate; | ||
int[10] tunnels; | ||
int tunnel_count; | ||
int[100] tunnel_cost; | ||
IntPairList list; | ||
} | ||
|
||
fn void populate_tunnels(Valve[] valves, int i, Valve* v, int tunnel, int cost) | ||
{ | ||
if (tunnel == i) return; | ||
int current_cost = v.tunnel_cost[tunnel]; | ||
if (current_cost && current_cost <= cost) return; | ||
v.tunnel_cost[tunnel] = cost; | ||
Valve* other_valve = &valves[tunnel]; | ||
for (int j = 0; j < other_valve.tunnel_count; j++) | ||
{ | ||
populate_tunnels(valves, i, v, other_valve.tunnels[j], cost + 1); | ||
} | ||
} | ||
|
||
fn Valve[] load_valves(Valve[100]* available_slots) | ||
{ | ||
File f; | ||
f.open("valves.txt", "rb")!!; | ||
defer catch(f.close()); | ||
int count = 0; | ||
while (!f.eof()) | ||
{ | ||
@pool() | ||
{ | ||
char[] line = f.tgetline(); | ||
char[][] parts = str::tsplit(line, " "); | ||
char[] name = str::copy(parts[1]); | ||
char[] rate_part = parts[4]; | ||
int val = v.@get_or_set(name, (int)v.count); | ||
Valve *valve_entry = &(*available_slots)[val]; | ||
assert(valve_entry.id == 0); | ||
count++; | ||
int rate = str::to_int(rate_part[5..^2])!!; | ||
int len = parts.len; | ||
*valve_entry = { .rate = rate, .id = val, .name = name }; | ||
for (int i = 9; i < parts.len; i++) | ||
{ | ||
char[] valve = parts[i]; | ||
if (i < parts.len - 1) | ||
{ | ||
valve = valve[..^2]; | ||
} | ||
val = v.@get_or_set(str::copy(valve), (int)v.count); | ||
valve_entry.tunnels[valve_entry.tunnel_count++] = val; | ||
} | ||
}; | ||
} | ||
Valve[] valves = (*available_slots)[:count]; | ||
foreach (int i, &v : valves) | ||
{ | ||
for (int j = 0; j < v.tunnel_count; j++) | ||
{ | ||
populate_tunnels(valves, i, v, v.tunnels[j], 1); | ||
} | ||
} | ||
// Make entering the other tunnels super expensive. | ||
foreach (int i, &v : valves) | ||
{ | ||
if (!v.rate) continue; | ||
foreach (&v2 : valves) | ||
{ | ||
v2.list.append({ i, v2.tunnel_cost[i] }); | ||
} | ||
} | ||
assert(count == v.count); | ||
return valves; | ||
} | ||
|
||
fn int visit_valve(int id, Valve[] valves, int* locations, int minutes, int current_flow) | ||
{ | ||
assert(minutes > 0); | ||
Valve* current = &valves[id]; | ||
assert(locations[id] == 1); | ||
int total = 0; | ||
if (current.rate) | ||
{ | ||
minutes--; | ||
total += current_flow; | ||
current_flow += current.rate; | ||
} | ||
int best_val = minutes * current_flow; | ||
if (minutes > 1) | ||
{ | ||
foreach (pair : current.list) | ||
{ | ||
int i = pair[0]; | ||
if (locations[i]) continue; | ||
int cost = pair[1]; | ||
assert(cost); | ||
if (cost >= minutes) continue; | ||
locations[i] = 1; | ||
int val = current_flow * cost + visit_valve(i, valves, locations, minutes - cost, current_flow); | ||
locations[i] = 0; | ||
if (val > best_val) best_val = val; | ||
} | ||
} | ||
return best_val + total; | ||
} | ||
|
||
fn int visit_valve2(int id, Valve[] valves, int* locations, int minutes, int current_flow, int start_moves, int start) | ||
{ | ||
assert(minutes > 0); | ||
Valve* current = &valves[id]; | ||
int total = 0; | ||
if (current.rate) | ||
{ | ||
minutes--; | ||
total += current_flow; | ||
current_flow += current.rate; | ||
} | ||
int best_val = minutes * current_flow + visit_valve(start, valves, locations, start_moves, 0); | ||
if (minutes > 1) | ||
{ | ||
foreach (pair : current.list) | ||
{ | ||
int i = pair[0]; | ||
if (locations[i]) continue; | ||
int cost = pair[1]; | ||
assert(cost); | ||
if (cost >= minutes) continue; | ||
locations[i] = 1; | ||
int val = current_flow * cost + visit_valve2(i, valves, locations, minutes - cost, current_flow, start_moves, start); | ||
locations[i] = 0; | ||
if (val > best_val) | ||
{ | ||
best_val = val; | ||
} | ||
} | ||
} | ||
return best_val + total; | ||
} | ||
|
||
fn void part1(Valve[] valves, int start) | ||
{ | ||
int[100] locations; | ||
locations[start] = 1; | ||
int flow = visit_valve(start, valves, &locations, 30, 0); | ||
io::printfln("Best flow: %d", flow); | ||
} | ||
|
||
fn void part2(Valve[] valves, int start) | ||
{ | ||
int[100] locations; | ||
locations[start] = 1; | ||
int flow = visit_valve2(start, valves, &locations, 26, 0, 26, start); | ||
io::printfln("Best flow: %d", flow); | ||
} | ||
|
||
fn void main() | ||
{ | ||
v.init(); | ||
int start = -1; | ||
Valve[] valves = load_valves(&&Valve[100] {}); | ||
foreach (int i, valve : valves) | ||
{ | ||
if (valve.name == "AA") start = i; | ||
} | ||
part1(valves, start); | ||
part2(valves, start); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
Valve SW has flow rate=0; tunnels lead to valves LX, LD | ||
Valve VS has flow rate=0; tunnels lead to valves JO, OO | ||
Valve OO has flow rate=10; tunnels lead to valves KK, HD, VS, KI | ||
Valve DZ has flow rate=8; tunnels lead to valves KV, GX, WQ, BA, PK | ||
Valve GX has flow rate=0; tunnels lead to valves AA, DZ | ||
Valve IF has flow rate=0; tunnels lead to valves OI, DW | ||
Valve BO has flow rate=0; tunnels lead to valves UJ, ZT | ||
Valve KI has flow rate=0; tunnels lead to valves OO, KU | ||
Valve JT has flow rate=3; tunnels lead to valves FC, AM, KV, XP, XZ | ||
Valve TQ has flow rate=0; tunnels lead to valves AA, DW | ||
Valve KK has flow rate=0; tunnels lead to valves QW, OO | ||
Valve NR has flow rate=0; tunnels lead to valves UG, XM | ||
Valve VO has flow rate=0; tunnels lead to valves YR, AA | ||
Valve MS has flow rate=17; tunnels lead to valves LT, LX | ||
Valve JO has flow rate=0; tunnels lead to valves YR, VS | ||
Valve ZB has flow rate=0; tunnels lead to valves UJ, LT | ||
Valve ZT has flow rate=0; tunnels lead to valves XM, BO | ||
Valve YR has flow rate=9; tunnels lead to valves VO, FY, WB, JO | ||
Valve QS has flow rate=0; tunnels lead to valves QW, FY | ||
Valve UD has flow rate=0; tunnels lead to valves CA, JB | ||
Valve AP has flow rate=0; tunnels lead to valves CA, DW | ||
Valve KV has flow rate=0; tunnels lead to valves JT, DZ | ||
Valve JH has flow rate=0; tunnels lead to valves IK, UJ | ||
Valve LD has flow rate=15; tunnels lead to valves IK, SW | ||
Valve XK has flow rate=0; tunnels lead to valves XZ, BH | ||
Valve XM has flow rate=11; tunnels lead to valves XP, CJ, ZT, NR | ||
Valve FY has flow rate=0; tunnels lead to valves YR, QS | ||
Valve GI has flow rate=22; tunnel leads to valve TI | ||
Valve JB has flow rate=14; tunnels lead to valves WB, UD, WQ, HD | ||
Valve DW has flow rate=6; tunnels lead to valves AP, TQ, NQ, IF, PK | ||
Valve UJ has flow rate=13; tunnels lead to valves JH, ZB, BO | ||
Valve KU has flow rate=0; tunnels lead to valves CA, KI | ||
Valve WQ has flow rate=0; tunnels lead to valves JB, DZ | ||
Valve BA has flow rate=0; tunnels lead to valves BH, DZ | ||
Valve AA has flow rate=0; tunnels lead to valves YX, TQ, VO, GX, QP | ||
Valve TI has flow rate=0; tunnels lead to valves GI, UG | ||
Valve FC has flow rate=0; tunnels lead to valves QP, JT | ||
Valve CA has flow rate=18; tunnels lead to valves KU, UD, AP | ||
Valve QW has flow rate=25; tunnels lead to valves QS, KK | ||
Valve XZ has flow rate=0; tunnels lead to valves JT, XK | ||
Valve YX has flow rate=0; tunnels lead to valves AA, CJ | ||
Valve OI has flow rate=0; tunnels lead to valves IF, BH | ||
Valve NQ has flow rate=0; tunnels lead to valves AM, DW | ||
Valve QP has flow rate=0; tunnels lead to valves AA, FC | ||
Valve AM has flow rate=0; tunnels lead to valves NQ, JT | ||
Valve XP has flow rate=0; tunnels lead to valves XM, JT | ||
Valve BH has flow rate=12; tunnels lead to valves BA, XK, OI | ||
Valve HD has flow rate=0; tunnels lead to valves OO, JB | ||
Valve LT has flow rate=0; tunnels lead to valves MS, ZB | ||
Valve LX has flow rate=0; tunnels lead to valves MS, SW | ||
Valve CJ has flow rate=0; tunnels lead to valves XM, YX | ||
Valve PK has flow rate=0; tunnels lead to valves DW, DZ | ||
Valve IK has flow rate=0; tunnels lead to valves LD, JH | ||
Valve WB has flow rate=0; tunnels lead to valves YR, JB | ||
Valve UG has flow rate=21; tunnels lead to valves TI, NR |