Compare commits

...

8 Commits

18 changed files with 1228 additions and 117 deletions

View File

@@ -309,9 +309,9 @@ aoc-c: res=25434
+++++++++++++++++ part 1
aoc-c: res=5176944
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+749
context-switch: 0+1, page-faults: 0+152
+++++++++++++++++ part 2
aoc-c: res=13350458933732
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+90
context-switch: 0+1, page-faults: 0+88

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2022, day 13
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2022, day 14
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2022, day 15
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
@@ -20,17 +20,13 @@
#include "br.h"
#include "list.h"
#include "pool.h"
#include "hashtable.h"
#include "pjwhash-inline.h"
#include "debug.h"
#include "aoc.h"
static pool_t *pool_segment, *pool_row, *pool_pair;
static pool_t *pool_segment, *pool_pair;
#define HBITS 20 /* 20 bits: 1,048,576 buckets */
static DEFINE_HASHTABLE(hasht_rows, HBITS);
struct coord {
int x, y;
};
@@ -39,6 +35,7 @@ struct coord {
#define RIGHT 1
#define BOTTOM 2
#define LEFT 3
/**
* struct pair - input file pair list
* @sensor, @beacon: struct coord sensor and beacon coordinates.
@@ -56,18 +53,6 @@ struct pair {
};
LIST_HEAD(pairs_head);
/**
* struct map - full map
* @min, @max: map's min and max coordinates.
* @hash: rows hash table
*/
struct map {
struct coord min, max;
struct hlist_head *hash;
} map = {
.min = { INT_MIN, INT_MIN }, .max = {INT_MAX, INT_MAX }, hasht_rows
};
/**
* struct row - row description
* @row: row number.
@@ -79,7 +64,20 @@ struct row {
int beacons[64];
int nbeacons;
struct list_head segments;
struct hlist_node hlist;
};
/**
* struct map - full map
* @min, @max: map's min and max coordinates.
* @hash: rows hash table
*/
static struct map {
struct coord min, max;
struct row row; /* for part 1 */
//hlist_head *hash;
} map = {
.min = { INT_MIN, INT_MIN }, .max = {INT_MAX, INT_MAX },
.row = { 0, {0}, 0, LIST_HEAD_INIT(map.row.segments) }
};
/**
@@ -104,15 +102,6 @@ struct segment {
struct list_head list;
};
static struct row *find_row(struct hlist_head *head, int row)
{
struct row *cur;
hlist_for_each_entry(cur, head, hlist)
if (cur->row == row)
return cur;
return NULL;
}
static struct segment *get_segment(int row, int start, int end)
{
struct segment *new = pool_get(pool_segment);
@@ -125,18 +114,18 @@ static struct segment *get_segment(int row, int start, int end)
return new;
}
static void merge_segment(struct row *prow, int start, int end)
static void merge_segment(int start, int end)
{
struct segment *seg, *new;
struct list_head *cur, *tmp;
static int l = 9;
new = get_segment(prow->row, start, end);
if (list_empty(&prow->segments)) {
list_add(&new->list, &prow->segments);
new = get_segment(map.row.row, start, end);
if (list_empty(&map.row.segments)) {
list_add(&new->list, &map.row.segments);
goto end;
}
list_for_each_safe(cur, tmp, &prow->segments) {
list_for_each_safe(cur, tmp, &map.row.segments) {
seg = list_entry(cur, struct segment, list);
/* 1) check for disjoint segments */
@@ -197,51 +186,24 @@ static void merge_segment(struct row *prow, int start, int end)
pool_add(pool_segment, seg);
goto end;
}
list_add_tail(&new->list, &prow->segments);
list_add_tail(&new->list, &map.row.segments);
end:
return;
}
static __always_inline void add_beacon(struct row *prow, int bx)
static __always_inline void add_beacon(int bx)
{
for (int i = 0; i < prow->nbeacons; ++i) {
if (prow->beacons[i] == bx)
for (int i = 0; i < map.row.nbeacons; ++i) {
if (map.row.beacons[i] == bx)
return;
}
prow->beacons[prow->nbeacons++] = bx;
}
static __always_inline struct row *add_segment(int row, int center, int half)
{
int x1, x2;
uint hash = row, bucket = hash_32(hash, HBITS);
struct row *prow = find_row(&map.hash[bucket], hash);
x1 = max(center - half, map.min.x);
x2 = min(center + half, map.max.x);
if (x1 != center - half || x2 != center + half)
log(1, "adjust x: min:%d->%d max:%d->%d\n",
center - half, x1, center + half, x2);
log_f(3, "adding segment (%d,%d) on row (%d) - bucket(%u) = %u prow=%p\n",
x1, x2, row, hash, bucket, prow);
log(3, "map borders: xmin=%d xmax=%d ymin=%d ymax=%d\n",
map.min.x, map.max.x, map.min.y, map.max.y);
if (!prow) {
prow = pool_get(pool_row);
prow->row = row;
prow->nbeacons = 0;
INIT_HLIST_NODE(&prow->hlist);
INIT_LIST_HEAD(&prow->segments);
hlist_add_head(&prow->hlist, &map.hash[bucket]);
}
merge_segment(prow, x1, x2);
return prow;
map.row.beacons[map.row.nbeacons++] = bx;
}
/**
* is_off_range() - test if a point is off range from all sensors.
*/
static int is_off_range(struct coord *point)
static __always_inline int is_off_range(struct coord *point)
{
struct pair *pair;
@@ -254,27 +216,6 @@ static int is_off_range(struct coord *point)
return 1;
}
static int add_segments(struct pair *pair)
{
int manhattan = pair->manhattan,
ymin = max(pair->sensor.y - manhattan, map.min.y),
ymax = min(pair->sensor.y + manhattan, map.max.y);
struct row *prow;
log_f(2, "sensor4=(%d, %d) beacon=(%d, %d) - ",
pair->sensor.x, pair->sensor.y, pair->beacon.x, pair->beacon.y);
log(2, "manhattan=%u ymin=%d ymax=%d\n", manhattan, ymin, ymax);
for (int y = ymin; y <= ymax; ++y) {
int half = pair->manhattan - abs(y - pair->sensor.y);
prow = add_segment(y, pair->sensor.x, half);
if (y == pair->beacon.y)
add_beacon(prow, pair->beacon.x);
}
return 1;
}
static struct pair *parse()
{
int ret;
@@ -354,9 +295,9 @@ static __always_inline struct coord *intersect(struct coord *p1, struct coord *p
b2 = q1->y - q1->x * a2;
/* Lines intersection (x,y) is at:
* (x * a1) + b1 = (x * a2) + b2
* (a1 * x) + b1 = (a2 * x) + b2
* x * (a1 - a2) = b2 - b1
* x = (b2 - b1) / (a1 - a2)
* x = (b2 - b1) / (a1 - a2) a2 ≠ a1
* Then we find y = ax + b
*/
x = (b2 - b1) / (a1 - a2);
@@ -366,10 +307,10 @@ static __always_inline struct coord *intersect(struct coord *p1, struct coord *p
* 1) Within p1-p2 and q1-q2 segments
* 2) Within map area
*/
if (x >= min(p1->x, p2->x) && x >= min(q1->x, q2->x) &&
x <= max(p1->x, p2->x) && x <= max(q1->x, q2->x) &&
y >= min(p1->y, p2->y) && y >= min(q1->y, q2->y) &&
y <= max(p1->y, p2->y) && y <= max(q1->y, q2->y) &&
if (x >= min(min(p1->x, p2->x), min(q1->x, q2->x)) &&
x <= max(max(p1->x, p2->x), max(q1->x, q2->x)) &&
y >= min(min(p1->y, p2->y), min(q1->y, q2->y)) &&
y <= max(max(p1->y, p2->y), max(q1->y, q2->y)) &&
x >= map.min.x && x <= map.max.x &&
y >= map.min.y && y <= map.max.y) {
*ret = (struct coord) {x, y};
@@ -417,22 +358,25 @@ static struct coord *check_intersect(struct coord *ret)
static u64 part1(void)
{
u64 res = 0;
int row = testmode() ? 10: 2000000;
uint bucket = hash_32(row, HBITS);
struct pair *pair;
struct segment *cur;
map.min.y = map.max.y = row;
map.row.row = map.min.y = map.max.y = testmode() ? 10: 2000000;
while ((pair = parse()))
add_segments(pair);
struct row *prow = find_row(&map.hash[bucket], row);
if (prow) {
struct segment *cur;
list_for_each_entry(cur, &prow->segments, list)
res += cur->end - cur->start + 1;
res -= prow->nbeacons;
while ((pair = parse())) {
if (map.row.row >= pair->sensor.y - pair->manhattan &&
map.row.row <= pair->sensor.y + pair->manhattan) {
int half = pair->manhattan - abs(map.row.row - pair->sensor.y);
int x1 = max(pair->sensor.x - half, map.min.x);
int x2 = max(pair->sensor.x + half, map.min.x);
merge_segment(x1, x2);
if (map.row.row == pair->beacon.y)
add_beacon(pair->beacon.x);
}
}
return res;
list_for_each_entry(cur, &map.row.segments, list)
res += cur->end - cur->start + 1;
return res - map.row.nbeacons;
}
static u64 part2()
@@ -454,12 +398,10 @@ int main(int ac, char **av)
{
int part = parseargs(ac, av);
pool_row = pool_create("rows", 8192, sizeof(struct row));
pool_segment = pool_create("segments", 8192, sizeof(struct segment));
pool_pair = pool_create("pair", 32, sizeof(struct pair));
printf("%s: res=%lu\n", *av, part == 1? part1(): part2());
pool_destroy(pool_row);
pool_destroy(pool_segment);
pool_destroy(pool_pair);
exit(0);

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Copyright (C) 2021-2023 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -178,6 +178,98 @@ with this valve layout, =1651=.
Work out the steps to release the most pressure in 30 minutes. /What is
the most pressure you can release?/
To begin, [[file:16/input][get your puzzle input]].
Your puzzle answer was =1737=.
Answer:
** --- 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?/
Your puzzle answer was =2216=.
Both parts of this puzzle are complete! They provide two gold stars: **

446
2022/day16/aoc-c.c Normal file
View File

@@ -0,0 +1,446 @@
/* aoc-c.c: Advent of Code 2022, day 16
*
* Copyright (C) 2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "br.h"
#include "list.h"
#include "pool.h"
#include "debug.h"
#include "bits.h"
#include "aoc.h"
pool_t *pool_valve;
union val {
u32 val;
char str[3];
};
enum state {
CLOSED,
OPENED
};
struct worker {
struct valve *pos;
int depth;
int time;
};
struct valve {
int index; /* -1 for zero flow rate */
union val val;
enum state state;
int rate;
int evalflow, evaltime;
int playedflow, playedtime;
struct hlist_node hlist;
struct list_head index_sorted;
struct list_head flow_sorted;
struct list_head eval;
int worker;
struct list_head played;
int ntunnels, tottunnels;
struct valve **tunnels; /* array */
};
static struct graph {
struct valve *aa; /* head ("AA") */
int npositive; /* only "AA" & working valves */
int nvalves;
u64 opened; /* bitmask of opened valves */
u64 openable; /* bitmask of openable valves */
struct list_head index_sorted; /* TO REMOVE ? */
struct list_head flow_sorted;
struct list_head eval;
struct list_head played[2];
struct valve **indexed_all;
int *dist; /* 2-D array */
} graph = {
.aa = NULL,
.npositive = 0,
.nvalves = 0,
.index_sorted = LIST_HEAD_INIT(graph.index_sorted),
.flow_sorted = LIST_HEAD_INIT(graph.flow_sorted),
.eval = LIST_HEAD_INIT(graph.eval),
.played[0] = LIST_HEAD_INIT(graph.played[0]),
.played[1] = LIST_HEAD_INIT(graph.played[1]),
.indexed_all = NULL,
.dist = NULL
};
#define POS(a, b) ((a)*graph.nvalves + (b))
#define DIST(a, b) (graph.dist[POS((a), (b))])
static void print_valves()
{
struct valve *cur;
printf("**** graph: .head=%p npositive=%d\n", graph.aa, graph.npositive);
printf("index1: ");
list_for_each_entry(cur, &graph.index_sorted, index_sorted) {
printf("%d:%s ", cur->index, cur->val.str);
}
printf("\n");
printf("index2: ");
for (int i = 0; i < graph.nvalves; ++i) {
printf("%d:%s ", graph.indexed_all[i]->index, graph.indexed_all[i]->val.str);
}
printf("\n");
if (testmode()) {
printf("distances:\n ");
for (int i = 0; i < graph.nvalves; ++i) {
printf(" %s", graph.indexed_all[i]->val.str);
}
printf("\n");
for (int i = 0; i < graph.nvalves; ++i) {
printf("%s ", graph.indexed_all[i]->val.str);
for (int j = 0; j < graph.nvalves; ++j) {
printf("%5d ", DIST(i, j));
}
printf("\n");
}
}
printf("flow_sorted: ");
list_for_each_entry(cur, &graph.flow_sorted, flow_sorted) {
printf("%s:%d ", cur->val.str, cur->rate);
}
printf("\n");
printf("openable: %#lx ", graph.openable);
int pos, tmp;
bit_for_each64_2(pos, tmp, graph.openable) {
printf("%d ", pos);
}
printf("\n");
}
#define PAD3 log(3, "%*s", _depth * 2, "")
#define PAD4 log(4, "%*s", _depth * 2, "")
/**
* eval() - eval possible moves from @flow_sorted list.
* @_depth: recursivity depth (for debug only, TODO: remove).
* @nworkers: number of workers.
* @workers: array of workers.
* @pick: max position (in @flow_sorted) to pick moves from (-1 for all).
* @pressure: total pressure per time unit so far.
*
* 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, 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, 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,
worker[0].pos->index, worker[0].pos->val.str,
worker[0].depth, worker[0].time,
worker[1].pos->index, worker[1].pos->val.str,
worker[1].depth, worker[1].time,
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;
if (!--_pick) {
PAD4; log(4, "pick exhausted\n");
break;
}
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);
PAD3; log(3, "worker %d/%d ", _w + 1, nworkers );
PAD3; log(3, "dist(%s,%s) = %d ", w->pos->val.str, cur->val.str, d);
if (remain < 1) {
PAD3; log(4, "time exhausted\n");
continue;
}
val = remain * cur->rate;
PAD3; log(3, "--> val=%d\n", val);
if (w->depth > 0) {
struct worker _tmp = *w;
w->pos = cur;
w->depth--;
w->time = remain;
/* do not use list_del() here, to preserve prev/next pointers */
__list_del_entry(list_flow);
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;
} else {
sub = NULL;
}
val1 = sub? sub->evalflow: 0;
PAD3; log(3, "eval3(%s->%s)= %5d = %d + %d", w->pos->val.str, cur->val.str,
val+val1, val, val1);
if (val + val1 > max) {
max = val + val1;
best = cur;
bestworker = _w;
log(3, " NEW MAX !");
}
log(3, "\n");
}
}
if (best) {
best->evalflow = max;
best->worker = bestworker; /* FIXME */
PAD3; log(3, "EVAL returning best [%s] worker=%d eval=%d\n", best->val.str,
best->worker, max);
}
return best;
}
static struct valve *find_valve(union val val, int ntunnels, int rate)
{
struct valve *cur;
log_f(3, "val=%s ntunnels=%d rate=%d\n", val.str, ntunnels, rate);
list_for_each_entry(cur, &graph.index_sorted, index_sorted) {
//log(3, "\tcomparing with found, addr=%p\n", cur);
if (cur->val.val == val.val) {
log(3, "\tfound, addr=%p\n", cur);
if (ntunnels)
goto init;
goto end;
}
}
cur = pool_get(pool_valve);
cur->val.val = val.val;
cur->ntunnels = 0;
cur->state = CLOSED;
cur->worker = -1;
cur->evalflow = cur->playedflow = 0;
cur->evaltime = cur->playedtime = 30;
INIT_LIST_HEAD(&cur->index_sorted);
INIT_LIST_HEAD(&cur->flow_sorted);
INIT_LIST_HEAD(&cur->eval);
INIT_LIST_HEAD(&cur->played);
log(3, "\talloc new, addr=%p\n", cur);
init:
if (ntunnels) {
cur->rate = rate;
cur->tottunnels = ntunnels;
cur->tunnels = calloc(ntunnels, sizeof(struct valve *));
}
end:
return cur;
}
/**
* nthtok - get nth token fron string.
* @buf: buffer to parse.
* @sep: separators string.
* @n: token number (0: first token).
*
* @Return: pointer to token.
*/
static char *nthtok(char *buf, const char *sep, int n)
{
char *ret;
for (; n >= 0; n--) {
ret = strtok(buf, sep);
buf = NULL;
}
return ret;
}
#define SEP " ,;="
static struct graph *parse()
{
int index = 0, ntunnels;
size_t alloc = 0;
ssize_t buflen;
char *buf = NULL, *tok;
int rate;
struct valve *v1, *v2;
union val cur, link;
while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
buf[--buflen] = 0;
/* valve name */
strncpy(cur.str, nthtok(buf, SEP, 1), sizeof(cur.str));
//printf("valve=%s ", tok);
rate = atoi(nthtok(NULL, SEP, 3));
//printf("rate=%s ", tok);
tok = nthtok(NULL, SEP, 4);
ntunnels = (buf + buflen - tok) / 4 + 1;
v1 = find_valve(cur, ntunnels, rate);
v1->index = index++;
// TODO: remove this list ?
list_add_tail(&v1->index_sorted, &graph.index_sorted);
graph.nvalves++;
//if (rate || v1->val.val == ('A' << 8 | 'A')) {
if (rate) {
struct valve *cur;
graph.npositive++;
/* keep this list sorted by flow decrasing */
list_for_each_entry(cur, &graph.flow_sorted, flow_sorted) {
if (rate > cur->rate) {
list_add_tail(&v1->flow_sorted, &cur->flow_sorted);
goto inserted;
}
}
list_add_tail(&v1->flow_sorted, &graph.flow_sorted);
inserted: ;
if (rate) {
//printf("adjust openable(%d): %#lx", v1->index, graph.openable);
graph.openable |= (1 << v1->index);
//printf("->%#lx", graph.openable);
}
}
//printf("lead=%s ntunnels=%d ", tok, ntunnels);
do {
link.val = *(u16 *)tok;
v2 = find_valve(link, 0, 0);
*(v1->tunnels + v1->ntunnels++) = v2;
//printf(",%s", tok);
} while ((tok = nthtok(NULL, SEP, 0)));
//printf("\n");
}
graph.aa = find_valve((union val) { .str="AA" }, 0, 0);
/* build array of indexed valves */
graph.indexed_all = calloc(graph.nvalves, sizeof(struct valve *));
list_for_each_entry(v1, &graph.index_sorted, index_sorted) {
graph.indexed_all[v1->index] = v1;
}
return &graph;
}
static int is_neighbour(int i, int j)
{
struct valve *v1 = graph.indexed_all[i], *v2 = graph.indexed_all[j];
for (int i = 0; i < v1->ntunnels; ++i)
if (v1->tunnels[i]->val.val == v2->val.val)
return 1;
return 0;
}
static void build_distances()
{
int i, j, k;
graph.dist = calloc(graph.nvalves * graph.nvalves, sizeof(int));
/* initialize values */
for (i = 0; i < graph.nvalves; ++i) {
for (j = 1; j < graph.nvalves; ++j) {
if (i != j) {
if (is_neighbour(i, j))
DIST(i, j) = DIST(j, i) = 1;
else
DIST(i, j) = DIST(j, i) = 10000;
}
}
}
/* get all distances using Floyd-Warshall
* see https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
*
* Add all vertices one by one to the set of intermediate vertices.
* ---> Before start of an iteration, we have shortest distances between all
* pairs of vertices such that the shortest distances consider only the
* vertices in set {0, 1, 2, .. k-1} as intermediate vertices.
* ----> After the end of an iteration, vertex no. k is added to the set of
* intermediate vertices and the set becomes {0, 1, 2, .. k}
*/
for (k = 0; k < graph.nvalves; k++) {
/* Pick all vertices as source one by one */
for (i = 0; i < graph.nvalves; i++) {
/* Pick all vertices as destination for the above picked source */
for (j = i + 1; j < graph.nvalves; j++)
DIST(i, j) = DIST(j, i) = min(DIST(i, j), DIST(i, k) + DIST(k, j));
}
}
return;
}
static void print_played(int nworkers)
{
struct valve *p;
int total = 0;
for (int w = 0; w < nworkers; ++w) {
int remain = 26, i = 1;
struct valve *prev = graph.aa;
i = 1;
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;
total += p->rate * remain;
printf("dist=%d remain=%d total=%d", DIST(p->index, prev->index), remain,
total);
printf("\n");
i++;
prev = p;
}
}
}
static int doit(int part)
{
struct worker w[2];
struct valve *best;
int res = 0;
//int topick = part == 1? 7: 12;
int topick = part == 1? 12: 12;
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;
res += best->rate * w[best->worker].time;
print_played(part);
}
return res;
}
static ulong part1()
{
return doit(1);
}
static ulong part2()
{
return doit(2);
}
int main(int ac, char **av)
{
int part = parseargs(ac, av);
pool_valve = pool_create("valve", 512, sizeof(struct valve));
parse();
build_distances();
print_valves();
printf("%s: res=%lu\n", *av, part == 1? part1(): part2());
exit(0);
}

View File

@@ -1,6 +1,6 @@
/* aoc.c: Advent of Code 2022
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -2,7 +2,7 @@
#
# common.bash: Advent of Code 2022, common bash functions
#
# Copyright (C) 2022 Bruno Raoult ("br")
# Copyright (C) 2022-2023 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* common.c: Advent of Code 2022, common functions
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

111
2022/day17/Makefile Normal file
View File

@@ -0,0 +1,111 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2023 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := input/input.txt
SHELL := /bin/bash
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 part1 part2 ccls bear org
all: README.org ccls part1 part2
memcheck: memcheck1 memcheck2
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
part1: aoc-c
@#$(TIME) aoc.bash -p 1 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 1 < $(INPUT)
part2: aoc-c
@#$(TIME) aoc.bash -p 2 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
aoc-c: aoc-c.c common.c
@echo compiling $<
$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $^ $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
org: README.org
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@touch .ccls-root
@$(BEAR) -- make compile

374
2022/day17/README.org Normal file
View File

@@ -0,0 +1,374 @@
** --- Day 17: Pyroclastic Flow ---
Your handheld device has located an alternative exit from the cave for
you and the elephants. The ground is rumbling almost continuously now,
but the strange valves bought you some time. It's definitely getting
warmer in here, though.
The tunnels eventually open into a very tall, narrow chamber. Large,
oddly-shaped rocks are falling into the chamber from above, presumably
due to all the rumbling. If you can't work out where the rocks will fall
next, you might be crushed!
The five types of rocks have the following peculiar shapes, where =#= is
rock and =.= is empty space:
#+begin_example
####
.#.
###
.#.
..#
..#
###
#
#
#
#
##
##
#+end_example
The rocks fall in the order shown above: first the =-= shape, then the
=+= shape, and so on. Once the end of the list is reached, the same
order repeats: the =-= shape falls first, sixth, 11th, 16th, etc.
The rocks don't spin, but they do get pushed around by jets of hot gas
coming out of the walls themselves. A quick scan reveals the effect the
jets of hot gas will have on the rocks as they fall (your puzzle input).
For example, suppose this was the jet pattern in your cave:
#+begin_example
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
#+end_example
In jet patterns, =<= means a push to the left, while =>= means a push to
the right. The pattern above means that the jets will push a falling
rock right, then right, then right, then left, then left, then right,
and so on. If the end of the list is reached, it repeats.
The tall, vertical chamber is exactly /seven units wide/. Each rock
appears so that its left edge is two units away from the left wall and
its bottom edge is three units above the highest rock in the room (or
the floor, if there isn't one).
After a rock appears, it alternates between /being pushed by a jet of
hot gas/ one unit (in the direction indicated by the next symbol in the
jet pattern) and then /falling one unit down/. If any movement would
cause any part of the rock to move into the walls, floor, or a stopped
rock, the movement instead does not occur. If a /downward/ movement
would have caused a falling rock to move into the floor or an
already-fallen rock, the falling rock stops where it is (having landed
on something) and a new rock immediately begins falling.
Drawing falling rocks with =@= and stopped rocks with =#=, the jet
pattern in the example above manifests as follows:
#+begin_example
The first rock begins falling:
|..@@@@.|
|.......|
|.......|
|.......|
+-------+
Jet of gas pushes rock right:
|...@@@@|
|.......|
|.......|
|.......|
+-------+
Rock falls 1 unit:
|...@@@@|
|.......|
|.......|
+-------+
Jet of gas pushes rock right, but nothing happens:
|...@@@@|
|.......|
|.......|
+-------+
Rock falls 1 unit:
|...@@@@|
|.......|
+-------+
Jet of gas pushes rock right, but nothing happens:
|...@@@@|
|.......|
+-------+
Rock falls 1 unit:
|...@@@@|
+-------+
Jet of gas pushes rock left:
|..@@@@.|
+-------+
Rock falls 1 unit, causing it to come to rest:
|..####.|
+-------+
A new rock begins falling:
|...@...|
|..@@@..|
|...@...|
|.......|
|.......|
|.......|
|..####.|
+-------+
Jet of gas pushes rock left:
|..@....|
|.@@@...|
|..@....|
|.......|
|.......|
|.......|
|..####.|
+-------+
Rock falls 1 unit:
|..@....|
|.@@@...|
|..@....|
|.......|
|.......|
|..####.|
+-------+
Jet of gas pushes rock right:
|...@...|
|..@@@..|
|...@...|
|.......|
|.......|
|..####.|
+-------+
Rock falls 1 unit:
|...@...|
|..@@@..|
|...@...|
|.......|
|..####.|
+-------+
Jet of gas pushes rock left:
|..@....|
|.@@@...|
|..@....|
|.......|
|..####.|
+-------+
Rock falls 1 unit:
|..@....|
|.@@@...|
|..@....|
|..####.|
+-------+
Jet of gas pushes rock right:
|...@...|
|..@@@..|
|...@...|
|..####.|
+-------+
Rock falls 1 unit, causing it to come to rest:
|...#...|
|..###..|
|...#...|
|..####.|
+-------+
A new rock begins falling:
|....@..|
|....@..|
|..@@@..|
|.......|
|.......|
|.......|
|...#...|
|..###..|
|...#...|
|..####.|
+-------+
#+end_example
The moment each of the next few rocks begins falling, you would see
this:
#+begin_example
|..@....|
|..@....|
|..@....|
|..@....|
|.......|
|.......|
|.......|
|..#....|
|..#....|
|####...|
|..###..|
|...#...|
|..####.|
+-------+
|..@@...|
|..@@...|
|.......|
|.......|
|.......|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|..@@@@.|
|.......|
|.......|
|.......|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|...@...|
|..@@@..|
|...@...|
|.......|
|.......|
|.......|
|.####..|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|....@..|
|....@..|
|..@@@..|
|.......|
|.......|
|.......|
|..#....|
|.###...|
|..#....|
|.####..|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|..@....|
|..@....|
|..@....|
|..@....|
|.......|
|.......|
|.......|
|.....#.|
|.....#.|
|..####.|
|.###...|
|..#....|
|.####..|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|..@@...|
|..@@...|
|.......|
|.......|
|.......|
|....#..|
|....#..|
|....##.|
|....##.|
|..####.|
|.###...|
|..#....|
|.####..|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
|..@@@@.|
|.......|
|.......|
|.......|
|....#..|
|....#..|
|....##.|
|##..##.|
|######.|
|.###...|
|..#....|
|.####..|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+
#+end_example
To prove to the elephants your simulation is accurate, they want to know
how tall the tower will get after 2022 rocks have stopped (but before
the 2023rd rock begins falling). In this example, the tower of rocks
will be =3068= units tall.
/How many units tall will the tower of rocks be after 2022 rocks have
stopped falling?/

17
2022/day17/aoc.h Normal file
View File

@@ -0,0 +1,17 @@
/* aoc.c: Advent of Code 2022
*
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#ifndef _AOC_H_
#define _AOC_H_
extern int parseargs(int ac, char**av);
extern int testmode(void);
#endif /* _AOC_H_ */

68
2022/day17/common.bash Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
#
# common.bash: Advent of Code 2022, common bash functions
#
# Copyright (C) 2022-2023 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
# shellcheck disable=2034
export cmdname=${0##*/}
export debug=0
export res
export LANG=C
shopt -s extglob
set -o noglob
usage() {
printf "usage: %s [-d DEBUG] [-p PART]\n" "$cmdname"
exit 1
}
checkargs() {
local part=1
while getopts p:d: todo; do
case "$todo" in
d)
if [[ "$OPTARG" =~ ^[[:digit:]+]$ ]]; then
debug="$OPTARG"
else
printf "%s: illegal [%s] debug level.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
p)
if [[ "$OPTARG" =~ ^[12]$ ]]; then
part="$OPTARG"
else
printf "%s: illegal [%s] part.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
*)
usage
;;
esac
done
# Now check remaining argument (backup directory)
shift $((OPTIND - 1))
(( $# > 1 )) && usage
return "$part"
}
main() {
local -i part
checkargs "$@"
part=$?
parse "$part"
solve "$part"
printf "%s: res=%s\n" "$cmdname" "$res"
}

59
2022/day17/common.c Normal file
View File

@@ -0,0 +1,59 @@
/* common.c: Advent of Code 2022, common functions
*
* Copyright (C) 2022-2023 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "aoc.h"
#include "debug.h"
static int _testmode = 0;
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-t][-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int testmode(void)
{
return _testmode;
}
int parseargs(int ac, char **av)
{
int opt, part = 1;
while ((opt = getopt(ac, av, "td:p:")) != -1) {
switch (opt) {
case 't':
_testmode = 1;
break;
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
return usage(*av);
break;
case 'i':
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
return part;
}

View File

@@ -0,0 +1 @@
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>

File diff suppressed because one or more lines are too long