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.

158 lines
3.8 KiB

6 years ago
#include <stdio.h>
#include <limits.h>
#include <glib.h>
struct light {
int x;
int y;
int velx;
int vely;
};
struct rect {
int x;
int y;
int w;
int h;
};
struct light *parse_lights(const char *fname, unsigned *len)
{
FILE *f = fopen(fname, "r");
if (!f) {
perror(fname);
return NULL;
}
GArray *array = g_array_new(FALSE, TRUE, sizeof(struct light));
char *line = NULL;
size_t line_len = 0;
while (getline(&line, &line_len, f) != -1) {
struct light light;
sscanf(line, "position=<%d, %d> velocity=<%d, %d>",
&light.x, &light.y, &light.velx, &light.vely);
g_array_append_val(array, light);
}
*len = array->len;
free(line);
fclose(f);
return (struct light *)g_array_free(array, FALSE);
}
struct rect get_frame(struct light *lights, const unsigned lights_len)
{
struct rect res = {0};
if (!lights_len) return res;
res.x = lights->x;
res.y = lights->y;
int xmax = res.x;
int ymax = res.y;
for (struct light *light = lights + 1; light < lights + lights_len; light++) {
if (light->x < res.x) res.x = light->x;
if (light->y < res.y) res.y = light->y;
if (light->x > xmax) xmax = light->x;
if (light->y > ymax) ymax = light->y;
}
res.w = xmax - res.x + 1;
res.h = ymax - res.y + 1;
return res;
}
void advance_frame(struct light *lights, const unsigned lights_len)
{
for (struct light *light = lights; light < lights + lights_len; light++) {
light->x += light->velx;
light->y += light->vely;
}
}
int check_limit(const struct rect limit, struct light *lights,
const unsigned lights_len)
{
for (struct light *light = lights; light < lights + lights_len; light++) {
if (light->x < limit.x) return 1;
if (light->y < limit.y) return 1;
if (light->x > limit.x + limit.w) return 1;
if (light->y > limit.y + limit.h) return 1;
}
return 0;
}
int make_bitmap(const char *fname, const struct rect frame,
struct light *lights, const unsigned lights_len)
{
int bitmap_width = frame.w / CHAR_BIT;
if (frame.w % CHAR_BIT != 0) bitmap_width++;
size_t bitmap_size = frame.h * bitmap_width;
char (*bitmap)[bitmap_width] = calloc(1, bitmap_size);
if (!bitmap) {
perror("calloc");
return 1;
}
for (struct light *light = lights; light < lights + lights_len; light++) {
if (light->x < frame.x) continue;
if (light->y < frame.y) continue;
if (light->x > frame.x + frame.w) continue;
if (light->y > frame.y + frame.h) continue;
int bitmap_x = light->x - frame.x;
int bitmap_y = light->y - frame.y;
bitmap[bitmap_y][bitmap_x / CHAR_BIT] |= 1 << (CHAR_BIT - bitmap_x % CHAR_BIT - 1);
}
FILE *f = fopen(fname, "w");
if (!f) {
perror(fname);
free(bitmap);
return 1;
}
fprintf(f, "P4\n%d %d\n", frame.w, frame.h);
fwrite(bitmap, bitmap_size, 1, f);
free(bitmap);
fclose(f);
return 0;
}
#define REASONABLE_HEIGHT 100
int main()
{
unsigned lights_len;
struct light *lights = parse_lights("input", &lights_len);
if (!lights) return 1;
struct rect frame;
while (1) {
frame = get_frame(lights, lights_len);
if (frame.h <= REASONABLE_HEIGHT) break;
advance_frame(lights, lights_len);
}
GString *fname = g_string_new(NULL);
unsigned frame_id = 0;
while (check_limit(frame, lights, lights_len) == 0) {
g_string_printf(fname, "out/frame%03d.pbm", frame_id++);
if (make_bitmap(fname->str, frame, lights, lights_len)) break;
advance_frame(lights, lights_len);
}
g_string_free(fname, TRUE);
free(lights);
return 0;
}