2022 day 16 (C): use same eval() for parts 1 & 2.

This commit is contained in:
2023-04-20 08:31:16 +02:00
parent f80a051177
commit 3a857e4d53

View File

@@ -134,166 +134,24 @@ static void print_valves()
/**
* eval() - eval possible moves from @flow_sorted list.
* @_depth: recursivity depth (for debug only, TODO: remove).
* @valve: &starting valve (where we are).
* @depth: remaining depth (-1: full depth).
* @nworkers: number of workers.
* @workers: array of workers.
* @pick: max position (in @flow_sorted) to pick moves from (-1 for all).
* @time: remaining time.
* @pressure: total pressure per time unit so far.
*
* 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.
* Find the "best" next move by evaluating only the first @pick elements
* in @flow_sorted list.
*
* @Return: the current position eval.
*/
static struct valve *eval(int _depth, struct valve *pos, int depth, int pick, int time, int pressure)
static struct valve *eval(int _depth, int nworkers, struct worker *worker, int pick, 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 + 1, cur, depth - 1, pick, 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");
}
if (best) {
best->evalflow = max;
PAD3; log(3, "EVAL returning best [%s] eval=%d\n", best->val.str, max);
}
return best;
}
/**
* eval() - eval possible moves from @flow_sorted list.
* @_depth: recursivity depth (for debug only, TODO: remove).
* @valve: &starting valve (where we are).
* @depth: remaining depth (-1: full depth).
* @pick: max position (in @flow_sorted) to pick moves from (-1 for all).
* @time: remaining time.
* @pressure: total pressure per time unit so far.
*
* 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.
*/
static struct valve *eval2(int _depth, struct worker *worker, int pick, 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, worker->pos->index, worker->pos->val.str, worker->depth,
pick, worker->time, pressure);
list_for_each_safe(list_flow, tmp, &graph.flow_sorted) {
cur = list_entry(list_flow, struct valve, flow_sorted);
int d = DIST(worker->pos->index, cur->index),
remain = worker->time - (d + 1);
PAD4; log(4, "dist(%s,%s) = %d\n", worker->pos->val.str, cur->val.str, d);
if (!--_pick) {
PAD4; log(4, "pick exhausted\n");
continue;
}
if (remain < 1) {
PAD4; log(4, "time exhausted\n");
continue;
}
val = remain * cur->rate;
PAD4; log(4, "val=%d\n", val);
if (worker->depth > 0) {
struct worker w = {
.pos = cur,
.depth = worker->depth - 1,
.time = remain
};
/* do not use list_del() here, to preserve prev/next pointers */
__list_del_entry(list_flow);
sub = eval2(_depth + 1, &w, pick, pressure + worker->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, "eval2(%s->%s)= %5d = %d + %d", worker->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");
}
if (best) {
best->evalflow = max;
best->worker = 0; /* FIXME */
PAD3; log(3, "EVAL returning best [%s] worker=%d eval=%d\n", best->val.str,
best->worker, max);
}
return best;
}
/**
* eval() - eval possible moves from @flow_sorted list.
* @_depth: recursivity depth (for debug only, TODO: remove).
* @valve: &starting valve (where we are).
* @depth: remaining depth (-1: full depth).
* @pick: max position (in @flow_sorted) to pick moves from (-1 for all).
* @time: remaining time.
* @pressure: total pressure per time unit so far.
*
* 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.
*/
static struct valve *eval3(int _depth, struct worker *worker, int pick, int pressure)
{
struct valve *cur, *best = NULL, *sub;
struct list_head *list_flow, *tmp;
int _pick = pick, val = 0, val1, max = 0, bestworker;
int _pick = pick, val = 0, val1, max = 0, bestworker = -1;
int _nworkers = nworkers;
if (nworkers == 2 && worker[0].pos->index == worker[1].pos->index)
_nworkers = 1;
PAD3; log_f(3, "EVAL _depth=%d w0={ pos=%d[%s] depth=%d time=%d } w1={ pos=%d[%s] depth=%d time=%d } pick=%d pressure=%d \n",
_depth,
@@ -304,12 +162,12 @@ static struct valve *eval3(int _depth, struct worker *worker, int pick, int pres
pick, pressure);
list_for_each_safe(list_flow, tmp, &graph.flow_sorted) {
cur = list_entry(list_flow, struct valve, flow_sorted);
int nworkers = worker[0].pos->index == worker[1].pos->index? 1: 2;
//int nworkers = worker[0].pos->index == worker[1].pos->index? 1: 2;
if (!--_pick) {
PAD4; log(4, "pick exhausted\n");
break;
}
for (int _w = 0; _w < nworkers; ++_w) {
for (int _w = 0; _w < _nworkers; ++_w) {
struct worker *w = worker + _w;
int d = DIST(w->pos->index, cur->index);
int remain = w->time - (d + 1);
@@ -329,7 +187,7 @@ static struct valve *eval3(int _depth, struct worker *worker, int pick, int pres
w->time = remain;
/* do not use list_del() here, to preserve prev/next pointers */
__list_del_entry(list_flow);
sub = eval3(_depth + 1, worker, pick, pressure + w->pos->rate);
sub = eval(_depth + 1, nworkers, worker, pick, pressure + w->pos->rate);
list_flow->prev->next = list_flow;
list_flow->next->prev = list_flow;
*w = _tmp;
@@ -520,15 +378,15 @@ static void build_distances()
return;
}
static void print_played()
static void print_played(int nworkers)
{
struct valve *p;
int total = 0;
for (int w = 0; w < 2; ++w) {
for (int w = 0; w < nworkers; ++w) {
int remain = 26, i = 1;
struct valve *prev = graph.aa;
i = 1;
printf("played by %d:\n", w);
printf("played by %d/%d:\n", w + 1, nworkers);
list_for_each_entry(p, &graph.played[w], played) {
printf("%2d: %s, ", i, p->val.str);
remain -= DIST(p->index, prev->index) + 1;
@@ -542,59 +400,38 @@ static void print_played()
}
}
static void doit()
static int doit(int part)
{
struct worker w[2];
w[0].pos = w[1].pos = graph.aa;
w[0].depth = w[1].depth = 4;
w[0].time = w[1].time = 26;
/* struct worker w[2] = {
{ .pos = graph.aa, .depth = 5, .time = 30 },
{ .pos = graph.aa, .depth = 5, .time = 30 },
};
*/
struct valve *best;
int res = 0;
//int topick = part == 1? 7: 12;
int topick = part == 1? 12: 12;
//list_add_tail(&w[0].pos->played, &graph.played[0]);
//list_add_tail(&w[1].pos->played, &graph.played[1]);
//while ()
while ((best = eval3(0, w, 12, 0))) {
w[0].pos = w[1].pos = graph.aa;
//w[0].depth = w[1].depth = part == 1? 7: 4;
w[0].depth = w[1].depth = part == 1? 4: 4;
w[0].time = w[1].time = part == 1? 30: 26;
while ((best = eval(0, part, w, topick, 0))) {
list_del(&best->flow_sorted);
list_add_tail(&best->played, &graph.played[best->worker]);
w[best->worker].time -= DIST(w[best->worker].pos->index, best->index) + 1;
w[best->worker].pos = best;
print_played();
res += best->rate * w[best->worker].time;
print_played(part);
}
return res;
}
static ulong part1()
{
ulong res = 1;
struct worker w[2];
w[0].pos = w[1].pos = graph.aa;
w[0].depth = w[1].depth = 5;
w[0].time = w[1].time = 30;
printf("part 1\n");
eval(0, graph.aa, 7, 7, 30, 0);
eval2(0, &w[0], 4, 0);
return res;
return doit(1);
}
static ulong part2()
{
ulong res = 1;
//struct worker w = {
// .pos = graph.aa,
// .depth = 4,
// .time = 30
//};
printf("part 2\n");
//while ()
//eval2(0, &w, 7, 0);
doit();
return res;
return doit(2);
}
int main(int ac, char **av)