advent2023

Advent of Code 2023 solutions
git clone git://bsandro.tech/advent2023
Log | Files | Refs | LICENSE

puzzle.c (2969B)


      1 #define _DEFAULT_SOURCE
      2 
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <errno.h>
      7 #include <string.h>
      8 #include <strings.h>
      9 #include <assert.h>
     10 #include <stdbool.h>
     11 
     12 #define STR_LEN 2048
     13 // 140x140 for real one
     14 //#define FIELD_SIZE 10
     15 #define FIELD_SIZE 140
     16 
     17 bool is_digit(char b) {
     18 	return b>='0' && b<='9';
     19 }
     20 
     21 typedef struct Gear {
     22 	int pos; // y * FIELD_SIZE + x
     23 	int part;
     24 	struct Gear *next;
     25 } Gear;
     26 
     27 Gear * find_gear(Gear *gears, int pos) {
     28 	Gear *gear = gears;
     29 	while (gear != NULL) {
     30 		if (gear->pos == pos) {
     31 			return gear;
     32 		}
     33 		gear = gear->next;
     34 	}
     35 	return NULL;
     36 }
     37 
     38 Gear * make_gear(Gear *prev) {
     39 	Gear *gear = malloc(sizeof(Gear));
     40 	memset(gear, 0, sizeof(Gear));
     41 	if (prev!=NULL) {
     42 		prev->next = gear;
     43 	}
     44 	return gear;
     45 }
     46 
     47 bool check_part(int x, int y, const char (*field)[FIELD_SIZE][FIELD_SIZE]) {
     48 	for (int dy=-1; dy<=1; ++dy) {
     49 		for (int dx=-1; dx<=1; ++dx) {
     50 			int dy1=y+dy;
     51 			int dx1=x+dx;
     52 			if (dy1>=0 && dy1<FIELD_SIZE && dx1>=0 && dx1<FIELD_SIZE) {
     53 				if (!is_digit((*field)[dy1][dx1]) && (*field)[dy1][dx1]!='.') {
     54 					return true;
     55 				}
     56 			}
     57 		}
     58 	}
     59 	return false;
     60 }
     61 
     62 int check_gear(int x, int y, const char (*field)[FIELD_SIZE][FIELD_SIZE]) {
     63 	for (int dy=-1; dy<=1; ++dy) {
     64 		for (int dx=-1; dx<=1; ++dx) {
     65 			int dy1=y+dy;
     66 			int dx1=x+dx;
     67 			if (dy1>=0 && dy1<FIELD_SIZE && dx1>=0 && dx1<FIELD_SIZE) {
     68 				if ((*field)[dy1][dx1]=='*') {
     69 					return dy1*FIELD_SIZE+dx1;
     70 				}
     71 			}
     72 		}
     73 	}
     74 	return -1;
     75 }
     76 
     77 void puzzle(const char *filename, long long *result1, long long *result2) {
     78 	FILE *infile = fopen(filename, "r");
     79 	if (infile == NULL) {
     80 		fprintf(stderr, "fopen() error: %s\n", strerror(errno));
     81 		return;
     82 	}
     83 
     84 	char field[FIELD_SIZE][FIELD_SIZE] = {0};
     85 	char buf[STR_LEN] = {0};
     86 	unsigned int line_num = 0;
     87 
     88 	*result1 = 0;
     89 	*result2 = 0;
     90 
     91 	while (fgets(buf, STR_LEN, infile) != NULL) {
     92 		for (int i=0; i<FIELD_SIZE; ++i) {
     93 			field[line_num][i] = buf[i];
     94 		}
     95 		++line_num;
     96 		bzero(buf, STR_LEN);
     97 	}
     98 
     99 	// mutiny! ignoring feof/ferror.
    100 	fclose(infile);
    101 
    102 	Gear *gears = NULL;
    103 	Gear *gear_last = NULL;
    104 
    105 	for (int y=0; y<FIELD_SIZE; ++y) {
    106 		int x = 0;
    107 		while (x<FIELD_SIZE) {
    108 			int digit = 0;
    109 			bool is_part = false;
    110 			int gear_pos = -1;
    111 			while (is_digit(field[y][x++])) {
    112 				int cx = x-1;
    113 				if (cx>=FIELD_SIZE) break; // too lazy to make it sane
    114 				if (check_part(cx, y, &field)) is_part = true;
    115 				digit = digit*10 + field[y][cx] - '0';
    116 				if (gear_pos==-1) gear_pos = check_gear(cx, y, &field);
    117 			}
    118 			if (digit>0 && is_part) {
    119 				//printf("%d\n", digit);
    120 				*result1 += digit;
    121 
    122 				if (gear_pos != -1) {
    123 					Gear *gear = find_gear(gears, gear_pos);
    124 					if (gear!=NULL) {
    125 						*result2 += digit * gear->part;
    126 						gear->part = digit;
    127 					} else {
    128 						gear = make_gear(gear_last);
    129 						gear->pos = gear_pos;
    130 						gear->part = digit;
    131 						if (gears==NULL) gears = gear;
    132 
    133 						if (gear_last!=NULL) {
    134 							gear_last->next = gear;
    135 						}
    136 						gear_last = gear;
    137 					}
    138 				}
    139 			}
    140 		}
    141 	}
    142 }