main.c (15613B)
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <assert.h> 6 #include <stdarg.h> 7 8 // https://en.wikipedia.org/wiki/Knuth's_Algorithm_X 9 // https://github.com/Elementrix08/Sudoku/blob/master/Dancing-Links.cpp 10 // https://garethrees.org/2007/06/10/zendoku-generation/#figure-2 11 12 #define CELL unsigned long 13 14 // sudoku board. top left hand corner is (0,0) 15 CELL *board = NULL; 16 unsigned int board_size = 0, board_grid_size = 0, board_cell_size = 0, board_line_size = 0; 17 18 const char BOARD_EMPTY = '.', BOARD_CSEP = ',', BOARD_VWALL = '|', BOARD_HWALL = '=', BOARD_JOIN = '#'; 19 20 // if defined, will ignore sudoku grid and construct test matrix for dlx 21 #define DLX_TESTING 22 #undef DLX_TESTING 23 24 #define DEBUG_STEP_PRINT 25 #undef DEBUG_STEP_PRINT 26 27 /* =========================================================================== 28 * Sudoku Grid Utilities 29 * =========================================================================== 30 */ 31 32 CELL board_get(unsigned int i, unsigned int j) { 33 size_t idx = i + (j * board_line_size); 34 35 if (board && idx < board_size) { 36 return board[idx]; 37 } 38 39 return 0; 40 } 41 42 void board_set(unsigned int i, unsigned int j, CELL value) { 43 size_t idx = i + (j * board_line_size); 44 45 if (board && idx < board_size) { 46 board[idx] = value; 47 } 48 } 49 50 bool board_try_resize(size_t size) { 51 if (size) { 52 board_size = size; 53 board = realloc(board, size * sizeof(CELL)); 54 55 return board != NULL; 56 } 57 58 return false; 59 } 60 61 bool try_read_board(FILE *input) { 62 static char buf[4096]; 63 const size_t BUF_SIZE = sizeof(buf) / sizeof(char); 64 65 const char INPUT_CSEP[] = { BOARD_CSEP, '\0' }; 66 const char INPUT_VWALL[] = { BOARD_VWALL, '\0' }; 67 68 // get first line in sudoku grid 69 char *line = fgets(buf, BUF_SIZE, input); 70 71 unsigned int cell_size = 0, line_size = 0, grid_size = 0; 72 char *first_cell = strtok(line, INPUT_VWALL); 73 size_t first_cell_len = strlen(first_cell); 74 75 if (first_cell) { 76 // count the number of cell value separators in the first cell 77 for (size_t i = 0; i < first_cell_len; i++) { 78 cell_size += first_cell[i] == BOARD_CSEP; 79 } 80 cell_size++; 81 82 line_size = cell_size * cell_size; 83 grid_size = line_size * line_size; 84 } 85 86 board_cell_size = cell_size; 87 board_line_size = line_size; 88 board_grid_size = grid_size; 89 90 if (!board_try_resize(grid_size)) { 91 printf("Failed to resize board to required amount: %u!\n", grid_size); 92 return false; 93 } 94 95 if (fseek(input, 0, SEEK_SET)) { 96 printf("Failed to seek to start of file!\n"); 97 return false; 98 } 99 100 for (unsigned int i = 0, j = 0; j < line_size; j++) { 101 line = fgets(buf, BUF_SIZE, input); 102 103 // ignore horizontal cell separator lines 104 if (line[0] == BOARD_HWALL) { j--; continue; } 105 106 char *cell_saveptr = NULL, *value_saveptr = NULL; 107 108 char *cell = strtok_r(line, INPUT_VWALL, &cell_saveptr); 109 while (cell) { 110 char *value = strtok_r(cell, INPUT_CSEP, &value_saveptr); 111 while (value) { 112 board_set(i++, j, strtoul(value, NULL, 10)); 113 114 value = strtok_r(NULL, INPUT_CSEP, &value_saveptr); 115 } 116 117 cell = strtok_r(NULL, INPUT_VWALL, &cell_saveptr); 118 } 119 120 i = 0; 121 memset(buf, 0, strlen(line)); 122 } 123 124 return true; 125 } 126 127 void board_print() { 128 char value_buf[3] = { 0 }; 129 130 for (unsigned int j = 0; j < board_line_size; j++) { 131 if (j && (j % board_cell_size) == 0) { 132 for (unsigned int k = 0; k < board_line_size; k++) { 133 if (k && (k % board_cell_size) == 0) { 134 printf("%c%c", BOARD_JOIN, BOARD_HWALL); 135 } 136 137 const char BOARD_HSEP[] = { 138 BOARD_HWALL, BOARD_HWALL, BOARD_HWALL, BOARD_HWALL, '\0' 139 }; 140 printf("%s", BOARD_HSEP); 141 } 142 143 printf("\n"); 144 } 145 146 for (unsigned int i = 0; i < board_line_size; i++) { 147 CELL value = board_get(i, j); 148 snprintf(value_buf, 3, "%lu", value); 149 150 if (i && (i % board_cell_size) == 0) { 151 printf("%c ", BOARD_VWALL); 152 } 153 154 printf("%3s ", value_buf); 155 } 156 157 printf("\n"); 158 } 159 160 printf("\n"); 161 } 162 163 /* =========================================================================== 164 * Dancing Links + Algorithm X 165 * =========================================================================== 166 */ 167 168 struct dlx_matrix; 169 struct dlx_node; 170 171 enum DLX_TYPE { 172 DLX_TYPE_DATA = 0, 173 DLX_TYPE_COLUMN = 1 174 }; 175 176 struct dlx_node { 177 enum DLX_TYPE type; 178 struct dlx_node *left, *right, *up, *down; 179 180 union { 181 struct { 182 size_t row_id; 183 struct dlx_node *parent; 184 } data; // matrix data node 185 186 struct { 187 size_t id; 188 size_t count; 189 } column; // matrix column node 190 }; 191 }; 192 193 struct dlx_matrix { 194 struct dlx_node *root; 195 bool solved; 196 }; 197 198 struct dlx_node *node_create(enum DLX_TYPE type, struct dlx_node *parent, size_t id) { 199 struct dlx_node *node = malloc(sizeof(struct dlx_node)); 200 201 node->type = type; 202 203 node->left = NULL; 204 node->right = NULL; 205 node->up = NULL; 206 node->down = NULL; 207 208 switch (type) { 209 case DLX_TYPE_DATA: 210 node->data.row_id = id; 211 node->data.parent = parent; 212 break; 213 214 case DLX_TYPE_COLUMN: 215 node->column.id = id; 216 node->column.count = 0; 217 break; 218 } 219 220 return node; 221 } 222 223 void node_free(struct dlx_node *val) { 224 free(val); 225 } 226 227 typedef unsigned char linkmask_t; 228 229 const linkmask_t LINK_UP = 0b00000001; 230 const linkmask_t LINK_RIGHT = 0b00000010; 231 const linkmask_t LINK_DOWN = 0b00000100; 232 const linkmask_t LINK_LEFT = 0b00001000; 233 234 void link_nodes(struct dlx_node *a, struct dlx_node *b, linkmask_t mask) { 235 if (!a || !b) return; 236 237 if (mask & LINK_LEFT) { a->left = b; b->right = a; } 238 if (mask & LINK_RIGHT) { a->right = b; b->left = a; } 239 if (mask & LINK_UP) { a->up = b; b->down = a; } 240 if (mask & LINK_DOWN) { a->down = b; b->up = a; } 241 } 242 243 // converts the board into a sparse matrix. 244 struct dlx_matrix *matrix_create() { 245 struct dlx_matrix *mat = malloc(sizeof(struct dlx_matrix)); 246 247 mat->solved = false; 248 249 // we need to create the header value for our columns 250 struct dlx_node *h = node_create(DLX_TYPE_COLUMN, NULL, 0); 251 mat->root = h; 252 253 // the constraints will be the columns in our dlx matrix. there are 4 254 // different sets of constraints that we need to solve for: 255 // - row-column : represents the need to have a given number at the 256 // intersection of a given row and given column 257 // - row-number : represents the need to have 1 of a given number in 258 // a given row 259 // - col-number : represents the need to have 1 of a given number in 260 // a given column 261 // - box-number : represents the need to have 1 of a given number in 262 // a given cell (box) 263 size_t constraint_set_size = board_line_size * board_line_size; 264 size_t cols = 4 * constraint_set_size; 265 266 struct dlx_node **constraints = malloc(cols * sizeof(struct dlx_node*)); 267 268 // we populate the column object row, linking all the different columns 269 // together. this linked list is made circular by the final linking back 270 // to the header 271 struct dlx_node *previous_constraint = h; 272 for (size_t col = 0; col < cols; col++) { 273 struct dlx_node *constraint = node_create(DLX_TYPE_COLUMN, NULL, col); 274 275 constraints[col] = constraint; 276 277 // 2D linked lists form a torus, allowing us to later easily 278 // add data nodes to each column 279 link_nodes(constraint, constraint, LINK_DOWN); 280 link_nodes(previous_constraint, constraint, LINK_RIGHT); 281 282 previous_constraint = constraint; 283 } 284 link_nodes(previous_constraint, h, LINK_RIGHT); 285 286 // the possibilities will be the different placements of every number 287 // in every possible space on the board. these will be the rows in our 288 // dlx matrix 289 size_t placement_set_size = board_grid_size; 290 size_t number_set_size = board_line_size; 291 size_t rows = number_set_size * placement_set_size; 292 293 // we populate each row with 4 nodes, one for each of the different 294 // constraint 295 for (size_t row = 0; row < rows; row++) { 296 size_t row_idx = row / board_grid_size; 297 size_t col_idx = (row / board_line_size) % board_line_size; 298 size_t offset = row % board_line_size; 299 300 // we only create a data object for a sudoku grid cell if the 301 // cell has a non-zero value (aka has a valid value), and if 302 // the value if equal to the current offset. this is because 303 // the grid is 2D, and the row is 1D, so we have to map from 304 // the grid to the row (this is done via the offset index) 305 CELL value = board_get(col_idx, row_idx); 306 if (value && value != offset + 1) 307 continue; 308 309 310 // to create our data elements, we need to first fetch the 311 // constraint each element will satisfy. this is done by mapping 312 // the current row_idx, col_idx, and offset into a flat index 313 // into the constraints array 314 struct dlx_node *num_constraint = constraints[(0 * constraint_set_size) + (row / board_line_size)]; 315 struct dlx_node *row_constraint = constraints[(1 * constraint_set_size) + (row_idx * board_line_size) + offset]; 316 struct dlx_node *col_constraint = constraints[(2 * constraint_set_size) + (col_idx * board_line_size) + offset]; 317 struct dlx_node *box_constraint = constraints[(3 * constraint_set_size) + ((board_cell_size * (row_idx / board_cell_size) + (col_idx / board_cell_size)) * board_line_size) + offset]; 318 319 // we create the data elements with the correct row id and parent constraint (column header) 320 struct dlx_node *num_node = node_create(DLX_TYPE_DATA, num_constraint, row); 321 struct dlx_node *row_node = node_create(DLX_TYPE_DATA, row_constraint, row); 322 struct dlx_node *col_node = node_create(DLX_TYPE_DATA, col_constraint, row); 323 struct dlx_node *box_node = node_create(DLX_TYPE_DATA, box_constraint, row); 324 325 // we need to keep track of the number of elements in each column 326 num_constraint->column.count++; 327 row_constraint->column.count++; 328 col_constraint->column.count++; 329 box_constraint->column.count++; 330 331 // link nodes onto bottom nodes in columns 332 link_nodes(num_constraint->up, num_node, LINK_DOWN); 333 link_nodes(row_constraint->up, row_node, LINK_DOWN); 334 link_nodes(col_constraint->up, col_node, LINK_DOWN); 335 link_nodes(box_constraint->up, box_node, LINK_DOWN); 336 337 // link column headers onto bottoms of nodes 338 link_nodes(num_constraint, num_node, LINK_UP); 339 link_nodes(row_constraint, row_node, LINK_UP); 340 link_nodes(col_constraint, col_node, LINK_UP); 341 link_nodes(box_constraint, box_node, LINK_UP); 342 343 // link row across 344 link_nodes(num_node, row_node, LINK_RIGHT); 345 link_nodes(row_node, col_node, LINK_RIGHT); 346 link_nodes(col_node, box_node, LINK_RIGHT); 347 link_nodes(box_node, num_node, LINK_RIGHT); 348 } 349 350 free(constraints); 351 352 return mat; 353 } 354 355 void matrix_free(struct dlx_matrix *val) { 356 struct dlx_node *root = val->root; 357 for (struct dlx_node *column = root->left, *next_column; column != root; column = next_column) { 358 for (struct dlx_node *row = column->up, *next_row; row != column; row = next_row) { 359 next_row = row->up; 360 node_free(row); 361 } 362 363 next_column = column->left; 364 node_free(column); 365 } 366 367 node_free(root); 368 free(val); 369 } 370 371 struct dlx_node *choose_min_length_column(struct dlx_matrix *matrix) { 372 size_t min_count = (2 << sizeof(size_t)) - 1; 373 374 struct dlx_node *root = matrix->root, *best = NULL; 375 for (struct dlx_node *curr = root->right; curr != root; curr = curr->right) { 376 if (curr->column.count < min_count) { 377 best = curr; 378 min_count = curr->column.count; 379 } 380 } 381 382 return best; 383 } 384 385 void cover_column(struct dlx_node *col) { 386 assert(col->type == DLX_TYPE_COLUMN); 387 // cut column from column list 388 col->left->right = col->right; 389 col->right->left = col->left; 390 391 // removes column's rows from other columns 392 for (struct dlx_node *row = col->down; row != col; row = row->down) { 393 // affect all nodes in same row 394 for (struct dlx_node *node = row->right; node != row; node = node->right) { 395 // cut node from linked list 396 node->up->down = node->down; 397 node->down->up = node->up; 398 399 node->data.parent->column.count--; 400 } 401 } 402 403 } 404 405 void uncover_column(struct dlx_node *col) { 406 assert(col->type == DLX_TYPE_COLUMN); 407 // restores column's rows in other columns in inverse order 408 for (struct dlx_node *row = col->up; row != col; row = row->up) { 409 // affect all nodes in same row 410 for (struct dlx_node *node = row->left; node != row; node = node->left) { 411 node->data.parent->column.count++; 412 413 // restore node to the linked list 414 node->down->up = node; 415 node->up->down = node; 416 } 417 } 418 419 // restore column to column list 420 col->right->left = col; 421 col->left->right = col; 422 } 423 424 void step_print(unsigned int k, const char *format, ...) { 425 #ifdef DEBUG_STEP_PRINT 426 static char buf[4096]; 427 428 size_t format_len = strlen(format); 429 size_t buf_len = format_len + k; 430 431 for (size_t i = 0, j = k; i < buf_len; i++) { 432 if (j) { 433 buf[i] = '\t'; 434 j--; 435 } else { 436 buf[i] = format[i - k]; 437 } 438 } 439 buf[buf_len] = '\0'; 440 441 va_list argp; 442 va_start(argp, format); 443 vprintf(buf, argp); 444 va_end(argp); 445 #endif 446 } 447 448 bool solve_impl(struct dlx_matrix *matrix, unsigned int k, struct dlx_node ***solution, size_t *solution_len); 449 bool solve_impl(struct dlx_matrix *matrix, unsigned int k, struct dlx_node ***solution, size_t *solution_len) { 450 struct dlx_node *root = matrix->root; 451 452 step_print(k, "Solve(%u):\n", k); 453 454 if (root->right == root) { 455 step_print(k, "Solved!\n"); 456 return true; // matrix has no columns, found solution 457 } 458 459 struct dlx_node *col = choose_min_length_column(matrix); 460 step_print(k, "Selected column: %lu with %lu elements\n", col->column.id, col->column.count); 461 462 cover_column(col); 463 step_print(k, "Covered column: %lu\n", col->column.id); 464 465 for (struct dlx_node *row = col->down; row != col; row = row->down) { 466 step_print(k, "Selected row: %lu\n", row->data.row_id); 467 468 if (!matrix->solved) { 469 // push row to solution set 470 *solution_len += 1; 471 *solution = realloc(*solution, *solution_len * sizeof(struct dlx_node*)); 472 (*solution)[*solution_len - 1] = row; 473 } 474 475 for (struct dlx_node *node = row->right; node != row; node = node->right) { 476 step_print(k, "Covering adjacent column: %lu\n", node->data.parent->column.id); 477 cover_column(node->data.parent); 478 } 479 480 if (solve_impl(matrix, k + 1, solution, solution_len)) { 481 matrix->solved = true; 482 } 483 484 if (!matrix->solved) { 485 // pop row from solution set 486 *solution_len -= 1; 487 (*solution)[*solution_len] = NULL; 488 *solution = realloc(*solution, *solution_len * sizeof(struct dlx_node*)); 489 } 490 491 for (struct dlx_node *node = row->left; node != row; node = node->left) { 492 step_print(k, "Uncovering adjacent column: %lu\n", node->data.parent->column.id); 493 uncover_column(node->data.parent); 494 } 495 } 496 497 uncover_column(col); 498 step_print(k, "Uncovered column: %lu\n", col->column.id); 499 500 return matrix->solved; 501 } 502 503 bool solve(struct dlx_matrix *matrix, struct dlx_node ***solution, size_t *solution_len) { 504 return solve_impl(matrix, 0, solution, solution_len); 505 } 506 507 int main(int argc, char **argv) { 508 if (argc < 2) { 509 printf("Please pass the name of the input file as a parameter!\n"); 510 return -1; 511 } 512 513 FILE *input = fopen(argv[1], "r"); 514 515 if (!input) { 516 printf("Could not open input file!\n"); 517 return -1; 518 } 519 520 if (!try_read_board(input)) { 521 printf("Failed to parse board!\n"); 522 return -1; 523 } 524 525 fclose(input); 526 527 board_print(); 528 529 struct dlx_matrix *board_repr = matrix_create(); 530 531 struct dlx_node **solution = NULL; 532 size_t solution_len = 0; 533 534 if (!solve(board_repr, &solution, &solution_len)) { 535 printf("Failed to find a solution!\n"); 536 matrix_free(board_repr); 537 free(solution); 538 return -1; 539 } 540 541 matrix_free(board_repr); 542 543 printf("Solution Found:\n"); 544 for (size_t i = 0; i < solution_len; i++) { 545 unsigned int row_id = solution[i]->data.row_id; 546 547 size_t row_idx = row_id / board_grid_size; 548 size_t col_idx = (row_id / board_line_size) % board_line_size; 549 size_t offset = (row_id % board_line_size) + 1; 550 551 board_set(col_idx, row_idx, offset); 552 } 553 554 board_print(); 555 556 free(solution); 557 558 return 0; 559 }