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