2022 day 16 part 1 (C) - before cleaning useless hash

This commit is contained in:
2023-04-11 09:18:48 +02:00
parent e8bed49e13
commit f28c2d0406
2 changed files with 201 additions and 83 deletions

View File

@@ -178,6 +178,96 @@ with this valve layout, =1651=.
Work out the steps to release the most pressure in 30 minutes. /What is Work out the steps to release the most pressure in 30 minutes. /What is
the most pressure you can release?/ the most pressure you can release?/
To begin, [[file:16/input][get your puzzle input]]. Your puzzle answer was =1737=.
Answer: The first half of this puzzle is complete! It provides one gold star: *
** --- Part Two ---
You're worried that even with an optimal approach, the pressure released
won't be enough. What if you got one of the elephants to help you?
It would take you 4 minutes to teach an elephant how to open the right
valves in the right order, leaving you with only /26 minutes/ to
actually execute your plan. Would having two of you working together be
better, even if it means having less time? (Assume that you teach the
elephant before opening any valves yourself, giving you both the same
full 26 minutes.)
In the example above, you could teach the elephant to help you as
follows:
#+begin_example
== Minute 1 ==
No valves are open.
You move to valve II.
The elephant moves to valve DD.
== Minute 2 ==
No valves are open.
You move to valve JJ.
The elephant opens valve DD.
== Minute 3 ==
Valve DD is open, releasing 20 pressure.
You open valve JJ.
The elephant moves to valve EE.
== Minute 4 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve II.
The elephant moves to valve FF.
== Minute 5 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve AA.
The elephant moves to valve GG.
== Minute 6 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve BB.
The elephant moves to valve HH.
== Minute 7 ==
Valves DD and JJ are open, releasing 41 pressure.
You open valve BB.
The elephant opens valve HH.
== Minute 8 ==
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
You move to valve CC.
The elephant moves to valve GG.
== Minute 9 ==
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
You open valve CC.
The elephant moves to valve FF.
== Minute 10 ==
Valves BB, CC, DD, HH, and JJ are open, releasing 78 pressure.
The elephant moves to valve EE.
== Minute 11 ==
Valves BB, CC, DD, HH, and JJ are open, releasing 78 pressure.
The elephant opens valve EE.
(At this point, all valves are open.)
== Minute 12 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
...
== Minute 20 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
...
== Minute 26 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
#+end_example
With the elephant helping, after 26 minutes, the best you could do would
release a total of =1707= pressure.
/With you and an elephant working together for 26 minutes, what is the
most pressure you could release?/

View File

@@ -29,12 +29,11 @@ static DEFINE_HASHTABLE(hasht_valves, HBITS);
pool_t *pool_valve; pool_t *pool_valve;
union val { union val {
u16 val; u32 val;
char str[2]; char str[3];
}; };
enum state { enum state {
// BLOCKED = 0,
CLOSED, CLOSED,
OPENED OPENED
}; };
@@ -44,10 +43,13 @@ struct valve {
union val val; union val val;
enum state state; enum state state;
int rate; int rate;
int evalflow, evaltime;
int playedflow, playedtime;
struct hlist_node hlist; struct hlist_node hlist;
struct list_head index_sorted; struct list_head index_sorted;
struct list_head flow_sorted; struct list_head flow_sorted;
struct list_head permute; struct list_head permute;
struct list_head eval;
struct list_head played; struct list_head played;
int ntunnels, tottunnels; int ntunnels, tottunnels;
struct valve **tunnels; /* array */ struct valve **tunnels; /* array */
@@ -63,6 +65,7 @@ static struct graph {
struct list_head index_sorted; /* TO REMOVE ? */ struct list_head index_sorted; /* TO REMOVE ? */
struct list_head flow_sorted; struct list_head flow_sorted;
struct list_head permute; struct list_head permute;
struct list_head eval;
struct list_head played; struct list_head played;
struct valve **indexed; struct valve **indexed;
int *dist; /* 2-D array */ int *dist; /* 2-D array */
@@ -74,13 +77,14 @@ static struct graph {
.index_sorted = LIST_HEAD_INIT(graph.index_sorted), .index_sorted = LIST_HEAD_INIT(graph.index_sorted),
.flow_sorted = LIST_HEAD_INIT(graph.flow_sorted), .flow_sorted = LIST_HEAD_INIT(graph.flow_sorted),
.permute = LIST_HEAD_INIT(graph.permute), .permute = LIST_HEAD_INIT(graph.permute),
.eval = LIST_HEAD_INIT(graph.eval),
.played = LIST_HEAD_INIT(graph.played), .played = LIST_HEAD_INIT(graph.played),
.indexed = NULL, .indexed = NULL,
.dist = NULL .dist = NULL
}; };
#define pos(a, b) ((a)*graph.nvalves + (b)) #define POS(a, b) ((a)*graph.nvalves + (b))
#define dist(a, b) (graph.dist[pos((a), (b))]) #define DIST(a, b) (graph.dist[POS((a), (b))])
static void print_valves() static void print_valves()
{ {
@@ -89,44 +93,44 @@ static void print_valves()
printf("**** graph: .head=%p npositive=%d nzero=%d\n", graph.aa, graph.npositive, printf("**** graph: .head=%p npositive=%d nzero=%d\n", graph.aa, graph.npositive,
graph.nzero); graph.nzero);
hash_for_each(hasht_valves, bucket, cur, hlist) { hash_for_each(hasht_valves, bucket, cur, hlist) {
printf("Valve %2.2s: rate=%d ntunnels=%d tottunnels=%d ( ", printf("Valve %s: rate=%d ntunnels=%d tottunnels=%d ( ",
cur->val.str, cur->rate, cur->ntunnels, cur->tottunnels); cur->val.str, cur->rate, cur->ntunnels, cur->tottunnels);
for (int i=0; i < cur->ntunnels; ++i) for (int i=0; i < cur->ntunnels; ++i)
printf("%2s ", cur->tunnels[i]->val.str); printf("%s ", cur->tunnels[i]->val.str);
printf(")\n"); printf(")\n");
} }
printf("index1: "); printf("index1: ");
list_for_each_entry(cur, &graph.index_sorted, index_sorted) { list_for_each_entry(cur, &graph.index_sorted, index_sorted) {
printf("%d:%2.2s ", cur->index, cur->val.str); printf("%d:%s ", cur->index, cur->val.str);
} }
printf(")\n"); printf("\n");
printf("index2: "); printf("index2: ");
for (int i = 0; i < graph.nvalves; ++i) { for (int i = 0; i < graph.nvalves; ++i) {
printf("%d:%d:%2.2s ", i, graph.indexed[i]->index, graph.indexed[i]->val.str); printf("%d:%s ", graph.indexed[i]->index, graph.indexed[i]->val.str);
} }
printf(")\n"); printf("\n");
if (testmode()) { if (testmode()) {
printf("distances:\n "); printf("distances:\n ");
for (int i = 0; i < graph.nvalves; ++i) { for (int i = 0; i < graph.nvalves; ++i) {
printf(" %2.2s", graph.indexed[i]->val.str); printf(" %s", graph.indexed[i]->val.str);
} }
printf("\n"); printf("\n");
for (int i = 0; i < graph.nvalves; ++i) { for (int i = 0; i < graph.nvalves; ++i) {
printf("%2.2s ", graph.indexed[i]->val.str); printf("%s ", graph.indexed[i]->val.str);
for (int j = 0; j < graph.nvalves; ++j) { for (int j = 0; j < graph.nvalves; ++j) {
printf("%5d ", dist(i, j)); printf("%5d ", DIST(i, j));
} }
printf("\n"); printf("\n");
} }
} }
printf("flow_sorted: "); printf("flow_sorted: ");
list_for_each_entry(cur, &graph.flow_sorted, flow_sorted) { list_for_each_entry(cur, &graph.flow_sorted, flow_sorted) {
printf("%2.2s:%d ", cur->val.str, cur->rate); printf("%s:%d ", cur->val.str, cur->rate);
} }
printf("\n"); printf("\n");
printf("permute: "); printf("permute: ");
list_for_each_entry(cur, &graph.permute, permute) { list_for_each_entry(cur, &graph.permute, permute) {
printf("%2.2s:%d ", cur->val.str, cur->rate); printf("%s:%d ", cur->val.str, cur->rate);
} }
printf("\n"); printf("\n");
printf("openable: %#lx ", graph.openable); printf("openable: %#lx ", graph.openable);
@@ -139,51 +143,79 @@ static void print_valves()
} }
static struct valve *valve_nth(struct list_head *start, struct list_head *head, //#define flow2valve(p) list_entry(p, struct valve, flow_sorted)
int n)
{
struct valve *cur = list_first_entry_or_null(start, struct valve, flow_sorted);
int i = 1;
if (cur) {
list_for_each_entry_from(cur, head, flow_sorted) { /**
if (i == n || cur->flow_sorted.next == head) * eval() - eval possible moves from @flow_sorted list.
break; * @valve: &starting valve (where we are).
i++; * @depth: remaining depth (-1: full depth).
* @pick: max position (in @flow_sorted) to pick moves from (-1 for all).
* @time: remaining time.
*
* Find the "best" next move by evaluating up to @depth moves, using only the
* first @pick elements in @flow_sorted list, and within @time remaining time.
*
* @depth and @picked may be linked, for instance to fully explore the first N
* possibilities in @flow_sorted with a N depth.
*
* @Return: the current position eval.
*/
#define PAD3 log(3, "%*s", _depth, "")
#define PAD4 log(4, "%*s", _depth, "")
static struct valve *eval(int _depth, struct valve *pos, int depth, int pick, int time, int pressure)
{
struct valve *cur, *best = NULL, *sub;
struct list_head *list_flow, *tmp;
int _pick = pick, val = 0, val1, max = 0;
PAD3;
log(3, "EVAL _depth=%d pos=%d[%s] depth=%d pick=%d time=%d pressure=%d\n",
_depth, pos->index, pos->val.str, depth, pick, time, pressure);
list_for_each_safe(list_flow, tmp, &graph.flow_sorted) {
cur = list_entry(list_flow, struct valve, flow_sorted);
int d = DIST(pos->index, cur->index);
PAD4; log(4, "dist(%s,%s) = %d\n", pos->val.str, cur->val.str, d);
if (!--_pick) {
PAD4; log(4, "pick exhausted\n");
continue;
} }
if (time - (d + 1 + 1) < 0) {
PAD4; log(4, "time exhausted\n");
continue;
}
val = (time - (d + 1)) * cur->rate;
PAD4; log(4, "val=%d\n", val);
if (depth > 0) {
/* do not use list_del() here, to preserve prev/next pointers */
__list_del_entry(list_flow);
sub = eval(_depth + 2, cur, depth - 1, pick - 1, time - d - 1, pressure + pos->rate);
list_flow->prev->next = list_flow;
list_flow->next->prev = list_flow;
} else {
sub = NULL;
}
val1 = sub? sub->evalflow: 0;
PAD3; log(3, "eval(%s->%s)= %5d = %d + %d", pos->val.str, cur->val.str,
val+val1, val, val1);
if (val + val1 > max) {
max = val + val1;
best = cur;
log(3, " NEW MAX !");
}
log(3, "\n");
} }
return cur; if (best) {
best->evalflow = max;
PAD3; log(3, "EVAL returning best [%s] eval=%d\n", best->val.str, max);
//best->evaltime = time - (d + 2);
}
return best;
} }
#define flow2valve(p) list_entry(p, struct valve, flow_sorted) static __unused void permute_prepare(int n)
static struct valve *list_nth(struct list_head *start, struct list_head *head,
int n)
{
struct list_head *cur = NULL;
if (n == 0 || start->next == head)
return NULL;
list_for_each_continue(cur, start) {
if (!--n || cur == head)
break;
}
return cur ? flow2valve(cur): NULL;
}
static void list_reverse(struct list_head *start, struct list_head *head, int n)
{
struct list_head *cur = start->next, *tmp;
list_for_each_safe(cur, tmp, start) {
if (!--n || cur == head)
break;
list_move_tail(cur, start);
start = cur;
}
}
static void permute_prepare(int n)
{ {
struct valve *cur; struct valve *cur;
INIT_LIST_HEAD(&graph.permute); INIT_LIST_HEAD(&graph.permute);
@@ -198,7 +230,7 @@ static void permute_prepare(int n)
* permute() - get next permutation in graph.permute list. * permute() - get next permutation in graph.permute list.
* @n: permutation number (0 first first one) * @n: permutation number (0 first first one)
* *
* Will construct next permutation in graph.permute list, following the * Construct next permutation in graph.permute list, following the
* "lexicographic order algorithm" : * "lexicographic order algorithm" :
* https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order * https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
* *
@@ -207,7 +239,7 @@ static void permute_prepare(int n)
* 2) permute_prepare() should have been called. * 2) permute_prepare() should have been called.
* @Return: 0 if no more permutation, 1 otherwise. * @Return: 0 if no more permutation, 1 otherwise.
*/ */
static int permute(int n) static __unused int permute(int n)
{ {
struct valve *last, *first, *k, *l; struct valve *last, *first, *k, *l;
@@ -244,7 +276,7 @@ static struct valve *find_valve(union val val, int ntunnels, int rate)
struct valve *cur; struct valve *cur;
uint hash = val.val, bucket = hash_32(hash, HBITS); uint hash = val.val, bucket = hash_32(hash, HBITS);
log_f(3, "val=%2.2s ntunnels=%d rate=%d h=%u b=%d\n", val.str, ntunnels, log_f(3, "val=%s ntunnels=%d rate=%d h=%u b=%d\n", val.str, ntunnels,
rate, hash, bucket); rate, hash, bucket);
hlist_for_each_entry(cur, &hasht_valves[bucket], hlist) { hlist_for_each_entry(cur, &hasht_valves[bucket], hlist) {
if (cur->val.val == val.val) { if (cur->val.val == val.val) {
@@ -258,6 +290,8 @@ static struct valve *find_valve(union val val, int ntunnels, int rate)
cur->val.val = val.val; cur->val.val = val.val;
cur->ntunnels = 0; cur->ntunnels = 0;
cur->state = CLOSED; cur->state = CLOSED;
cur->evalflow = cur->playedflow = 0;
cur->evaltime = cur->playedtime = 30;
INIT_LIST_HEAD(&cur->index_sorted); INIT_LIST_HEAD(&cur->index_sorted);
INIT_LIST_HEAD(&cur->flow_sorted); INIT_LIST_HEAD(&cur->flow_sorted);
INIT_LIST_HEAD(&cur->permute); INIT_LIST_HEAD(&cur->permute);
@@ -297,7 +331,7 @@ static struct graph *parse()
while ((buflen = getline(&buf, &alloc, stdin)) > 0) { while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
buf[--buflen] = 0; buf[--buflen] = 0;
cur.val = *(u16 *)getnth(buf, 1); strncpy(cur.str, getnth(buf, 1), sizeof(cur.str));
//printf("valve=%s ", tok); //printf("valve=%s ", tok);
rate = atoi(getnth(NULL, 3)); rate = atoi(getnth(NULL, 3));
//printf("rate=%s ", tok); //printf("rate=%s ", tok);
@@ -308,7 +342,8 @@ static struct graph *parse()
// TODO: remove this list ? // TODO: remove this list ?
list_add_tail(&v1->index_sorted, &graph.index_sorted); list_add_tail(&v1->index_sorted, &graph.index_sorted);
graph.nvalves++; graph.nvalves++;
if (rate || v1->val.val == ('A' << 8 | 'A')) { //if (rate || v1->val.val == ('A' << 8 | 'A')) {
if (rate) {
struct valve *cur; struct valve *cur;
graph.npositive++; graph.npositive++;
/* keep this list sorted by flow decrasing */ /* keep this list sorted by flow decrasing */
@@ -334,7 +369,7 @@ static struct graph *parse()
v2 = find_valve(link, 0, 0); v2 = find_valve(link, 0, 0);
*(v1->tunnels + v1->ntunnels++) = v2; *(v1->tunnels + v1->ntunnels++) = v2;
//printf(",%s", tok); //printf(",%s", tok);
} while ((tok = getnth(NULL, 1))); } while ((tok = getnth(NULL, 0)));
//printf("\n"); //printf("\n");
} }
graph.aa = find_valve((union val) { .str="AA" }, 0, 0); graph.aa = find_valve((union val) { .str="AA" }, 0, 0);
@@ -363,12 +398,12 @@ static void build_distances()
graph.dist = calloc(graph.nvalves * graph.nvalves, sizeof(int)); graph.dist = calloc(graph.nvalves * graph.nvalves, sizeof(int));
/* initialize values */ /* initialize values */
for (i = 0; i < graph.nvalves; ++i) { for (i = 0; i < graph.nvalves; ++i) {
for (j = i; j < graph.nvalves; ++j) { for (j = 1; j < graph.nvalves; ++j) {
if (i != j) { if (i != j) {
if (is_neighbour(i, j)) if (is_neighbour(i, j))
dist(i, j) = dist(j, i) = 1; DIST(i, j) = DIST(j, i) = 1;
else else
dist(i, j) = dist(j, i) = 10000; DIST(i, j) = DIST(j, i) = 10000;
} }
//printf("pos(%d,%d)=%d\n", i, j, pos(i, j)); //printf("pos(%d,%d)=%d\n", i, j, pos(i, j));
} }
@@ -390,11 +425,9 @@ static void build_distances()
for (i = 0; i < graph.nvalves; i++) { for (i = 0; i < graph.nvalves; i++) {
/* Pick all vertices as destination for the above picked source */ /* Pick all vertices as destination for the above picked source */
for (j = i + 1; j < graph.nvalves; j++) for (j = i + 1; j < graph.nvalves; j++)
dist(i, j) = dist(j, i) = min(dist(i, j), dist(i, k) + dist(k, j)); DIST(i, j) = DIST(j, i) = min(DIST(i, j), DIST(i, k) + DIST(k, j));
} }
} }
print_valves();
/* first, build an array */
return; return;
} }
@@ -416,28 +449,23 @@ static ulong part1()
printf("part1\n"); printf("part1\n");
build_distances(); build_distances();
struct valve *v;
for (int i = 1; i < 10; ++i) {
v = valve_nth(&graph.flow_sorted, &graph.flow_sorted, i);
printf("sorted(%d): i=%d rate=%d\n", i, v->index, v->rate);
}
permute_prepare(4);
print_valves(); print_valves();
struct valve *cur;
printf("permutation 0: "); puts("zob1");
list_for_each_entry(cur, &graph.permute, permute) { eval(0, graph.aa, 7, 7, 30, 0);
printf("%d ", cur->rate); puts("zob2");
} /*
printf("\n"); permute_prepare(4);
for (int i = 0; permute(i); ++i) { for (int i = 0; permute(i); ++i) {
struct valve *cur;
printf("permutation %d: ", i); printf("permutation %d: ", i);
list_for_each_entry(cur, &graph.permute, permute) { list_for_each_entry(cur, &graph.permute, permute) {
printf("%d ", cur->rate); printf("%d ", cur->rate);
} }
printf("\n"); printf("\n");
} }
//res = do_1(cur, 0, 0); */
return res; return res;
} }