Compare commits
14 Commits
0a3b404c4c
...
main
Author | SHA1 | Date | |
---|---|---|---|
ad6a39e82a | |||
3a857e4d53 | |||
f80a051177 | |||
129fa07787 | |||
1472082c86 | |||
e8bed49e13 | |||
83d70dcc7a | |||
56d2e63fac | |||
5c91de5d40 | |||
40a9c7b12e | |||
34b6cd7b57 | |||
5ad5c87fd8 | |||
11e7b45676 | |||
3f2a5648df |
@@ -301,3 +301,17 @@ aoc-c: res=665
|
||||
aoc-c: res=25434
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+121
|
||||
|
||||
=========================================
|
||||
================= day15 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c: res=5176944
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
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+88
|
||||
|
@@ -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.
|
||||
*
|
||||
|
@@ -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.
|
||||
*
|
||||
|
@@ -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,30 +20,38 @@
|
||||
#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;
|
||||
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;
|
||||
};
|
||||
|
||||
#define TOP 0
|
||||
#define RIGHT 1
|
||||
#define BOTTOM 2
|
||||
#define LEFT 3
|
||||
|
||||
/**
|
||||
* struct map - full map
|
||||
* @xmin, @xmax: most left/right x-coordinates.
|
||||
* @ymin, @ymax: most top/bottom y-coordinates.
|
||||
* @hash: rows hash table
|
||||
* struct pair - input file pair list
|
||||
* @sensor, @beacon: struct coord sensor and beacon coordinates.
|
||||
* @manhattan: manhattan distance between sensor and beacon.
|
||||
* @parity: beacon coordinates parity (as bishop color in chess).
|
||||
* @corners: coordinates of rhombus immediately out of sensor range (clockwise).
|
||||
* @list: list of pairs.
|
||||
*/
|
||||
struct map {
|
||||
int xmin, xmax, ymin, ymax;
|
||||
struct hlist_head *hash;
|
||||
} map = {
|
||||
//INT_MAX, INT_MIN, INT_MAX, INT_MIN, hasht_rows
|
||||
INT_MIN, INT_MAX, INT_MIN, INT_MAX, hasht_rows
|
||||
struct pair {
|
||||
struct coord sensor, beacon;
|
||||
int manhattan;
|
||||
int parity;
|
||||
struct coord corners[4];
|
||||
struct list_head list;
|
||||
};
|
||||
LIST_HEAD(pairs_head);
|
||||
|
||||
/**
|
||||
* struct row - row description
|
||||
@@ -56,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) }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -81,121 +102,48 @@ 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 void print_segments()
|
||||
{
|
||||
struct row *prow;
|
||||
struct segment *s;
|
||||
|
||||
//log_f(1, "xmin=%d xmax=%d\n", map.xmin, map.xmax);
|
||||
if (! testmode())
|
||||
return;
|
||||
|
||||
for (int y = -3; y <= 22; ++y) {
|
||||
if ((prow = find_row(&map.hash[hash_32(y, HBITS)], y))) {
|
||||
log(1, "%2d ", y);
|
||||
log(5, "prow(%d->%d)=%p\n", y, hash_32(y, HBITS), prow);
|
||||
int count = 0;
|
||||
list_for_each_entry(s, &prow->segments, list) {
|
||||
log(1, "%s (%d,%d)", count? " -> ":"", s->start, s->end);
|
||||
}
|
||||
log(1, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_map() /* for test mode only */
|
||||
{
|
||||
struct row *prow;
|
||||
struct segment *s;
|
||||
|
||||
//log_f(1, "xmin=%d xmax=%d\n", map.xmin, map.xmax);
|
||||
if (! testmode())
|
||||
return;
|
||||
log(1, " - 1 1 2 2 3\n");
|
||||
log(1, " 5 0 5 0 5 0 5 0\n");
|
||||
|
||||
for (int y = -3; y <= 22; ++y) {
|
||||
if ((prow = find_row(&map.hash[hash_32(y, HBITS)], y))) {
|
||||
log(1, "%2d ", y);
|
||||
log(5, "prow(%d->%d)=%p\n", y, hash_32(y, HBITS), prow);
|
||||
int x = -6;
|
||||
list_for_each_entry(s, &prow->segments, list) {
|
||||
//log_f(1, "segment start=%d end=%d\n", s->start, s->end);
|
||||
for (; x <= 30 && x < s->start; ++x) {
|
||||
log(1, ".");
|
||||
}
|
||||
for (; x <= 30 && x <= s->end; ++x) {
|
||||
log(1, "#");
|
||||
}
|
||||
}
|
||||
for (; x <= 30; ++x) {
|
||||
log(1, ".");
|
||||
}
|
||||
log(1, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct segment *get_segment(int row, int x1, int x2)
|
||||
static struct segment *get_segment(int row, int start, int end)
|
||||
{
|
||||
struct segment *new = pool_get(pool_segment);
|
||||
|
||||
log_f(5, "alloc segment (%d,%d) on row (%d)\n", x1, x2, row);
|
||||
log_f(5, "alloc segment (%d,%d) on row (%d)\n", start, end, row);
|
||||
new->row=row;
|
||||
new->start=x1;
|
||||
new->end=x2;
|
||||
new->start=start;
|
||||
new->end=end;
|
||||
INIT_LIST_HEAD(&new->list);
|
||||
return new;
|
||||
}
|
||||
|
||||
static int 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;
|
||||
int l;
|
||||
static int l = 9;
|
||||
|
||||
l = debug_level_get();
|
||||
//if (prow->row != 9)
|
||||
l++;
|
||||
|
||||
log_f(l, "merging segment (%d,%d) on row (%d)\n", start, end, prow->row);
|
||||
new = get_segment(prow->row, start, end);
|
||||
if (list_empty(&prow->segments)) {
|
||||
log_f(l, " first segment\n");
|
||||
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);
|
||||
log_f(l, "compare to (start=%d end=%d)\n", seg->start, seg->end);
|
||||
|
||||
/* 1) check for disjoint segments */
|
||||
if (start > seg->end + 1) {
|
||||
log_f(l, " skipping (%d,%d)\n", seg->start, seg->end);
|
||||
continue;
|
||||
}
|
||||
if (end < seg->start - 1) {
|
||||
log_f(l, " adding before (%d,%d)\n", seg->start, seg->end);
|
||||
list_add_tail(&new->list, &seg->list);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* new is inside cur: do nothing */
|
||||
/* 2) new is inside cur: do nothing */
|
||||
if (start >= seg->start && end <= seg->end) {
|
||||
log_f(l, " overlap IN, do nothing\n");
|
||||
pool_add(pool_segment, new);
|
||||
goto end;
|
||||
}
|
||||
/* cur inside new: remove cur */
|
||||
/* 3) cur inside new: remove cur */
|
||||
if (start <= seg->start && end >= seg->end) {
|
||||
log_f(l, " overlap OUT, remove current\n");
|
||||
// TODO: avoid this
|
||||
@@ -204,219 +152,257 @@ static int merge_segment(struct row *prow, int start, int end)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 2) adjacent block */
|
||||
/* 4) new segment start is within current one */
|
||||
if (start >= seg->start && start <= seg->end + 1) {
|
||||
log_f(l, " setting new start to %d\n", seg->start);
|
||||
new->start = seg->start;
|
||||
list_del(cur);
|
||||
pool_add(pool_segment, seg);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 5) new segment is left-adjacent to current */
|
||||
if (end == seg->start - 1) {
|
||||
seg->start = start;
|
||||
pool_add(pool_segment, new);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* we know here there is at least one overlap or contiguous */
|
||||
log_f(l, " could merge new=(%d,%d) with cur=(%d,%d)\n",
|
||||
start, end, seg->start, seg->end);
|
||||
/* from here, we know there is an overlap */
|
||||
|
||||
/* exactly one overlap */
|
||||
log_f(3, " exactly one overlap\n");
|
||||
|
||||
if (start >= seg->start) {
|
||||
log_f(l, " overlap left new=(%d,%d)\n", new->start, new->end);
|
||||
/* 6) adjust new start to current start */
|
||||
if (start >= seg->start)
|
||||
new->start = seg->start;
|
||||
}
|
||||
|
||||
/* 7) remove current if covered by new */
|
||||
if (end >= seg->end){
|
||||
log_f(l, " overlap right: delete cur\n");
|
||||
list_del(cur);
|
||||
pool_add(pool_segment, seg);
|
||||
continue;
|
||||
}
|
||||
/* we stop here */
|
||||
log_f(l, " stop here\n");
|
||||
/* 8) replace current with new - finished */
|
||||
new->end = seg->end;
|
||||
list_add_tail(&new->list, cur);
|
||||
list_del(cur);
|
||||
pool_add(pool_segment, seg);
|
||||
goto end;
|
||||
}
|
||||
log_f(l, " adding at end of list\n");
|
||||
list_add_tail(&new->list, &prow->segments);
|
||||
list_add_tail(&new->list, &map.row.segments);
|
||||
end:
|
||||
//print_segments();
|
||||
return 10;
|
||||
}
|
||||
|
||||
static void add_beacon(int bx, int by)
|
||||
{
|
||||
uint hash = by, bucket = hash_32(hash, HBITS);
|
||||
struct row *prow = find_row(&map.hash[bucket], hash);
|
||||
|
||||
if (!prow) {
|
||||
puts("fuck)");
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < prow->nbeacons; ++i) {
|
||||
if (prow->beacons[i] == bx)
|
||||
return;
|
||||
}
|
||||
prow->beacons[prow->nbeacons++] = bx;
|
||||
|
||||
static __always_inline void add_beacon(int bx)
|
||||
{
|
||||
for (int i = 0; i < map.row.nbeacons; ++i) {
|
||||
if (map.row.beacons[i] == bx)
|
||||
return;
|
||||
}
|
||||
map.row.beacons[map.row.nbeacons++] = bx;
|
||||
}
|
||||
|
||||
static int 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.xmin);
|
||||
x2 = min(center + half, map.xmax);
|
||||
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);
|
||||
/*
|
||||
* if (row < map.ymin) {
|
||||
* log(5, "new ymin=%d->%d\n", map.ymin, row);
|
||||
* map.ymin = row;
|
||||
* }
|
||||
* if (row > map.ymax) {
|
||||
* log(5, "new ymax=%d->%d\n", map.ymax, row);
|
||||
* map.ymax = row;
|
||||
* }
|
||||
* if (x1 < map.xmin) {
|
||||
* log(5, "new xmin=%d->%d\n", map.xmin, x1);
|
||||
* map.xmin = x1;
|
||||
* }
|
||||
* if (x2 > map.xmax) {
|
||||
* log(5, "new xmax=%d->%d\n", map.xmax, x2);
|
||||
* map.xmax = x2;
|
||||
* }
|
||||
/**
|
||||
* is_off_range() - test if a point is off range from all sensors.
|
||||
*/
|
||||
log(3, "map borders: xmin=%d xmax=%d ymin=%d ymax=%d\n",
|
||||
map.xmin, map.xmax, map.ymin, map.ymax);
|
||||
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]);
|
||||
static __always_inline int is_off_range(struct coord *point)
|
||||
{
|
||||
struct pair *pair;
|
||||
|
||||
/* reverse loop, because higher manhattan means higher chances to fail */
|
||||
list_for_each_entry_reverse(pair, &pairs_head, list) {
|
||||
if ((abs(point->x - pair->sensor.x) +
|
||||
abs(point->y - pair->sensor.y)) <= pair->manhattan)
|
||||
return 0;
|
||||
}
|
||||
merge_segment(prow, x1, x2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int add_segments(int sx, int sy, int bx, int by)
|
||||
static struct pair *parse()
|
||||
{
|
||||
int manhattan = abs(bx - sx) + abs(by - sy);
|
||||
int ymin = max(sy - manhattan, map.ymin);
|
||||
int ymax = min(sy + manhattan, map.ymax);
|
||||
int ret;
|
||||
struct pair *pair = NULL, *cur;
|
||||
struct coord sensor, beacon;
|
||||
|
||||
log_f(2, "sensor4=(%d, %d) beacon=(%d, %d) - ", sx, sy, bx, by);
|
||||
log(2, "manhattan=%u ymin=%d ymax=%d\n", manhattan, ymin, ymax);
|
||||
//add_segment(sy, sx, manhattan);
|
||||
ret = scanf("%*[^-0-9]%d%*[^-0-9]%d%*[^-0-9]%d%*[^-0-9]%d",
|
||||
&sensor.x, &sensor.y, &beacon.x, &beacon.y);
|
||||
if (ret == 4) {
|
||||
pair = pool_get(pool_pair);
|
||||
pair->sensor = sensor;
|
||||
pair->beacon = beacon;
|
||||
pair->manhattan = abs(beacon.x - sensor.x) + abs(beacon.y - sensor.y);
|
||||
pair->parity = (pair->beacon.x + pair->beacon.y) % 2;
|
||||
pair->corners[TOP] = (struct coord) {
|
||||
sensor.x, sensor.y - pair->manhattan - 1
|
||||
};
|
||||
pair->corners[BOTTOM] = (struct coord) {
|
||||
sensor.x, sensor.y + pair->manhattan + 1
|
||||
};
|
||||
pair->corners[RIGHT] = (struct coord) {
|
||||
sensor.x + pair->manhattan + 1, sensor.y
|
||||
};
|
||||
pair->corners[LEFT] = (struct coord) {
|
||||
sensor.x - pair->manhattan - 1, sensor.y
|
||||
};
|
||||
|
||||
for (int y = ymin; y <= ymax; ++y) {
|
||||
int half = manhattan - abs(y - sy);
|
||||
add_segment(y, sx, half);
|
||||
if (y == by)
|
||||
add_beacon(bx, by);
|
||||
//add_segment(y, sx, half);
|
||||
/* keep list ordered by manhattan */
|
||||
if (!list_empty(&pairs_head)) {
|
||||
list_for_each_entry(cur, &pairs_head, list) {
|
||||
if (cur->manhattan > pair->manhattan) {
|
||||
list_add_tail(&pair->list, &cur->list);
|
||||
goto end;
|
||||
}
|
||||
//for (int dy = 1, half = manhattan - 1; dy <= manhattan; ++dy, half--) {
|
||||
// add_segment(sy - dy, sx, half);
|
||||
// add_segment(sy + dy, sx, half);
|
||||
//}
|
||||
//add_beacon(bx, by);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
list_add_tail(&pair->list, &pairs_head);
|
||||
}
|
||||
end:
|
||||
return pair;
|
||||
}
|
||||
|
||||
static inline int parse(int *sx, int *sy, int *bx, int *by)
|
||||
{
|
||||
int ret = scanf("%*[^-0-9]%d%*[^-0-9]%d%*[^-0-9]%d%*[^-0-9]%d",
|
||||
sx, sy, bx, by);
|
||||
/**
|
||||
* /#\
|
||||
* /#\ /# #\
|
||||
* /# #\ /# #\
|
||||
* /# #\O/# <--- O is a possible point
|
||||
* #X#
|
||||
* rhomb A /#\ rhom B
|
||||
* /# #\
|
||||
* /# #\
|
||||
* /# #\
|
||||
* /# #\
|
||||
* /# rhombs #\
|
||||
* A & B
|
||||
* (intersection)
|
||||
*/
|
||||
|
||||
/**
|
||||
* intersect() - find intersection of two segments
|
||||
*
|
||||
*/
|
||||
static __always_inline struct coord *intersect(struct coord *p1, struct coord *p2,
|
||||
struct coord *q1, struct coord *q2,
|
||||
struct coord *ret)
|
||||
{
|
||||
int a1, a2, b1, b2, x, y;
|
||||
|
||||
/* a1, b1, a2, b2 are the formulas of (p1, p2) and (q1, q2), such as:
|
||||
* y = ax + b
|
||||
* a = (y2 - y1) / (x2 - x1) x2 ≠ x1
|
||||
* b = y - a * x We can take either p1 or p2 coordinates
|
||||
*/
|
||||
a1 = (p2->y - p1->y) / (p2->x - p1->x);
|
||||
b1 = p1->y - p1->x * a1;
|
||||
a2 = (q2->y - q1->y) / (q2->x - q1->x);
|
||||
b2 = q1->y - q1->x * a2;
|
||||
|
||||
/* Lines intersection (x,y) is at:
|
||||
* (a1 * x) + b1 = (a2 * x) + b2
|
||||
* x * (a1 - a2) = b2 - b1
|
||||
* x = (b2 - b1) / (a1 - a2) a2 ≠ a1
|
||||
* Then we find y = ax + b
|
||||
*/
|
||||
x = (b2 - b1) / (a1 - a2);
|
||||
y = a1 * x + b1;
|
||||
|
||||
/* check if intersection is:
|
||||
* 1) Within p1-p2 and q1-q2 segments
|
||||
* 2) Within map area
|
||||
*/
|
||||
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};
|
||||
} else {
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ulong part1()
|
||||
{
|
||||
ulong res = 0;
|
||||
int row = testmode() ? 10: 2000000;
|
||||
uint bucket = hash_32(row, HBITS);
|
||||
int sx, sy, bx, by;
|
||||
#define T_R(p) &p->corners[TOP], &p->corners[RIGHT]
|
||||
#define R_B(p) &p->corners[RIGHT], &p->corners[BOTTOM]
|
||||
#define B_L(p) &p->corners[BOTTOM], &p->corners[LEFT]
|
||||
#define L_T(p) &p->corners[LEFT], &p->corners[TOP]
|
||||
|
||||
map.ymin = row - 1;
|
||||
map.ymax = row + 1;
|
||||
while (parse(&sx, &sy, &bx, &by) > 0) {
|
||||
int manhattan = abs(bx - sx) + abs(by - sy);
|
||||
add_segments(sx, sy, bx, by);
|
||||
log(3, "m=%d : ", manhattan);
|
||||
static struct coord *check_intersect(struct coord *ret)
|
||||
{
|
||||
struct pair *pair, *second;
|
||||
|
||||
list_for_each_entry(pair, &pairs_head, list) {
|
||||
second = list_prepare_entry(pair, &pairs_head, list);
|
||||
list_for_each_entry_continue(second, &pairs_head, list) {
|
||||
if (second->parity == pair->parity) {
|
||||
/* top right segment */
|
||||
if ((intersect(T_R(pair), R_B(second), ret) && is_off_range(ret)) ||
|
||||
(intersect(T_R(pair), L_T(second), ret) && is_off_range(ret)))
|
||||
return ret;
|
||||
/* bottom left segment */
|
||||
if ((intersect(B_L(pair), R_B(second), ret) && is_off_range(ret)) ||
|
||||
(intersect(B_L(pair), L_T(second), ret) && is_off_range(ret)))
|
||||
return ret;
|
||||
/* right bottom segment */
|
||||
if ((intersect(R_B(pair), T_R(second), ret) && is_off_range(ret)) ||
|
||||
(intersect(R_B(pair), B_L(second), ret) && is_off_range(ret)))
|
||||
return ret;
|
||||
/* left top segment */
|
||||
if ((intersect(L_T(pair), T_R(second), ret) && is_off_range(ret)) ||
|
||||
(intersect(L_T(pair), B_L(second), ret) && is_off_range(ret)))
|
||||
return ret;
|
||||
}
|
||||
struct row *prow = find_row(&map.hash[bucket], row);
|
||||
if (prow) {
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u64 part1(void)
|
||||
{
|
||||
u64 res = 0;
|
||||
struct pair *pair;
|
||||
struct segment *cur;
|
||||
print_map();
|
||||
list_for_each_entry(cur, &prow->segments, list) {
|
||||
printf("counting segment (%d,%d) = %d nbeac=%d\n", cur->start, cur->end,
|
||||
cur->end - cur->start + 1, prow->nbeacons);
|
||||
|
||||
map.row.row = map.min.y = map.max.y = testmode() ? 10: 2000000;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
list_for_each_entry(cur, &map.row.segments, list)
|
||||
res += cur->end - cur->start + 1;
|
||||
}
|
||||
res -= prow->nbeacons;
|
||||
}
|
||||
return res;
|
||||
return res - map.row.nbeacons;
|
||||
}
|
||||
|
||||
static ulong part2()
|
||||
static u64 part2()
|
||||
{
|
||||
ulong res = 0;
|
||||
int sx, sy, bx, by;
|
||||
u64 res = 0;
|
||||
struct coord result = {0, 0};
|
||||
|
||||
map.xmin = map.ymin = 0;
|
||||
map.xmax = map.ymax = testmode()? 20: 4000000;
|
||||
while ((parse(&sx, &sy, &bx, &by)) > 0) {
|
||||
int manhattan = abs(bx - sx) + abs(by - sy);
|
||||
map.min.x = map.min.y = 0;
|
||||
map.max.x = map.max.y = testmode()? 20: 4000000;
|
||||
|
||||
add_segments(sx, sy, bx, by);
|
||||
log(3, "m=%d : ", manhattan);
|
||||
}
|
||||
for (int row = map.ymin; row <= map.ymax; ++row) {
|
||||
uint bucket = hash_32(row, HBITS);
|
||||
struct row *prow = find_row(&map.hash[bucket], row);
|
||||
if (!prow) {
|
||||
printf("fuck 1: prow(%d)=NULL\n", row);
|
||||
exit(1);
|
||||
}
|
||||
struct segment *cur;
|
||||
if (list_empty(&prow->segments)) {
|
||||
puts("fuck 2\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
cur = list_first_entry(&prow->segments, struct segment, list);
|
||||
if (cur->end != map.xmax) {
|
||||
res = ((u64)cur->end + 1UL) * 4000000UL + (u64)row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (parse())
|
||||
;
|
||||
check_intersect(&result);
|
||||
res = ((u64)result.x) * 4000000UL + (u64)result.y;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
111
2022/day16/Makefile
Normal file
111
2022/day16/Makefile
Normal 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
|
275
2022/day16/README.org
Normal file
275
2022/day16/README.org
Normal file
@@ -0,0 +1,275 @@
|
||||
** --- Day 16: Proboscidea Volcanium ---
|
||||
The sensors have led you to the origin of the distress signal: yet
|
||||
another handheld device, just like the one the Elves gave you. However,
|
||||
you don't see any Elves around; instead, the device is surrounded by
|
||||
elephants! They must have gotten lost in these tunnels, and one of the
|
||||
elephants apparently figured out how to turn on the distress signal.
|
||||
|
||||
The ground rumbles again, much stronger this time. What kind of cave is
|
||||
this, exactly? You scan the cave with your handheld device; it reports
|
||||
mostly igneous rock, some ash, pockets of pressurized gas, magma... this
|
||||
isn't just a cave, it's a volcano!
|
||||
|
||||
You need to get the elephants out of here, quickly. Your device
|
||||
estimates that you have /30 minutes/ before the volcano erupts, so you
|
||||
don't have time to go back out the way you came in.
|
||||
|
||||
You scan the cave for other options and discover a network of pipes and
|
||||
pressure-release /valves/. You aren't sure how such a system got into a
|
||||
volcano, but you don't have time to complain; your device produces a
|
||||
report (your puzzle input) of each valve's /flow rate/ if it were opened
|
||||
(in pressure per minute) and the tunnels you could use to move between
|
||||
the valves.
|
||||
|
||||
There's even a valve in the room you and the elephants are currently
|
||||
standing in labeled =AA=. You estimate it will take you one minute to
|
||||
open a single valve and one minute to follow any tunnel from one valve
|
||||
to another. What is the most pressure you could release?
|
||||
|
||||
For example, suppose you had the following scan output:
|
||||
|
||||
#+begin_example
|
||||
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||
Valve JJ has flow rate=21; tunnel leads to valve II
|
||||
#+end_example
|
||||
|
||||
All of the valves begin /closed/. You start at valve =AA=, but it must
|
||||
be damaged or jammed or something: its flow rate is =0=, so there's no
|
||||
point in opening it. However, you could spend one minute moving to valve
|
||||
=BB= and another minute opening it; doing so would release pressure
|
||||
during the remaining /28 minutes/ at a flow rate of =13=, a total
|
||||
eventual pressure release of =28 * 13 = 364=. Then, you could spend your
|
||||
third minute moving to valve =CC= and your fourth minute opening it,
|
||||
providing an additional /26 minutes/ of eventual pressure release at a
|
||||
flow rate of =2=, or =52= total pressure released by valve =CC=.
|
||||
|
||||
Making your way through the tunnels like this, you could probably open
|
||||
many or all of the valves by the time 30 minutes have elapsed. However,
|
||||
you need to release as much pressure as possible, so you'll need to be
|
||||
methodical. Instead, consider this approach:
|
||||
|
||||
#+begin_example
|
||||
== Minute 1 ==
|
||||
No valves are open.
|
||||
You move to valve DD.
|
||||
|
||||
== Minute 2 ==
|
||||
No valves are open.
|
||||
You open valve DD.
|
||||
|
||||
== Minute 3 ==
|
||||
Valve DD is open, releasing 20 pressure.
|
||||
You move to valve CC.
|
||||
|
||||
== Minute 4 ==
|
||||
Valve DD is open, releasing 20 pressure.
|
||||
You move to valve BB.
|
||||
|
||||
== Minute 5 ==
|
||||
Valve DD is open, releasing 20 pressure.
|
||||
You open valve BB.
|
||||
|
||||
== Minute 6 ==
|
||||
Valves BB and DD are open, releasing 33 pressure.
|
||||
You move to valve AA.
|
||||
|
||||
== Minute 7 ==
|
||||
Valves BB and DD are open, releasing 33 pressure.
|
||||
You move to valve II.
|
||||
|
||||
== Minute 8 ==
|
||||
Valves BB and DD are open, releasing 33 pressure.
|
||||
You move to valve JJ.
|
||||
|
||||
== Minute 9 ==
|
||||
Valves BB and DD are open, releasing 33 pressure.
|
||||
You open valve JJ.
|
||||
|
||||
== Minute 10 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve II.
|
||||
|
||||
== Minute 11 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve AA.
|
||||
|
||||
== Minute 12 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve DD.
|
||||
|
||||
== Minute 13 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve EE.
|
||||
|
||||
== Minute 14 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve FF.
|
||||
|
||||
== Minute 15 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve GG.
|
||||
|
||||
== Minute 16 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You move to valve HH.
|
||||
|
||||
== Minute 17 ==
|
||||
Valves BB, DD, and JJ are open, releasing 54 pressure.
|
||||
You open valve HH.
|
||||
|
||||
== Minute 18 ==
|
||||
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
|
||||
You move to valve GG.
|
||||
|
||||
== Minute 19 ==
|
||||
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
|
||||
You move to valve FF.
|
||||
|
||||
== Minute 20 ==
|
||||
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
|
||||
You move to valve EE.
|
||||
|
||||
== Minute 21 ==
|
||||
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
|
||||
You open valve EE.
|
||||
|
||||
== Minute 22 ==
|
||||
Valves BB, DD, EE, HH, and JJ are open, releasing 79 pressure.
|
||||
You move to valve DD.
|
||||
|
||||
== Minute 23 ==
|
||||
Valves BB, DD, EE, HH, and JJ are open, releasing 79 pressure.
|
||||
You move to valve CC.
|
||||
|
||||
== Minute 24 ==
|
||||
Valves BB, DD, EE, HH, and JJ are open, releasing 79 pressure.
|
||||
You open valve CC.
|
||||
|
||||
== Minute 25 ==
|
||||
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.
|
||||
|
||||
== Minute 27 ==
|
||||
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
|
||||
|
||||
== Minute 28 ==
|
||||
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
|
||||
|
||||
== Minute 29 ==
|
||||
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
|
||||
|
||||
== Minute 30 ==
|
||||
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
|
||||
#+end_example
|
||||
|
||||
This approach lets you release the most pressure possible in 30 minutes
|
||||
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?/
|
||||
|
||||
Your puzzle answer was =1737=.
|
||||
|
||||
** --- 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
446
2022/day16/aoc-c.c
Normal 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);
|
||||
}
|
17
2022/day16/aoc.h
Normal file
17
2022/day16/aoc.h
Normal 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/day16/common.bash
Normal file
68
2022/day16/common.bash
Normal 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/day16/common.c
Normal file
59
2022/day16/common.c
Normal 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;
|
||||
}
|
10
2022/day16/input/example.txt
Normal file
10
2022/day16/input/example.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||
Valve JJ has flow rate=21; tunnel leads to valve II
|
54
2022/day16/input/input.txt
Normal file
54
2022/day16/input/input.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
Valve EJ has flow rate=25; tunnel leads to valve MC
|
||||
Valve WC has flow rate=0; tunnels lead to valves OW, RU
|
||||
Valve NP has flow rate=0; tunnels lead to valves VR, KL
|
||||
Valve AA has flow rate=0; tunnels lead to valves QT, AP, EZ, AK, XV
|
||||
Valve VO has flow rate=6; tunnels lead to valves KM, RF, HS, LJ, IA
|
||||
Valve CB has flow rate=0; tunnels lead to valves UI, UP
|
||||
Valve TE has flow rate=18; tunnel leads to valve JT
|
||||
Valve CZ has flow rate=0; tunnels lead to valves UP, OW
|
||||
Valve LJ has flow rate=0; tunnels lead to valves DV, VO
|
||||
Valve UP has flow rate=7; tunnels lead to valves SK, CB, CZ
|
||||
Valve FP has flow rate=0; tunnels lead to valves OW, RE
|
||||
Valve KM has flow rate=0; tunnels lead to valves SE, VO
|
||||
Valve DV has flow rate=0; tunnels lead to valves LJ, UM
|
||||
Valve FL has flow rate=0; tunnels lead to valves AH, TS
|
||||
Valve VR has flow rate=24; tunnels lead to valves DM, TF, NP
|
||||
Valve IA has flow rate=0; tunnels lead to valves VS, VO
|
||||
Valve RF has flow rate=0; tunnels lead to valves VO, JF
|
||||
Valve RT has flow rate=0; tunnels lead to valves UM, SE
|
||||
Valve RU has flow rate=0; tunnels lead to valves AR, WC
|
||||
Valve SE has flow rate=4; tunnels lead to valves GU, KM, CX, RT
|
||||
Valve MC has flow rate=0; tunnels lead to valves EJ, AR
|
||||
Valve TF has flow rate=0; tunnels lead to valves AH, VR
|
||||
Valve CX has flow rate=0; tunnels lead to valves SE, TO
|
||||
Valve GL has flow rate=11; tunnels lead to valves UY, KL, CY
|
||||
Valve GU has flow rate=0; tunnels lead to valves SE, EZ
|
||||
Valve VS has flow rate=0; tunnels lead to valves XN, IA
|
||||
Valve EZ has flow rate=0; tunnels lead to valves AA, GU
|
||||
Valve GK has flow rate=0; tunnels lead to valves FI, HZ
|
||||
Valve JT has flow rate=0; tunnels lead to valves TE, XN
|
||||
Valve DM has flow rate=0; tunnels lead to valves VR, HZ
|
||||
Valve AR has flow rate=16; tunnels lead to valves UI, RU, MC
|
||||
Valve XN has flow rate=9; tunnels lead to valves XP, JT, VS, GT, CY
|
||||
Valve CY has flow rate=0; tunnels lead to valves XN, GL
|
||||
Valve QT has flow rate=0; tunnels lead to valves UM, AA
|
||||
Valve KL has flow rate=0; tunnels lead to valves GL, NP
|
||||
Valve SK has flow rate=0; tunnels lead to valves XV, UP
|
||||
Valve OW has flow rate=12; tunnels lead to valves CZ, WC, FP
|
||||
Valve AK has flow rate=0; tunnels lead to valves AA, HS
|
||||
Valve XV has flow rate=0; tunnels lead to valves AA, SK
|
||||
Valve GT has flow rate=0; tunnels lead to valves XN, UM
|
||||
Valve FI has flow rate=0; tunnels lead to valves JF, GK
|
||||
Valve UY has flow rate=0; tunnels lead to valves JF, GL
|
||||
Valve UM has flow rate=5; tunnels lead to valves DV, GT, RT, QT
|
||||
Valve IQ has flow rate=0; tunnels lead to valves HZ, AH
|
||||
Valve JF has flow rate=10; tunnels lead to valves RF, FI, UY, RE, TS
|
||||
Valve TS has flow rate=0; tunnels lead to valves JF, FL
|
||||
Valve AH has flow rate=23; tunnels lead to valves IQ, FL, TF
|
||||
Valve HS has flow rate=0; tunnels lead to valves AK, VO
|
||||
Valve HZ has flow rate=20; tunnels lead to valves IQ, DM, GK
|
||||
Valve TO has flow rate=15; tunnel leads to valve CX
|
||||
Valve XP has flow rate=0; tunnels lead to valves AP, XN
|
||||
Valve AP has flow rate=0; tunnels lead to valves XP, AA
|
||||
Valve RE has flow rate=0; tunnels lead to valves JF, FP
|
||||
Valve UI has flow rate=0; tunnels lead to valves AR, CB
|
111
2022/day17/Makefile
Normal file
111
2022/day17/Makefile
Normal 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
374
2022/day17/README.org
Normal 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
17
2022/day17/aoc.h
Normal 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
68
2022/day17/common.bash
Normal 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
59
2022/day17/common.c
Normal 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;
|
||||
}
|
1
2022/day17/input/example.txt
Normal file
1
2022/day17/input/example.txt
Normal file
@@ -0,0 +1 @@
|
||||
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
1
2022/day17/input/input.txt
Normal file
1
2022/day17/input/input.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -25,6 +25,7 @@
|
||||
#ifdef DEBUG_DEBUG
|
||||
void debug_init(u32 level);
|
||||
void debug_level_set(u32 level);
|
||||
u32 debug_level_get(void);
|
||||
void _printf debug(u32 level, bool timestamp,
|
||||
u32 indent, const char *src,
|
||||
u32 line, const char *, ...);
|
||||
|
@@ -35,6 +35,11 @@ void debug_level_set(u32 level)
|
||||
log(1, "debug level set to %u\n", level);
|
||||
}
|
||||
|
||||
u32 debug_level_get()
|
||||
{
|
||||
return debug_level;
|
||||
}
|
||||
|
||||
void debug_init(u32 level)
|
||||
{
|
||||
struct timespec timer;
|
||||
|
Reference in New Issue
Block a user