#include #include #include 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; }