diff --git a/day18p1/Makefile b/day18p1/Makefile new file mode 100644 index 0000000..79bbc11 --- /dev/null +++ b/day18p1/Makefile @@ -0,0 +1,12 @@ +CFLAGS := -O3 -Wall -Wextra -std=c17 -D_GNU_SOURCE + +.PHONY: all +all: main out/ + +.PHONY: clean +clean: + rm -f main out/* + +out/: + mkdir -p $@ + touch $@/.gitkeep diff --git a/day18p1/input b/day18p1/input new file mode 100644 index 0000000..eb3c596 --- /dev/null +++ b/day18p1/input @@ -0,0 +1,50 @@ +........#.##..#|#|.#.....|......#..#.|..##..||.#.. +#|##.|||.|..|||......|.##.#|#|....||#.#...#...#..# +..##...#|#..|#.|..#||#...|#....|#...#|#.|.||...|.. +.....#|||.|.#...###|....|#..#.#.#.|..#||#|....|#.| +....|.....#.||.#..#...#|....|||..#....##...|..|.#| +||...|###..|..|||..|#.##|.####.#...|.||.|....|.##. +..#.#.###..||......#|#|.|....#|.#|.|...#....#...#| +.|..||||||...#.##..|.#||.#|##|..#.#..##..#...|#... +.|.....||...#.#|.##|..|.##||..#.#..|..#.#.#..|.#|. +||...|#........#.|..##|.|..#...#...#|#|..||.|....# +#||.|.|..|.......##....|..#||#.#|.|||......|..||.. +.....#.|||.....|.#.#.......#.|..#.|.....|.|.#...#. +...#.##.#.||#.#|.#.##..#.||#.#.#|#.||.||.|......#. +|.|...#|.|####|.|..#.#|....|......|....|...||#||.. +.#...#.#......|...#.....|.....|.#|...##|||...#.|#. +||##.#...#.|...##..##.||#...#|...|##.##...#||..#|. +|.|#.||..|##.|.#.|..#..|.##.#.......#...|....||... +.|.......#..##...|.|..|#.#....|#|..##|#|.##|.|.|#. +.|....|.#|||#.#..#..|||.....||...#|.#..|..#.#...#. +...#..###.#|.##||.#.|.||###..|..|#.|#..||......||. +..##.......##|.....#...|#|..##|.#.|||.|#....|##... +#...#|##|......##|...|#..#.|..##..#..#.|##.##|#..# +|.#|.....|..#...|....|...#....#|..#.....||...|#|.| +##...#.....#.....|#|.......|....####.#..##.|.##... +.....|...|#|#..|#|.|..##.|..|....##..||.#...|..|.| +.|..|....##.||||.##|.#...|..|#|.#.|####.|..|##.#.. +#.........|##.#|..##|...|........|..|....|..#...## +.#.|...#...#...|.|...|..|.#.|....#..|.|..|..#|.... +.....#.....#|.#....|....##...##....###....#.|...|. +||.....|.|.##|.##||.#|#.##|.#..|#####|...|...||#.# +...#||....#.....##.|##|.##|#.##.#|.|.....#........ +..##.....||..#..#.|..##...#.|.|.|.|...|.#.|..|.... +|##..|..........##..#|...|......||.#....#....|..#. +...#..|.#.|...|.##|.##..##..|.|....#||#|##..||||.. +#...##......|..|#...#.#.|#||..#...|.#...|..###.||. +|#.......|#.|##|....|.....#..||.|#|#...#|....|..#| +.|.....#|##.|.#...#..#||#.....|....#||.#|.##.##.#| +|#..###..#..|#.....##...||.|.|.#.#|.||..||.||#|#.. +||||#....|#..|.|...|...||....|...#....#.##...#|... +...||##||#......|#.#..#..|.....|...#..#|...#...||| +.|#.|.|....|...#.....|#....|..#.#...#...||..##|..| +||#.|##.|...|.##......##|#..#..#.#.#.....|#|##.##. +|.#.....||.....#.#...|...|..|#|..|..#...|....|...| +###..#.#......#|..#....#......|##.##....|||.|..#|. +..#.|.#...#..|#####|.....##.|.|#......|..||.#|.... +.#||.|.##..#.|..##......|..|.|#..|.....#.....|#|.. +|##.#......#.#.#.#|||#|....#...#.|.........|||.#.. +|......||.|..#.|#||...||.#.#.##..#..#.#....#.#..#| +#.|..##.....#..|...|#...#...|.......|.|..|#|...... +##...#....#..#..#....|...#|#.||.|...|.#..###|##|.| diff --git a/day18p1/main.c b/day18p1/main.c new file mode 100644 index 0000000..49c7809 --- /dev/null +++ b/day18p1/main.c @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include + +struct size2d { + unsigned w; + unsigned h; +}; + +struct buffer { + char *data; + size_t len; + size_t alloc; +}; + +void *xrealloc(void *ptr, size_t size) +{ + void *res = realloc(ptr, size); + if (!res) { + perror("realloc"); + exit(1); + } + return res; +} + +struct buffer buffer_alloc() +{ + struct buffer buffer; + buffer.len = 0; + buffer.alloc = 0x10; + buffer.data = xrealloc(NULL, buffer.alloc); + return buffer; +} + +void buffer_append(struct buffer *buffer, char c) +{ + if (buffer->alloc <= buffer->len) { + buffer->alloc *= 2; + buffer->data = xrealloc(buffer->data, buffer->alloc); + } + buffer->data[buffer->len++] = c; +} + +char *parse_acres(const char *fname, struct size2d *size) +{ + FILE *f = fopen(fname, "r"); + if (!f) { + perror(fname); + return NULL; + } + + struct buffer buffer = buffer_alloc(); + size->w = 0; + size->h = 0; + + unsigned width = 0; + int c; + + flockfile(f); + while ((c = getc_unlocked(f)) != EOF) { + if (c == '\n') { + if (!size->w) { + size->w = width; + } else { + if (size->w != width) { + fprintf(stderr, "ERROR: Not each line has the same width\n"); + goto error; + } + } + width = 0; + size->h++; + continue; + } + + if (c != '.' && c != '|' && c != '#') { + fprintf(stderr, "ERROR: Unknown character: '%c'\n", c); + goto error; + } + + buffer_append(&buffer, c); + width++; + } + funlockfile(f); + fclose(f); + + return realloc(buffer.data, buffer.len); + +error: + funlockfile(f); + fclose(f); + free(buffer.data); + return NULL; +} + +void advance_frame(char *acres, char *next, const struct size2d size) +{ + for (unsigned y = 0; y < size.h; y++) { + for (unsigned x = 0; x < size.w; x++) { + char *a = next + y * size.w + x; + + char surrounding[8] = {'\0'}; + if (y > 0) surrounding[0] = acres[(y - 1) * size.w + x]; + if (x > 0) surrounding[1] = acres[y * size.w + (x - 1)]; + if (y + 1 < size.h) surrounding[2] = acres[(y + 1) * size.w + x]; + if (x + 1 < size.w) surrounding[3] = acres[y * size.w + (x + 1)]; + if (y > 0 && x + 1 < size.w) + surrounding[4] = acres[(y - 1) * size.w + (x + 1)]; + if (y > 0 && x > 0) + surrounding[5] = acres[(y - 1) * size.w + (x - 1)]; + if (y + 1 < size.h && x > 0) + surrounding[6] = acres[(y + 1) * size.w + (x - 1)]; + if (y + 1 < size.h && x + 1 < size.w) + surrounding[7] = acres[(y + 1) * size.w + (x + 1)]; + + unsigned tally = 0; + unsigned tally2 = 0; + char new = 0; + + switch (*a) { + case '.': + case '|': + new = (*a == '.' ? '|' : '#'); + for (char *c = surrounding; c < surrounding + 8; c++) { + if (*c == new) tally++; + } + if (tally >= 3) *a = new; + break; + case '#': + for (char *c = surrounding; c < surrounding + 8; c++) { + if (*c == '#') tally++; + if (*c == '|') tally2++; + } + if (!(tally >= 1 && tally2 >= 1)) *a = '.'; + break; + } + } + } +} + +int render_bitmap(const char *fname, const char *acres, const struct size2d size) +{ + FILE *f = fopen(fname, "w"); + if (!f) { + perror(fname); + return 1; + } + + flockfile(f); + fprintf(f, "P6\n%u %u\n255\n", size.w, size.h); + + for (unsigned y = 0; y < size.h; y++) { + for (unsigned x = 0; x < size.w; x++) { + char color[3] = {255}; + + switch (acres[y * size.w + x]) { + case '.': + // Yellow + color[0] = 205; + color[1] = 255; + color[2] = 110; + break; + case '|': + // Green + color[0] = 0; + color[1] = 255; + color[2] = 0; + break; + case '#': + // Brown + color[0] = 192; + color[1] = 125; + color[2] = 0; + break; + } + + fwrite_unlocked(color, 3, 1, f); + } + } + + funlockfile(f); + fclose(f); + return 0; +} + +int main(int argc, char *argv[]) +{ + struct size2d size; + char *acres = parse_acres("input", &size); + if (!acres) return 1; + + unsigned minutes = 10; + int render = 0; + if (argc > 1) minutes = strtol(argv[1], NULL, 0); + if (argc > 2 && strcmp(argv[2], "-render") == 0) render = 1; + + char *next = xrealloc(NULL, size.w * size.h); + memcpy(next, acres, size.w * size.h); + + char *fname = NULL; + clock_t start = clock(); + for (unsigned i = 0; i <= minutes; i++) { + if (i != 0) { + advance_frame(acres, next, size); + memcpy(acres, next, size.w * size.h); + + if (i % 10000 == 0) { + double framespers = 10000 / ((double)(clock() - start) / CLOCKS_PER_SEC); + unsigned eta = (double)(minutes - i) / framespers; + fprintf(stderr, "Progress: %.2f%% (speed: %.2f frames/s, ETA: %u:%u:%u)\n", + (double)i / minutes * 100, framespers, + eta / 60 / 60, (eta / 60) % 60, eta % 60); + start = clock(); + } + } + + if (render) { + if (asprintf(&fname, "out/frame%04u.ppm", i) == -1) { + perror("asprintf"); + break; + } + if (render_bitmap(fname, acres, size)) break; + free(fname); + } + } + + unsigned wood = 0; + unsigned lumber = 0; + for (unsigned y = 0; y < size.h; y++) { + for (unsigned x = 0; x < size.w; x++) { + char c = acres[y * size.w + x]; + if (c == '|') wood++; + if (c == '#') lumber++; + } + } + + printf("Resource value: %u\n", wood * lumber); + + free(next); + free(acres); + return 0; +} diff --git a/day18p1/makegif.sh b/day18p1/makegif.sh new file mode 100755 index 0000000..5df75d9 --- /dev/null +++ b/day18p1/makegif.sh @@ -0,0 +1,2 @@ +#!/bin/sh +convert -monitor -resize 1000% -filter point -delay 5 -loop 0 out/*.ppm out.gif diff --git a/day18p1/out.gif b/day18p1/out.gif new file mode 100644 index 0000000..f05e320 Binary files /dev/null and b/day18p1/out.gif differ diff --git a/day18p1/out/.gitkeep b/day18p1/out/.gitkeep new file mode 100644 index 0000000..e69de29