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 }