2019 day 3 cleanup

This commit is contained in:
2022-09-20 13:39:08 +02:00
parent dbfc914efb
commit ffb27a8338
5 changed files with 65 additions and 122 deletions

View File

@@ -51,7 +51,7 @@ export PATH := .:$(PATH)
all: README.org ex1 ex2 all: README.org ex1 ex2
memcheck: memcheck1 memcheck: memcheck1 memcheck2
memcheck1: aoc-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)

View File

@@ -51,7 +51,7 @@ export PATH := .:$(PATH)
all: README.org ex1 ex2 all: README.org ex1 ex2
memcheck: memcheck1 memcheck: memcheck1 memcheck2
memcheck1: aoc-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)

View File

@@ -51,7 +51,7 @@ export PATH := .:$(PATH)
all: README.org ex1 ex2 all: README.org ex1 ex2
memcheck: memcheck1 memcheck: memcheck1 memcheck2
memcheck1: aoc-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)

View File

@@ -55,10 +55,10 @@ is closer to the central port: its distance is =3 + 3 = 6=.
Here are a few more examples: Here are a few more examples:
- =R75,D30,R83,U83,L12,D49,R71,U7,L72=\\ - =R75,D30,R83,U83,L12,D49,R71,U7,L72= \\
=U62,R66,U55,R34,D71,R55,D58,R83= =U62,R66,U55,R34,D71,R55,D58,R83=
= distance =159= = distance =159=
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51=\\ - =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7= =U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
= distance =135= = distance =135=
@@ -104,10 +104,10 @@ However, the top-right intersection is better: the first wire takes only
Here are the best steps for the extra examples from above: Here are the best steps for the extra examples from above:
- =R75,D30,R83,U83,L12,D49,R71,U7,L72=\\ - =R75,D30,R83,U83,L12,D49,R71,U7,L72= \\
=U62,R66,U55,R34,D71,R55,D58,R83= =U62,R66,U55,R34,D71,R55,D58,R83=
= =610= steps = =610= steps
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51=\\ - =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7= =U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
= =410= steps = =410= steps

View File

@@ -22,7 +22,6 @@
#include "debug.h" #include "debug.h"
#include "list.h" #include "list.h"
#include "pool.h" #include "pool.h"
#include "debug.h"
typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t; typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t;
@@ -30,33 +29,30 @@ struct point {
int x, y; int x, y;
}; };
/**
* struct wire - one segment on wire.
* @dist: total distance from start before the current segment
* @dir: indicates which of ends[0] and ends[1] was the original line end point
* @ends: segment ends, ordered (ends[0].x <= ends[1].x and ends[0].y <= ends[1].y)
* @list: segments list
*/
struct wire { struct wire {
int dist; /* total distance before this wire */ int dist;
struct point delta; /* current delta */ int dir;
struct point p0, p1; struct point ends[2];
struct list_head list; /* wire list */ struct list_head list;
}; };
static struct wires {
int nwires[2];
struct list_head head[2];
} wires[2];
static pool_t *wire_pool; static pool_t *wire_pool;
static struct wires *parse() static struct list_head *parse(struct list_head *wires)
{ {
size_t alloc = 0; size_t alloc = 0;
ssize_t buflen; ssize_t buflen;
char *buf = NULL, *token; char *buf = NULL, *token;
/* initialize wires lists */
INIT_LIST_HEAD(&wires->head[0]);
INIT_LIST_HEAD(&wires->head[1]);
for (int line = 0; line < 2; ++line) { for (int line = 0; line < 2; ++line) {
int x0 = 0, y0 = 0; struct point p0 = {0, 0}, p1 = {0, 0};
int x1 = 0, y1 = 0;
int totdist = 0; int totdist = 0;
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) { if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
@@ -68,36 +64,21 @@ static struct wires *parse()
dir_t dir = *token; dir_t dir = *token;
int dist = atoi(token + 1); int dist = atoi(token + 1);
struct wire *new = pool_get(wire_pool); struct wire *new = pool_get(wire_pool);
INIT_LIST_HEAD(&new->list); INIT_LIST_HEAD(&new->list);
new->dist = totdist; new->dist = totdist;
new->delta.x = 0;
new->delta.y = 0;
totdist += abs(dist); totdist += abs(dist);
switch(dir) { new->dir = !!(dir == DOWN || dir == LEFT);
case DOWN: if (dir == DOWN || dir == UP) /* vertical segment */
y1 = y0 - dist; p1.y = p0.y + (1 - (new->dir * 2)) * dist;
new->delta.y = -dist; else /* horizontal segment */
break; p1.x = p0.x + (1 - (new->dir * 2)) * dist;
case UP: new->ends[0].x = min(p0.x, p1.x); /* order ends (p0.? <= p1.?) */
y1 = y0 + dist; new->ends[0].y = min(p0.y, p1.y);
new->delta.y = dist; new->ends[1].x = max(p0.x, p1.x);
break; new->ends[1].y = max(p0.y, p1.y);
case LEFT: list_add_tail(&new->list, &wires[line]);
x1 = x0 - dist; p0 = p1;
new->delta.x = -dist;
break;
case RIGHT:
x1 = x0 + dist;
new->delta.x = dist;
}
new->p0.x = min(x0, x1);
new->p0.y = min(y0, y1);
new->p1.x = max(x0, x1);
new->p1.y = max(y0, y1);
list_add_tail(&new->list, &wires->head[line]);
x0 = x1;
y0 = y1;
wires->nwires[line]++;
} }
} }
end: end:
@@ -105,85 +86,48 @@ end:
return wires; return wires;
} }
#define manhattan(x, y) (abs(x) + abs(y)) static struct point *intersect(struct wire *w0, struct wire *w1, struct point *ret)
static struct point *intersect(struct wire *w1, struct wire *w2, struct point *ret)
{ {
log_f(3, "(%d,%d)-(%d,%d) (%d,%d)-(%d,%d): ", if (w0->ends[0].x == w0->ends[1].x) { /* w0 vertical */
w1->p0.x, w1->p0.y, w1->p1.x, w1->p1.y, /* BUG: overlapping wires is not handled */
w2->p0.x, w2->p0.y, w2->p1.x, w2->p1.y); if (w0->ends[0].x >= w1->ends[0].x && w0->ends[1].x <= w1->ends[1].x &&
if (w1->p0.x == w1->p1.x) { /* w1 vertical */ w0->ends[0].y <= w1->ends[0].y && w0->ends[1].y >= w1->ends[1].y) {
/* TODO: overlapping wires (multiple intersections) */ ret->x = w0->ends[0].x;
if (w1->p0.x >= w2->p0.x && w1->p1.x <= w2->p1.x && ret->y = w1->ends[0].y;
w1->p0.y <= w2->p0.y && w1->p1.y >= w2->p1.y) {
log(3, "intersect 1 at (%d, %d)\n", w1->p0.x, w2->p0.y);
ret->x = w1->p0.x;
ret->y = w2->p0.y;
return ret; return ret;
//return manhatan(w1->p0.x, w2->p0.y);
} }
log(3, "no intersection\n");
return NULL; return NULL;
} else { /* w1 horizontal */ } else { /* w0 horizontal */
if (w1->p0.x <= w2->p0.x && w1->p1.x >= w2->p1.x && if (w0->ends[0].x <= w1->ends[0].x && w0->ends[1].x >= w1->ends[1].x &&
w1->p0.y <= w2->p1.y && w1->p1.y >= w2->p0.y) { w0->ends[0].y <= w1->ends[1].y && w0->ends[1].y >= w1->ends[0].y) {
log(3, "intersect 2 at (%d, %d)\n", w2->p0.x, w1->p0.y); ret->x = w1->ends[0].x;
ret->x = w2->p0.x; ret->y = w0->ends[0].y;
ret->y = w1->p0.y;
return ret; return ret;
//return manhatan(w2->p0.x, w1->p0.y);
} }
log(3, "no intersection\n");
return NULL; return NULL;
} }
} }
static s32 part1(struct wires *w) /* part 1 */
#define manhattan(point) (abs(point.x) + abs(point.y))
/* part 2 */
#define signal(point, w0, w1) \
(w0->dist + w1->dist + \
abs(cross.x - w0->ends[w0->dir].x) + abs(cross.y - w0->ends[w0->dir].y) + \
abs(cross.x - w1->ends[w1->dir].x) + abs(cross.y - w1->ends[w1->dir].y))
static int doit(struct list_head *w, int part)
{ {
struct wire *w0, *w1; struct wire *w0, *w1;
struct point cross; struct point cross;
s32 res = INT32_MAX; s32 res = INT32_MAX;
list_for_each_entry(w0, &w->head[0], list) { list_for_each_entry(w0, &w[0], list)
list_for_each_entry(w1, &w->head[1], list) { list_for_each_entry(w1, &w[1], list)
if (intersect(w0, w1, &cross)) { if (intersect(w0, w1, &cross))
int tmp = manhattan(cross.x, cross.y); res = min_not_zero(res, part == 1 ?
log(3, "new manhattan: %d\n", tmp); manhattan(cross) :
res = min(tmp, res); signal(cross, w0, w1));
}
}
}
return res;
}
static int part2(struct wires *w)
{
struct wire *w0, *w1;
struct point cross;
s32 res = INT32_MAX;
list_for_each_entry(w0, &w->head[0], list) {
list_for_each_entry(w1, &w->head[1], list) {
if (intersect(w0, w1, &cross)) {
if (cross.x || cross.y) {
int tmp = w0->dist + w1->dist;
/* as w->p0 contains the lowest value of (x, y), we lost the
* starting point information. We adjust remaining steps with
* the delta sign, which indicates if we swapped p0 and p1.
*/
tmp += w0->delta.x + w0->delta.y > 0 ?
abs(cross.x - w0->p0.x) + abs(cross.y - w0->p0.y) :
abs(cross.x - w0->p1.x) + abs(cross.y - w0->p1.y);
tmp += w1->delta.x + w1->delta.y > 0 ?
abs(cross.x - w1->p0.x) + abs(cross.y - w1->p0.y) :
abs(cross.x - w1->p1.x) + abs(cross.y - w1->p1.y);
/* new best */
res = min(tmp, res);
}
}
}
}
return res; return res;
} }
@@ -196,7 +140,7 @@ static int usage(char *prg)
int main(int ac, char **av) int main(int ac, char **av)
{ {
int opt, part = 1; int opt, part = 1;
struct wires *wires; struct list_head wires[2] = { LIST_HEAD_INIT(wires[0]), LIST_HEAD_INIT(wires[1]) };
while ((opt = getopt(ac, av, "d:p:")) != -1) { while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) { switch (opt) {
@@ -206,10 +150,8 @@ int main(int ac, char **av)
case 'p': /* 1 or 2 */ case 'p': /* 1 or 2 */
part = atoi(optarg); part = atoi(optarg);
if (part < 1 || part > 2) if (part < 1 || part > 2)
return usage(*av);
break;
default: default:
return usage(*av); return usage(*av);
} }
} }
@@ -217,8 +159,9 @@ int main(int ac, char **av)
return usage(*av); return usage(*av);
wire_pool = pool_create("wire", 256, sizeof(struct wire)); wire_pool = pool_create("wire", 256, sizeof(struct wire));
wires = parse(); if (parse(wires)) {
printf("%s : res=%d\n", *av, part == 1? part1(wires): part2(wires)); printf("%s : res=%d\n", *av, doit(wires, part));
pool_destroy(wire_pool); pool_destroy(wire_pool);
}
exit (0); exit (0);
} }