cdoku

cdoku.git
git clone git://git.lenczewski.org/cdoku.git
Log | Files | Refs | README | LICENSE

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 }