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