From d1cf8d96b851b0137337ff3a880d65007cf95ce9 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sat, 18 Mar 2023 16:35:08 +0100 Subject: [PATCH] 2022 day 14, parts 1 & 2, before cleaning --- 2022/day14/README.org | 58 +++++++++ 2022/day14/aoc-c.c | 272 ++++++++++++++++++++++++++++++++++++++++++ 2022/libsrc/Makefile | 88 ++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 2022/day14/aoc-c.c create mode 100644 2022/libsrc/Makefile diff --git a/2022/day14/README.org b/2022/day14/README.org index 2bd0c13..1f0a9b7 100644 --- a/2022/day14/README.org +++ b/2022/day14/README.org @@ -172,3 +172,61 @@ the path any new sand takes before falling forever is shown here with Using your scan, simulate the falling sand. /How many units of sand come to rest before sand starts flowing into the abyss below?/ + +Your puzzle answer was =665=. + +** --- Part Two --- +You realize you misread the scan. There isn't an endless void at the +bottom of the scan - there's floor, and you're standing on it! + +You don't have time to scan the floor, so assume the floor is an +infinite horizontal line with a =y= coordinate equal to /two plus the +highest =y= coordinate/ of any point in your scan. + +In the example above, the highest =y= coordinate of any point is =9=, +and so the floor is at =y=11=. (This is as if your scan contained one +extra rock path like =-infinity,11 -> infinity,11=.) With the added +floor, the example above now looks like this: + +#+begin_example + ...........+........ + .................... + .................... + .................... + .........#...##..... + .........#...#...... + .......###...#...... + .............#...... + .............#...... + .....#########...... + .................... +<-- etc #################### etc --> +#+end_example + +To find somewhere safe to stand, you'll need to simulate falling sand +until a unit of sand comes to rest at =500,0=, blocking the source +entirely and stopping the flow of sand into the cave. In the example +above, the situation finally looks like this after =93= units of sand +come to rest: + +#+begin_example +............o............ +...........ooo........... +..........ooooo.......... +.........ooooooo......... +........oo#ooo##o........ +.......ooo#ooo#ooo....... +......oo###ooo#oooo...... +.....oooo.oooo#ooooo..... +....oooooooooo#oooooo.... +...ooo#########ooooooo... +..ooooo.......ooooooooo.. +######################### +#+end_example + +Using your scan, simulate the falling sand until the source of the sand +becomes blocked. /How many units of sand come to rest?/ + +Your puzzle answer was =25434=. + +Both parts of this puzzle are complete! They provide two gold stars: ** diff --git a/2022/day14/aoc-c.c b/2022/day14/aoc-c.c new file mode 100644 index 0000000..ac51565 --- /dev/null +++ b/2022/day14/aoc-c.c @@ -0,0 +1,272 @@ +/* aoc-c.c: Advent of Code 2022, day 14 + * + * Copyright (C) 2022 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include +#include +#include +#include + +#include "br.h" +#include "list.h" +#include "pool.h" +#include "debug.h" + +#include "aoc.h" + +pool_t *pool_segment; + +#define INF (-1) /* found infinite fall position */ + +typedef enum { /* map cells */ + EMPTY = '.', + STONE = '#', + SAND = 'o', + CURR = 'v' +} type_t; + +typedef struct segment { + int x1, y1, x2, y2; + struct list_head list; +} segment_t; + +LIST_HEAD(segments); + + +static struct map { + int xmin, xmax, ymin, ymax; + int size_x, size_y; + int deltax, deltay; + int dropcol; /* drop sand here */ + int dropped; /* number of sand units */ + char *m; +} map = { + .xmin = INT_MAX, .xmax = INT_MIN, .ymin = INT_MAX, .ymax = INT_MIN, +}; + +static void print_segments() +{ + segment_t *cur; + log(2, "segments:\n"); + list_for_each_entry(cur, &segments, list) { + log(2, "segment: (%d,%d) -> (%d,%d)\n", cur->x1, cur->y1, cur->x2, cur->y2); + } +} + +#define XY(m, x, y) ((y) * m->size_x + (x)) +#define P(m, x, y) (m->m[XY(m, (x), (y))]) + +static void print_map(struct map *m) +{ + log_f(3, "xmin=%d xmax=%d ymin=%d ymax=%d deltax=%d deltay=%d sizex=%d sizey=%d\n", + m->xmin, m->xmax, m->ymin, m->ymax, m->deltax, m->deltay, m->size_x, m->size_y); + for (int skip=0; skip < m->dropcol + 3; ++skip) + log(3, " "); + log(3, "+\n"); + for (int y = 0; y < m->size_y; ++y) { + log(3, "%02d ", y); + for (int x = 0; x < m->size_x; ++x) { + log(3, "%c", P(m, x, y)); + } + log(3, "\n"); + } +} + +static int drop_sand(struct map *m, int x, int y) +{ + int ret = 0, tmp; + + log_f(3, "x=%d y=%d\n", x, y); + if (y >= m->ymax) /* nothing left under */ + return INF; + + if (P(m, x, y) != EMPTY) { + log(3, "ASSERT EMPTY(%d, %d) = %c\n", x, y, P(m, x, y)); + exit(0); + } + //P(m, x, y) = CURR; + //print_map(m); + //P(m, x, y) = EMPTY; + //print_map(m); + + log(4, "DOWN = (%d,%d)=%c %c\n", x, y+1, P(m, x, y+1), P(m, 7, 9)); + + if (P(m, x, y+1) == EMPTY) { /* down */ + //log(4, "zob1 %c!=%c\n", P(m, x, y+1), EMPTY); + if ((tmp = drop_sand(m, x, y+1)) < 0) + return INF; + ret += tmp; + } + if (//P(m, x-1, y) == EMPTY && + P(m, x-1, y+1) == EMPTY) { /* left */ + //puts("zob2"); + if ((tmp = drop_sand(m, x-1, y+1)) < 0) + return INF; + ret += tmp; + } + if (//P(m, x+1, y) == EMPTY && + P(m, x+1, y+1) == EMPTY) { /* right */ + //puts("zob3"); + if ((tmp = drop_sand(m, x+1, y+1)) < 0) + return INF; + ret += tmp; + } + /* the 3 lower adjacent cells are filled */ + P(m, x, y) = SAND; + m->dropped++; + if (y == 0) { + print_map(m); + return INF; + } + log(3, "DROPPED=%d\n", m->dropped); + if (!(m->dropped %100)) + print_map(m); + return ret; +} + +static struct map *gen_map(struct map *m, int part) +{ + segment_t *cur; + + if (part == 1) { + m->size_x = (m->xmax - m->xmin) + 3; + m->size_y = m->ymax + 1; + m->deltax = m->xmin - 1; + } else { + m->ymax += 2; + m->xmin = 500 - m->ymax; + m->xmax = 500 + m->ymax; + m->deltax = m->xmin - 1; + m->size_x = (m->xmax - m->xmin) + 3; + //m->size_x = m->xmax; + m->size_y = m->ymax + 2; + } + size_t size = m->size_x * m->size_y; + //m->deltax = - 1; + +//m->x1 -= m->deltax; + //m->y1 -= m->deltay; + //m->x2 -= m->deltax; + //m->y2 -= m->deltay, + m->dropcol = 500 - m->deltax; + m->dropped = 0; + + m->m = malloc(size); + memset(m->m, '.', size); + list_for_each_entry(cur, &segments, list) { + int x1 = cur->x1 - m->deltax, y1 = cur->y1 - m->deltay, + x2 = cur->x2 - m->deltax, y2 = cur->y2 - m->deltay; + int dx = 0, dy = 0; + if (x1 == x2) + dy = y2 - y1 > 0 ? 1 : -1; + else + dx = x2 - x1 > 0 ? 1 : -1; + log(3, "From (%d,%d) -> (%d,%d), dx=%d dy=%d <=> (%d,%d) -> (%d,%d)\n", + cur->x1, cur->y1, cur->x2, cur->y2, dx, dy, x1, y1, x2, y2 ); + do { + log(3, "Setting (%d,%d)\n", x1, y1); + P(m, x1, y1) = '#'; + x1 += dx, y1 += dy; + } while (x1 != x2 || y1 != y2); + log(3, "Setting (%d,%d)\n", x2, y2); + P(m, x2, y2) = '#'; + log(2, "segment: (%d,%d) -> (%d,%d)\n", cur->x1, cur->y1, cur->x2, cur->y2); + } + if (part == 2) + for (int i = 0; i < m->xmax; ++i) + P(m, i, m->ymax) = STONE; + + log(3, "deltax=%d dx=%d dy=%d size=%lu drop=%d\n\n", + m->deltax, m->size_x, m->size_y, size, m->dropcol); + print_map(m); + return m; +} + +static struct map *parse() +{ + size_t alloc = 0; + ssize_t buflen; + char *buf = NULL, *cur; + int i, scanned; + int x1, y1, x2, y2, x, y, n; + segment_t *segment; + + while ((buflen = getline(&buf, &alloc, stdin)) > 0) { + i = 0; + buf[--buflen] = 0; + cur = buf; + log(3, "INPUT: len=%lu <%s>\n", buflen, buf); + while (1) { + scanned = sscanf(cur, "%d,%d ->%n", &x, &y, &n); + log(5, "scanned=%d n=%d x=%d y=%d\n", scanned, n, x, y); + if (scanned != 2) + break; + map.xmin = min(x, map.xmin); + map.xmax = max(x, map.xmax); + map.ymin = min(y, map.ymin); + map.ymax = max(y, map.ymax); + if (i) { + x1 = x2; + y1 = y2; + } + x2 = x; + y2 = y; + if (!i) { /* first point */ + goto next; + } + segment = pool_get(pool_segment); + segment->x1 = x1; + segment->y1 = y1; + segment->x2 = x2; + segment->y2 = y2; + log(3, "segment: (%d,%d) -> (%d,%d)\n", x1, y1, x2, y2); + if (x1 != x2 && y1 != y2) { + log(3, "Ooops!\n"); + exit(1); + } + list_add_tail(&segment->list, &segments); + next: + i++; + cur += n; + if (cur - buf >= buflen) + break; + } + } + log(3, "xmin=%d xmax=%d ymin=%d ymax=%d\n", map.xmin, map.xmax, map.ymin, map.ymax); + print_segments(); + return ↦ +} + +static int part1() +{ + struct map *m = gen_map(parse(), 1); + drop_sand(m, m->dropcol, 0); + return m->dropped; +} + +static int part2() +{ + struct map *m = gen_map(parse(), 2); + drop_sand(m, m->dropcol, 0); + return m->dropped; +} + +int main(int ac, char **av) +{ + int part = parseargs(ac, av); + pool_segment = pool_create("segment", 512, sizeof(segment_t)); + + printf("%s: res=%d\n", *av, part == 1? part1(): part2()); + pool_destroy(pool_segment); + exit(0); +} diff --git a/2022/libsrc/Makefile b/2022/libsrc/Makefile new file mode 100644 index 0000000..c123e42 --- /dev/null +++ b/2022/libsrc/Makefile @@ -0,0 +1,88 @@ +# AOC Makefile - GNU make only. +# +# Copyright (C) 2021-2022 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 . +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +SHELL := /bin/bash +CC := gcc +BEAR := bear +CCLSFILE:= compile_commands.json + +#LIBS = -lreadline -lncurses +CFLAGS += -std=gnu11 + +CFLAGS += -O2 +CFLAGS += -g +# for gprof +#CFLAGS += -pg +CFLAGS += -Wall +CFLAGS += -Wextra +CFLAGS += -march=native + +CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c) +CFLAGS += -DDEBUG_POOL # memory pools management +# Next one may be useful for valgrind (some invalid instructions) +# CFLAGS += -mno-tbm +CFLAGS += -Wmissing-declarations +CFLAGS += -Wno-unused-result + +INCDIR := ../include +LIBSRCDIR := . +LIBDIR := ../lib +LIB := libaoc_$(shell uname -m) +SLIB := $(LIBDIR)/$(LIB).a +DLIB := $(LIBDIR)/$(LIB).so +LIBSRC := $(wildcard $(LIBSRCDIR)/*.c) +LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC)) +LDFLAGS := -L$(LIBDIR) +LDLIB := -l$(LIB) + +.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS) + +all: lib $(SUBDIRS) + +compile: $(LIBOBJ) + +clean: + @$(RM) -f *.o *.s *.i $(LIBOBJ) + +cleanall: clean + @$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ) + +lib: $(DLIB) $(SLIB) + +$(SLIB): $(LIBOBJ) + @echo building $@ static library. + @mkdir -p $(LIBDIR) + @$(AR) $(ARFLAGS) -o $@ $^ + +$(DLIB): CFLAGS += -fPIC +$(DLIB): LDFLAGS += -shared +$(DLIB): $(LIBOBJ) + @echo building $@ shared library. + @mkdir -p $(LIBDIR) + @$(CC) $(LDFLAGS) $^ -o $@ + +.c.o: + @echo compiling $<. + @$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -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 $@ + +bear: clean + @touch .ccls-root + @$(BEAR) -- make compile