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.
		
		
		
		
		
			
		
			
				
					
					
						
							157 lines
						
					
					
						
							3.8 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							157 lines
						
					
					
						
							3.8 KiB
						
					
					
				| #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; | |
| }
 | |
| 
 |