Skip to content

Commit

Permalink
Advent of Code day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Dec 17, 2022
1 parent 49f5328 commit a435696
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 12 deletions.
23 changes: 11 additions & 12 deletions day15.c3
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import std::math;
import std::array::list;
import std::priorityqueue;

define CoordPairList = List<CoordPair>;
define CoordPair = distinct int[<2>][2];
define CoordPairList = List<int[<2>][2]>;

fn int[<2>]! parse_coord(char[] s)
{
Expand Down Expand Up @@ -39,7 +38,7 @@ fn void part1(CoordPairList list)
const int Y_TARGET = 2000000;
int max_x;
int min_x;
foreach (i, CoordPair pair : list)
foreach (i, pair : list)
{
int[<2>] sensor_at = pair[0];
int[<2>] beacon_at = pair[1];
Expand All @@ -53,12 +52,12 @@ fn void part1(CoordPairList list)
}
int width = max_x - min_x + 1;
bool[] array = array::tmake(bool, width);
foreach (CoordPair pair : list)
foreach (pair : list)
{
int[<2>] sensor_at = pair[0];
int[<2>] beacon_at = pair[1];
int[<2>] diff = math::abs(sensor_at - beacon_at);
int range = diff[0] + diff[1];
int range = diff.sum();
int target_diff = math::abs(sensor_at[1] - Y_TARGET);
range -= target_diff;
if (range < 0) continue;
Expand All @@ -80,14 +79,14 @@ fn void part1(CoordPairList list)

fn bool is_covered(int[<2>] loc, CoordPairList list)
{
foreach (CoordPair pair : list)
foreach (pair : list)
{
int[<2>] sensor_at = pair[0];
int[<2>] beacon_at = pair[1];
int[<2>] diff = math::abs(sensor_at - beacon_at);
int[<2>] diff_loc = math::abs(sensor_at - loc);
int range = diff[0] + diff[1];
int to_loc = diff_loc[0] + diff_loc[1];
int range = diff.sum();
int to_loc = diff_loc.sum();
if (to_loc <= range) return true;
}
return false;
Expand All @@ -97,19 +96,19 @@ fn void part2(CoordPairList list)
{
const int RANGE = 4000000;

foreach (CoordPair pair : list)
foreach (pair : list)
{
int[<2>] sensor_at = pair[0];
int[<2>] beacon_at = pair[1];
int[<2>] diff = math::abs(sensor_at - beacon_at);
// We only need to search the space directly outside of any
// scanner's range for the hidden beacon
int range_add = diff[0] + diff[1] + 1;
int range_add = diff.sum() + 1;
for (int i = -range_add; i <= range_add; i++)
{
int[<2>] loc = sensor_at + int[<2>] { i, range_add - i };
if (loc[0] < 0 || loc[0] >= RANGE) continue;
if (loc[1] < 0 || loc[1] >= RANGE) continue;
if (loc.comp_lt({ 0, 0 }).or()) continue;
if (loc.comp_ge({ RANGE, RANGE }).or()) continue;
if (!is_covered(loc, list))
{
io::printfln("Found beacon at %s", loc);
Expand Down
180 changes: 180 additions & 0 deletions day16.c3
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);
}
55 changes: 55 additions & 0 deletions valves.txt
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

0 comments on commit a435696

Please sign in to comment.