diff --git a/2019/day01/Makefile b/2019/day01/Makefile index 234666d..30423a2 100644 --- a/2019/day01/Makefile +++ b/2019/day01/Makefile @@ -51,7 +51,7 @@ export PATH := .:$(PATH) all: README.org ex1 ex2 -memcheck: memcheck1 +memcheck: memcheck1 memcheck2 memcheck1: aoc-c @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) diff --git a/2019/day02/Makefile b/2019/day02/Makefile index 234666d..30423a2 100644 --- a/2019/day02/Makefile +++ b/2019/day02/Makefile @@ -51,7 +51,7 @@ export PATH := .:$(PATH) all: README.org ex1 ex2 -memcheck: memcheck1 +memcheck: memcheck1 memcheck2 memcheck1: aoc-c @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) diff --git a/2019/day03/Makefile b/2019/day03/Makefile index 234666d..30423a2 100644 --- a/2019/day03/Makefile +++ b/2019/day03/Makefile @@ -51,7 +51,7 @@ export PATH := .:$(PATH) all: README.org ex1 ex2 -memcheck: memcheck1 +memcheck: memcheck1 memcheck2 memcheck1: aoc-c @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) diff --git a/2019/day03/README.org b/2019/day03/README.org index 6b34672..b974f27 100644 --- a/2019/day03/README.org +++ b/2019/day03/README.org @@ -55,10 +55,10 @@ is closer to the central port: its distance is =3 + 3 = 6=. 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= = 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= = 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: -- =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= = =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= = =410= steps diff --git a/2019/day03/aoc-c.c b/2019/day03/aoc-c.c index cb4bb97..7d51f68 100644 --- a/2019/day03/aoc-c.c +++ b/2019/day03/aoc-c.c @@ -22,7 +22,6 @@ #include "debug.h" #include "list.h" #include "pool.h" -#include "debug.h" typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t; @@ -30,33 +29,30 @@ struct point { 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 { - int dist; /* total distance before this wire */ - struct point delta; /* current delta */ - struct point p0, p1; - struct list_head list; /* wire list */ + int dist; + int dir; + struct point ends[2]; + struct list_head list; }; -static struct wires { - int nwires[2]; - struct list_head head[2]; -} wires[2]; - static pool_t *wire_pool; -static struct wires *parse() +static struct list_head *parse(struct list_head *wires) { size_t alloc = 0; ssize_t buflen; 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) { - int x0 = 0, y0 = 0; - int x1 = 0, y1 = 0; + struct point p0 = {0, 0}, p1 = {0, 0}; int totdist = 0; if ((buflen = getline(&buf, &alloc, stdin)) <= 0) { @@ -68,36 +64,21 @@ static struct wires *parse() dir_t dir = *token; int dist = atoi(token + 1); struct wire *new = pool_get(wire_pool); + INIT_LIST_HEAD(&new->list); new->dist = totdist; - new->delta.x = 0; - new->delta.y = 0; totdist += abs(dist); - switch(dir) { - case DOWN: - y1 = y0 - dist; - new->delta.y = -dist; - break; - case UP: - y1 = y0 + dist; - new->delta.y = dist; - break; - case LEFT: - x1 = x0 - dist; - 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]++; + new->dir = !!(dir == DOWN || dir == LEFT); + if (dir == DOWN || dir == UP) /* vertical segment */ + p1.y = p0.y + (1 - (new->dir * 2)) * dist; + else /* horizontal segment */ + p1.x = p0.x + (1 - (new->dir * 2)) * dist; + new->ends[0].x = min(p0.x, p1.x); /* order ends (p0.? <= p1.?) */ + new->ends[0].y = min(p0.y, p1.y); + new->ends[1].x = max(p0.x, p1.x); + new->ends[1].y = max(p0.y, p1.y); + list_add_tail(&new->list, &wires[line]); + p0 = p1; } } end: @@ -105,85 +86,48 @@ end: return wires; } -#define manhattan(x, y) (abs(x) + abs(y)) - -static struct point *intersect(struct wire *w1, struct wire *w2, struct point *ret) +static struct point *intersect(struct wire *w0, struct wire *w1, struct point *ret) { - log_f(3, "(%d,%d)-(%d,%d) (%d,%d)-(%d,%d): ", - w1->p0.x, w1->p0.y, w1->p1.x, w1->p1.y, - w2->p0.x, w2->p0.y, w2->p1.x, w2->p1.y); - if (w1->p0.x == w1->p1.x) { /* w1 vertical */ - /* TODO: overlapping wires (multiple intersections) */ - if (w1->p0.x >= w2->p0.x && w1->p1.x <= w2->p1.x && - 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; + if (w0->ends[0].x == w0->ends[1].x) { /* w0 vertical */ + /* BUG: overlapping wires is not handled */ + if (w0->ends[0].x >= w1->ends[0].x && w0->ends[1].x <= w1->ends[1].x && + w0->ends[0].y <= w1->ends[0].y && w0->ends[1].y >= w1->ends[1].y) { + ret->x = w0->ends[0].x; + ret->y = w1->ends[0].y; return ret; - //return manhatan(w1->p0.x, w2->p0.y); } - log(3, "no intersection\n"); return NULL; - } else { /* w1 horizontal */ - if (w1->p0.x <= w2->p0.x && w1->p1.x >= w2->p1.x && - w1->p0.y <= w2->p1.y && w1->p1.y >= w2->p0.y) { - log(3, "intersect 2 at (%d, %d)\n", w2->p0.x, w1->p0.y); - ret->x = w2->p0.x; - ret->y = w1->p0.y; + } else { /* w0 horizontal */ + if (w0->ends[0].x <= w1->ends[0].x && w0->ends[1].x >= w1->ends[1].x && + w0->ends[0].y <= w1->ends[1].y && w0->ends[1].y >= w1->ends[0].y) { + ret->x = w1->ends[0].x; + ret->y = w0->ends[0].y; return ret; - //return manhatan(w2->p0.x, w1->p0.y); } - log(3, "no intersection\n"); 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 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)) { - int tmp = manhattan(cross.x, cross.y); - log(3, "new manhattan: %d\n", tmp); - res = min(tmp, res); - } - } - } - 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); - } - } - } - } + list_for_each_entry(w0, &w[0], list) + list_for_each_entry(w1, &w[1], list) + if (intersect(w0, w1, &cross)) + res = min_not_zero(res, part == 1 ? + manhattan(cross) : + signal(cross, w0, w1)); return res; } @@ -196,7 +140,7 @@ static int usage(char *prg) int main(int ac, char **av) { 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) { switch (opt) { @@ -206,10 +150,8 @@ int main(int ac, char **av) case 'p': /* 1 or 2 */ part = atoi(optarg); if (part < 1 || part > 2) - return usage(*av); - break; default: - return usage(*av); + return usage(*av); } } @@ -217,8 +159,9 @@ int main(int ac, char **av) return usage(*av); wire_pool = pool_create("wire", 256, sizeof(struct wire)); - wires = parse(); - printf("%s : res=%d\n", *av, part == 1? part1(wires): part2(wires)); - pool_destroy(wire_pool); + if (parse(wires)) { + printf("%s : res=%d\n", *av, doit(wires, part)); + pool_destroy(wire_pool); + } exit (0); }