Advent of Code 2018
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
6.2 KiB

6 years ago
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
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;
}