advent2021

Advent of Code 2021 Solutions
git clone git://bsandro.tech/advent2021
Log | Files | Refs | README | LICENSE

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 }