puzzle.c (4907B)
1 #define _DEFAULT_SOURCE 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <errno.h> 6 #include <string.h> 7 #include <strings.h> 8 #include <assert.h> 9 #include <ctype.h> 10 #include <limits.h> 11 #include <stdbool.h> 12 13 #include "util.h" 14 15 #define STR_LEN 128 16 17 struct point_t { 18 int x; 19 int y; 20 }; 21 22 struct fold_t { 23 int x; 24 int y; 25 }; 26 27 void parse_point(struct array_t *points, const char *str); 28 void parse_fold(struct array_t *folds, const char *str); 29 void print_points(struct array_t *points); 30 struct point_t flip_point(const struct point_t point, const struct point_t fold); 31 void add_point(struct array_t *points, struct point_t point); 32 void draw_points(const struct array_t *points); 33 34 void puzzle(const char *filename) { 35 FILE *infile = fopen(filename, "r"); 36 if (infile == NULL) { 37 fprintf(stderr, "fopen() error: %s\n", strerror(errno)); 38 return; 39 } 40 41 char buf[STR_LEN] = {0}; 42 unsigned int line_num = 0; 43 44 struct array_t points = { .data = NULL }; 45 array_init(&points, sizeof(struct point_t), 10); 46 struct array_t folds = { .data = NULL }; 47 array_init(&folds, sizeof(struct fold_t), 10); 48 49 bool folds_started = false; 50 while (fgets(buf, STR_LEN, infile) != NULL) { 51 if (strlen(buf) == 1) { 52 folds_started = true; 53 continue; 54 } 55 56 if (folds_started) { 57 parse_fold(&folds, buf); 58 } else { 59 parse_point(&points, buf); 60 } 61 62 ++line_num; 63 bzero(buf, STR_LEN); 64 } 65 66 for (size_t f = 0; f < folds.count; ++f) { 67 struct array_t points_folded = { .data = NULL }; 68 array_init(&points_folded, sizeof(struct point_t), 10); 69 70 struct point_t fold = ((struct point_t *)folds.data)[f]; 71 72 for (size_t i = 0; i < points.count; ++i) { 73 const struct point_t *data = points.data; 74 add_point(&points_folded, flip_point(data[i], fold)); 75 } 76 77 if (f == 0) { 78 printf("Puzzle #1: %zu\n", points_folded.count); 79 } 80 81 // copy folded points over old ones 82 free(points.data); 83 points.data = points_folded.data; 84 points.cap = points_folded.cap; 85 points.count = points_folded.count; 86 } 87 88 printf("Puzzle #2:\n"); 89 draw_points(&points); 90 91 // mutiny! ignoring feof/ferror. 92 fclose(infile); 93 } 94 95 struct point_t flip_point(const struct point_t point, const struct point_t fold) { 96 struct point_t p1 = point; 97 if (fold.x > 0 && point.x > fold.x) { 98 p1.x = 2 * fold.x - point.x; 99 } else if (fold.y > 0 && point.y > fold.y) { 100 p1.y = 2 * fold.y - point.y; 101 } 102 return p1; 103 } 104 105 void add_point(struct array_t *points, struct point_t point) { 106 assert(points != NULL); 107 struct point_t *data = points->data; 108 for (size_t i = 0; i < points->count; ++i) { 109 if (data[i].x == point.x && data[i].y == point.y) { 110 return; 111 } 112 } 113 114 if (points->count >= points->cap) { 115 array_expand(points); 116 } 117 data = points->data; 118 data[points->count++] = point; 119 } 120 121 void parse_point(struct array_t *points, const char *str) { 122 assert(points != NULL); 123 assert(str != NULL); 124 char *tmp = strndup(str, STR_LEN); 125 assert(tmp != NULL); 126 char *token = NULL; 127 128 int numbers[2] = {0}; 129 int i = 0; 130 while ((token = strsep(&tmp, ",\n")) != NULL) { 131 if (*token != '\0') { 132 assert(i < 2); 133 numbers[i] = atoi(token); 134 ++i; 135 } 136 } 137 138 if (points->count >= points->cap) { 139 array_expand(points); 140 } 141 142 struct point_t *data = points->data; 143 data[points->count++] = (struct point_t){ .x=numbers[0], .y=numbers[1] }; 144 } 145 146 void parse_fold(struct array_t *folds, const char *str) { 147 assert(folds != NULL); 148 assert(str != NULL); 149 char *tmp = strndup(str, STR_LEN); 150 assert(tmp != NULL); 151 char *token = NULL; 152 153 int i = 0; 154 int is_x = -1; // 0 is y, 1 is x 155 struct point_t fold = {0}; 156 while ((token = strsep(&tmp, "=\n")) != NULL) { 157 if (*token != '\0') { 158 assert(i < 2); 159 if (is_x == -1) { 160 size_t len = strlen(token); 161 // we're just taking last character and checking if it is 'x' 162 is_x = token[len-1] == 'x'; 163 } else if (is_x == 0) { 164 fold.y = atoi(token); 165 } else if (is_x == 1) { 166 fold.x = atoi(token); 167 } else { 168 assert(0 == 1); 169 } 170 ++i; 171 } 172 } 173 174 if (folds->count >= folds->cap) { 175 array_expand(folds); 176 } 177 178 struct point_t *data = folds->data; 179 data[folds->count++] = fold; 180 } 181 182 void print_points(struct array_t *points) { 183 assert(points != NULL); 184 struct point_t *data = points->data; 185 for (size_t i = 0; i < points->count; ++i) { 186 printf("x: %2d, y: %2d\n", data[i].x, data[i].y); 187 } 188 } 189 190 void draw_points(const struct array_t *points) { 191 assert(points != NULL); 192 const struct point_t *data = points->data; 193 int x_max = 0; 194 int y_max = 0; 195 for (size_t i = 0; i < points->count; ++i) { 196 x_max = data[i].x > x_max ? data[i].x : x_max; 197 y_max = data[i].y > y_max ? data[i].y : y_max; 198 } 199 x_max += 1; 200 y_max += 1; 201 202 char *buffer = malloc(x_max * y_max); 203 memset(buffer, ' ', x_max * y_max); 204 205 for (size_t i = 0; i < points->count; ++i) { 206 buffer[data[i].y * x_max + data[i].x] = '#'; 207 } 208 209 for (int y = 0; y < y_max; ++y) { 210 for (int x = 0; x < x_max; ++x) { 211 printf("%c", buffer[y*x_max + x]); 212 } 213 printf("\n"); 214 } 215 216 free(buffer); 217 }