advent2021

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

puzzle12.c (4047B)


      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 <stdbool.h>
      9 #include <assert.h>
     10 
     11 #include "util.h"
     12 
     13 #define STR_LEN 16384
     14 #define BOARD_SIZE 5
     15 
     16 struct board_t {
     17 	int tiles[BOARD_SIZE][BOARD_SIZE]; // 0-99 base, -1 marks drawn tiles
     18 	int rows_sig[BOARD_SIZE]; // sum of numbers that works as a "signature"
     19 	int cols_sig[BOARD_SIZE]; // once it goes down to -5 it means r/k are done
     20 	int sum;
     21 	bool won;
     22 };
     23 
     24 void fill_board(struct board_t *board, int row, const char *str);
     25 int check_board(struct board_t *board, int num);
     26 void print_boards(const struct array_t *boards);
     27 
     28 /* ****************************************************************** */
     29 
     30 void puzzle(const char *filename, int *result1, int *result2) {
     31 	FILE *infile = fopen(filename, "r");
     32 	if (infile == NULL) {
     33 		fprintf(stderr, "fopen() error: %s\n", strerror(errno));
     34 		return;
     35 	}
     36 
     37 	char buf[STR_LEN] = {0};
     38 	unsigned int line_num = 0;
     39 
     40 	struct array_t numbers = { .data = NULL };
     41 	struct array_t boards = { .data = NULL };
     42 
     43 	array_init(&numbers, sizeof(int), 100);
     44 	array_init(&boards, sizeof(struct board_t), 10);
     45 
     46 	struct board_t *current_board = NULL;
     47 	int current_row = -1;
     48 
     49 	while (fgets(buf, STR_LEN, infile) != NULL) {
     50 		// first line is always random numbers sequence
     51 		if (line_num == 0) {
     52 			parse_numbers_array(&numbers, buf, ",");
     53 
     54 		} else if (strlen(buf) == 1) { // line sized 1 is a separator before boards
     55 			if (boards.count >= boards.cap) {
     56 				array_expand(&boards);
     57 			}
     58 
     59 			struct board_t *data = (struct board_t *)boards.data;
     60 			current_board = &data[boards.count++];
     61 			current_row = 0;
     62 
     63 		} else { // filling the board
     64 			assert(current_board != NULL);
     65 			assert(current_row != -1);
     66 			fill_board(current_board, current_row++, buf);
     67 		}
     68 
     69 		++line_num;
     70 		bzero(buf, STR_LEN);
     71 	}
     72 
     73 	size_t active_boards = boards.count;
     74 
     75 	//print_boards(&boards);
     76 
     77 	// rolling
     78 	for (size_t i = 0; i < numbers.count; ++i) {
     79 		int num = ((int *)numbers.data)[i];
     80 
     81 		for (size_t j = 0; j < boards.count; ++j) {
     82 			struct board_t *board = &((struct board_t *)boards.data)[j];
     83 			if (board->won) continue;
     84 
     85 			int result = check_board(board, num);
     86 			if (result > 0) {
     87 				if (active_boards == boards.count) {
     88 					*result1 = result; // first winning board
     89 				} else {
     90 					*result2 = result; // last winning board
     91 				}
     92 				--active_boards;
     93 			}
     94 		}
     95 	}
     96 
     97 	//print_boards(&boards);
     98 
     99 	// mutiny! ignoring feof/ferror.
    100 	free(numbers.data);
    101 	free(boards.data);
    102 	fclose(infile);
    103 }
    104 
    105 /* ************************* BOILERPLATE ************************* */
    106 
    107 int check_board(struct board_t *board, int num) {
    108 	for (int r = 0; r < BOARD_SIZE; ++r) {
    109 		for (int k = 0; k < BOARD_SIZE; ++k) {
    110 			if (board->tiles[r][k] == num) {
    111 				board->tiles[r][k] = -1;
    112 				board->rows_sig[r] -= num + 1;
    113 				board->cols_sig[k] -= num + 1;
    114 				board->sum -= num;
    115 
    116 				if (board->rows_sig[r] == -BOARD_SIZE || board->cols_sig[k] == -BOARD_SIZE) {
    117 					board->won = true;
    118 					return board->sum * num;
    119 				}
    120 			}
    121 		}
    122 	}
    123 
    124 	return 0;
    125 }
    126 
    127 void print_boards(const struct array_t *boards) {
    128 	for (size_t i = 0; i < boards->count; ++i) {
    129 		const struct board_t *brd = (const struct board_t *)boards->data;
    130 		brd += i;
    131 		printf("\n----------- board %2zu ------------\n", i);
    132 		for (int r = 0; r < BOARD_SIZE; ++r) {
    133 			for (int k = 0; k < BOARD_SIZE; ++k) {
    134 				printf("[%3d]", brd->tiles[r][k]);
    135 			}
    136 			printf(" = [%3d]\n", brd->rows_sig[r]);
    137 		}
    138 		printf("=================================\n");
    139 		for (int k = 0; k < BOARD_SIZE; ++k) {
    140 			printf("[%3d]", brd->cols_sig[k]);
    141 		}
    142 		printf("\n");
    143 	}
    144 }
    145 
    146 void fill_board(struct board_t *board, int row, const char *str) {
    147 	char *tmp = strndup(str, STR_LEN);
    148 	assert(tmp != NULL);
    149 	char *token = NULL;
    150 	int col = 0;
    151 	while ((token = strsep(&tmp, " ")) != NULL) {
    152 		if (*token != '\0') { // WOWZA
    153 			int num = atoi(token);
    154 			board->tiles[row][col] = num;
    155 			board->rows_sig[row] += num;
    156 			board->cols_sig[col] += num;
    157 			board->sum += num;
    158 			++col;
    159 		}
    160 	}
    161 	assert(col == BOARD_SIZE);
    162 }