|
sudoku-solver
A side project written in C to solve Sudoku puzzles.
|
|
Holds all the logic for the sudoku solver.
More...
|
| int | process_arguments (int argc, char *argv[], int *verbosity, int *bulkFlag, int *timeFlag, int *forceFlag, int *debugFlag, char **inCsv, char **outCsv, char **missing) |
| | Processes the command line arguments provided. More...
|
| |
| int | initialize_globals (char buffer[ROW_BUF_SIZE], int isBulk) |
| | Allocates and initializes the global variables. More...
|
| |
|
void | free_globals () |
| | Frees the dynamically allocated global variables.
|
| |
| int | addToValid (int *tokenCount, char *token) |
| | Add the token to the valid array if not full. More...
|
| |
| int | process_token (int *tokenCount, char *token, int row, int col) |
| | Sanitize, and set the grid to reference a valid token. More...
|
| |
| int | read_csv (const char *fileName, char *missing) |
| | Reads from a csv file and loads into the grid. More...
|
| |
| void | get_columns_bitmap (int array[VALUES][VALUES]) |
| | Stores all columns as a bitmap of numbers. More...
|
| |
| void | get_boxes_bitmap (int array[SUB_SIZE][SUB_SIZE][VALUES]) |
| | Stores all columns as a bitmap of numbers. More...
|
| |
| void | get_row_bitmap (int row, int array[VALUES]) |
| | Stores the current row as a bitmap of numbers. More...
|
| |
| void | pre_process (int *cellsLeft) |
| | Initializes a bitmap to hold possible values. More...
|
| |
| void | print_array (int *array, int len, int isPadded) |
| | Prints a grid cell's possible contents. More...
|
| |
|
void | print_possible () |
| | Prints all possible values for each cell in the grid (FOR TESTING).
|
| |
| void | print_line (char type, int length) |
| | Prints a line of given length with a given character. More...
|
| |
|
void | print_grid () |
| | Prints the current state of the grid in a formatted output.
|
| |
| int * | make_pair (int row, int col) |
| | Dynamically allocated and initializes a pair of values. More...
|
| |
| int * | find_single () |
| | Gets the next pair of row and column where there is only one possibility. More...
|
| |
| int | get_possible_value (int *pair) |
| | Assumes there is only one value in the bitmap and retrieves it. More...
|
| |
| int * | unique_in_row (int *value) |
| | Gets position which is only place for a possible value in a row. More...
|
| |
| int * | unique_in_col (int *value) |
| | Gets position which is only place for a possible value in a col. More...
|
| |
| int * | unique_in_box (int *value) |
| | Gets position which is the only place for a possible value in a box. More...
|
| |
| int * | unique_in_range (int mode, int *value, int verbosity) |
| | Gets position which is only place for a possible value in a house. More...
|
| |
| int | remove_value_from_row (int row, int value, int mask[VALUES], int verbosity) |
| | Removes a value from the possibilities of all others in the same row. More...
|
| |
| int | remove_value_from_column (int col, int value, int mask[VALUES], int verbosity) |
| | Removes a value from the possibilities of all others in the same column. More...
|
| |
| int | remove_value_from_box (int row, int col, int value, int mask[VALUES], int verbosity) |
| | Removes a value from the possibilities of all others in the same box. More...
|
| |
| int | valid_in_row (int value, int row) |
| | Checks if the value is valid (no duplicates) in the given row. More...
|
| |
| int | valid_in_col (int value, int col) |
| | Checks if the value is valid (no duplicates) in the given column. More...
|
| |
| int | valid_in_box (int value, int row, int col) |
| | Checks if the value is valid (no duplicates) in the given box. More...
|
| |
| int | brute_force_rec (int curRow, int curCol, int verbosity) |
| | Attempts to solve using a brute force mechanism. More...
|
| |
| void | brute_force (int verbosity) |
| | Wrapper function to handle result of recursive brute force appropriately. More...
|
| |
| int | max (int a, int b) |
| | Returns the maximum of two integers. More...
|
| |
| int | focus_house (int houseBM[SUB_SIZE]) |
| | Returns overlapping house where possible locations of a value lie in. More...
|
| |
| int | intersection_removal (int verbosity) |
| | Find value in only overlapping house and remove from rest of other houses. More...
|
| |
| int | remove_naked_group (int *rows, int *cols, int *shared, int size, int mode, int verbosity) |
| | Removes values according to the contents of a known naked group. More...
|
| |
| int | remove_hidden_group (int *rows, int *cols, int *shared, int size, int mode, int verbosity) |
| | Removes values according to the contents of a known hidden group. More...
|
| |
| int | eval_naked_group (int *candidates, int size, int pos, int mode, int verbosity) |
| | Evaluates a naked group by checking validity and removing redundancy. More...
|
| |
| int | eval_hidden_group (int *candidates, int size, int pos, int mode, int verbosity) |
| | Evaluates a hidden group by checking validity and removing redundancy. More...
|
| |
| int | candid_group (int considered[VALUES], int curConsidered, int candidCount, int *candidates, int curCandid, int targetSize, int curSize, int pos, int mode, int verbosity, int isHidden) |
| | Recursive function to create groups of candidate numbers of the given size. More...
|
| |
| int | find_group (int considered[VALUES], int candidCount, int size, int pos, int mode, int verbosity, int isHidden) |
| | Wrapper function for forming naked groups and evaluating them. More...
|
| |
| int | naked_groups (int size, int verbosity) |
| | Top-level function to find and remove naked groups. More...
|
| |
| int | hidden_groups (int size, int verbosity) |
| | Top-level function to find and remove hidden groups. More...
|
| |
| int | eliminate_redundant (int verbosity) |
| | Elminates redundant possibilities using the techniques the solver knows. More...
|
| |
| int | process_next (int *cellsLeft, int verbosity, int forceFlag) |
| | Process the next iteration of the loop. More...
|
| |
| void | write_to_file (FILE *output) |
| | Writes the contents of the grid to a file in csv format. More...
|
| |
| int | export_grid (char *outCsv) |
| | Exports the solved grid as a csv file. More...
|
| |
| int | read_bulk (const char *fileName, int forceFlag) |
| | Reads, solves and checks all sudokus in a bulk sudoku file. More...
|
| |
| int | read_file (char *inCsv, char *missing, int isBulk, int forceFlag) |
| | Adapter function to handle the reading of a file depending on its structure. More...
|
| |
| int | main (int argc, char *argv[]) |
| | Called initially and encompasses the program's functionality. More...
|
| |
|
|
char *** | grid |
| | A string 2-D array storing known or determined values.
|
| |
|
int *** | possible |
| | Stores all possible values for each cell in the grid.
|
| |
|
int ** | possibleCount |
| | Stores the number of possibilities for each cell.
|
| |
|
char ** | valid |
| | Stores the valid tokens that can be used in the sudoku grid.
|
| |
|
int | VALUES |
| | The number of values that the sudoku can hold.
|
| |
|
int | SUB_SIZE |
| | The root of the values; i.e. the length of the boxes.
|
| |
|
char * | MODE_LABELS [] = {"rows", "cols", "boxes"} |
| |
Holds all the logic for the sudoku solver.
◆ addToValid()
| int addToValid |
( |
int * |
tokenCount, |
|
|
char * |
token |
|
) |
| |
Add the token to the valid array if not full.
- Parameters
-
| [in,out] | tokenCount | The number of tokens currently parsed |
| [in] | token | A candidate token for the array of valid tokens |
| [out] | status | 0: Success, 1: Invalid sudoku |
229 for (
int i = 0; i < *tokenCount; i++) {
230 if (strcmp(
valid[i], token) == 0) {
235 if (*tokenCount >=
VALUES + 1) {
236 fprintf(stderr,
"Too many different valid tokens in grid\n");
239 valid[*tokenCount] = strdup(token);
◆ brute_force()
| void brute_force |
( |
int |
verbosity | ) |
|
Wrapper function to handle result of recursive brute force appropriately.
- Parameters
-
| [in] | verbosity | The verbosity of the output (print or hide) |
897 printf(PROCESS
"Attempting brute force...\n");
900 printf(
"Brute Force failed.\n");
◆ brute_force_rec()
| int brute_force_rec |
( |
int |
curRow, |
|
|
int |
curCol, |
|
|
int |
verbosity |
|
) |
| |
Attempts to solve using a brute force mechanism.
- Parameters
-
| [in] | curRow,curCol | The current position to be forced in |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | status | 0: Success, 1: Invalid state |
847 if (verbosity == 2) {
848 printf(FOUND
"Brute Force(%i, %i)\n", curRow, curCol);
851 for (
int row = curRow; row <
VALUES; row++) {
852 for (
int col = 0; col <
VALUES; col++) {
872 if (verbosity == 2) {
873 printf(ADD
"Forced: %i, %i, %i\n", row, col, value);
878 (col + 1) %
VALUES, verbosity) == 0) {
883 else if (verbosity == 2) {
884 printf(
"\x1B[36m' \x1B[0mSkipped: %i, %i\n", row, col);
◆ candid_group()
| int candid_group |
( |
int |
considered[VALUES], |
|
|
int |
curConsidered, |
|
|
int |
candidCount, |
|
|
int * |
candidates, |
|
|
int |
curCandid, |
|
|
int |
targetSize, |
|
|
int |
curSize, |
|
|
int |
pos, |
|
|
int |
mode, |
|
|
int |
verbosity, |
|
|
int |
isHidden |
|
) |
| |
Recursive function to create groups of candidate numbers of the given size.
These are used for both naked and hidden and evaluated when formed. Optimized to exit early if not enough candidates left for forming a group.
- Parameters
-
| [in] | considered | A bitmap of candidate cells in a house |
| [in] | curConsidered | The current index within considered |
| [in] | candidCount | The number of candidates in considered |
| [in,out] | candidates | The candidates currently in the group |
| [in] | curCandid | The position of the candidate in order |
| [in] | targetSize | The desired size of the candidate group |
| [in] | curSize | The current size of the candidate group |
| [in] | pos | Specifies the position of the house |
| [in] | mode | Mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [in] | isHidden | Whether the group is hidden or naked |
| [out] | removed | (Bool) 0: False, 1: True |
1482 if (curSize == targetSize) {
1483 if (isHidden == 1) {
1490 if (candidCount - curCandid < targetSize - curSize) {
1496 int nextCandid = curCandid;
1498 nextConsidered = -1;
1499 for (
int i = curConsidered + 1; i <
VALUES; i++) {
1500 if (considered[i] == 1) {
1507 if (nextConsidered != -1) {
1508 candidates[curSize] = nextConsidered;
1510 candidates, nextCandid, targetSize, curSize + 1, pos, mode, verbosity,
1513 curConsidered = nextConsidered;
1515 }
while (nextConsidered != -1);
◆ eliminate_redundant()
| int eliminate_redundant |
( |
int |
verbosity | ) |
|
Elminates redundant possibilities using the techniques the solver knows.
Adopts an incremental strategy to use more advanced techniques only if no progress is made by the previous strategies, for greedy addition.
- Parameters
-
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1715 if (verbosity > 0) {
1716 printf(PROCESS
"Removing redundant values...\n");
1718 while (output == 0 && step < 3) {
1721 for (
int size = 2; size <= 4; size++) {
1727 for (
int size = 2; size <= 4; size++) {
◆ eval_hidden_group()
| int eval_hidden_group |
( |
int * |
candidates, |
|
|
int |
size, |
|
|
int |
pos, |
|
|
int |
mode, |
|
|
int |
verbosity |
|
) |
| |
Evaluates a hidden group by checking validity and removing redundancy.
- Parameters
-
| [in] | candidates | The positions of the cells within the house |
| [in] | size | The number of cells in the group |
| [in] | pos | Specifies the house, with mode specifying its type |
| [in] | mode | The mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1372 memset(preShared, 0,
sizeof(preShared));
1375 for (
int i = 0; i < size; i++) {
1376 for (
int col = 0; col <
VALUES; col++) {
1377 if (
possible[pos][col][candidates[i]] == 1) {
1378 preShared[col] += 1;
1385 for (
int i = 0; i < size; i++) {
1386 for (
int row = 0; row <
VALUES; row++) {
1387 if (
possible[row][pos][candidates[i]] == 1) {
1388 preShared[row] += 1;
1397 for (
int i = 0; i < size; i++) {
1398 for (
int inPos = 0; inPos <
VALUES; inPos++) {
1399 int curRow = subRow + (inPos /
SUB_SIZE);
1400 int curCol = subCol + (inPos %
SUB_SIZE);
1401 if (
possible[curRow][curCol][candidates[i]] == 1) {
1402 preShared[inPos] += 1;
1411 memset(shared, 0,
sizeof(shared));
1412 int sharedCounter = 0;
1413 for (
int position = 0; position <
VALUES; position++) {
1414 if (preShared[position] > 0) {
1415 if (sharedCounter == size) {
1418 shared[sharedCounter] = position;
1423 if (sharedCounter < size) {
1429 memset(rows, 0,
sizeof(rows));
1430 memset(cols, 0,
sizeof(cols));
1434 for (
int i = 0; i < size; i++) {
1436 cols[i] = shared[i];
1441 for (
int i = 0; i < size; i++) {
1442 rows[i] = shared[i];
1450 for (
int i = 0; i < size; i++) {
1451 rows[i] = subRow + (shared[i] /
SUB_SIZE);
1452 cols[i] = subCol + (shared[i] %
SUB_SIZE);
◆ eval_naked_group()
| int eval_naked_group |
( |
int * |
candidates, |
|
|
int |
size, |
|
|
int |
pos, |
|
|
int |
mode, |
|
|
int |
verbosity |
|
) |
| |
Evaluates a naked group by checking validity and removing redundancy.
- Parameters
-
| [in] | candidates | The positions of the cells within the house |
| [in] | size | The number of cells in the group |
| [in] | pos | Specifies the house, with mode specifying its type |
| [in] | mode | The mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1225 memset(preShared, 0,
sizeof(preShared));
1228 for (
int i = 0; i < size; i++) {
1229 for (
int value = 0; value <
VALUES; value++) {
1230 if (
possible[pos][candidates[i]][value] == 1) {
1231 preShared[value] += 1;
1238 for (
int i = 0; i < size; i++) {
1239 for (
int value = 0; value <
VALUES; value++) {
1240 if (
possible[candidates[i]][pos][value] == 1) {
1241 preShared[value] += 1;
1250 for (
int i = 0; i < size; i++) {
1251 int curRow = subRow + (candidates[i] /
SUB_SIZE);
1252 int curCol = subCol + (candidates[i] %
SUB_SIZE);
1253 for (
int value = 0; value <
VALUES; value++) {
1254 if (
possible[curRow][curCol][value] == 1) {
1255 preShared[value] += 1;
1264 memset(shared, 0,
sizeof(shared));
1265 int sharedCounter = 0;
1266 for (
int value = 0; value <
VALUES; value++) {
1267 if (preShared[value] > 0) {
1268 if (sharedCounter == size) {
1271 shared[sharedCounter] = value;
1279 memset(rows, 0,
sizeof(rows));
1280 memset(cols, 0,
sizeof(cols));
1284 for (
int i = 0; i < size; i++) {
1286 cols[i] = candidates[i];
1291 for (
int i = 0; i < size; i++) {
1292 rows[i] = candidates[i];
1300 for (
int i = 0; i < size; i++) {
1301 rows[i] = subRow + (candidates[i] /
SUB_SIZE);
1302 cols[i] = subCol + (candidates[i] %
SUB_SIZE);
1308 output =
max(output,
1312 int sharedValue = -1;
1313 int sharesGroup = 1;
1315 for (
int i = 0; i < size; i++) {
1316 if (sharedValue == -1) {
1317 sharedValue = candidates[i] /
SUB_SIZE;
1318 }
else if (sharedValue != candidates[i] /
SUB_SIZE) {
1323 if (sharesGroup == 1) {
1324 output =
max(output,
1328 for (
int i = 0; i < size; i++) {
1329 if (sharedValue == -1) {
1330 sharedValue = rows[i];
1331 }
else if (sharedValue != rows[i]) {
1336 if (sharesGroup == 1) {
1337 output =
max(output,
1343 for (
int i = 0; i < size; i++) {
1344 if (sharedValue == -1) {
1345 sharedValue = cols[i];
1346 }
else if (sharedValue != cols[i]) {
1351 if (sharesGroup == 1) {
1352 output =
max(output,
◆ export_grid()
| int export_grid |
( |
char * |
outCsv | ) |
|
Exports the solved grid as a csv file.
- Parameters
-
| [in] | outCsv | The path (and name) of the file to output to |
| [out] | status | 0: Success, 1: Failure |
1846 char* outCsvFull = calloc(strlen(outCsv) + 4,
sizeof(
char));
1847 strcpy(outCsvFull, outCsv);
1848 if (strstr(outCsvFull,
".csv") !=
1849 &outCsvFull[strlen(outCsvFull) - 4]) {
1850 strcat(outCsvFull,
".csv");
1854 FILE* output = fopen(outCsvFull,
"w+");
1856 if (output == NULL) {
1857 fprintf(stderr,
"Output file could not be created\n");
◆ find_group()
| int find_group |
( |
int |
considered[VALUES], |
|
|
int |
candidCount, |
|
|
int |
size, |
|
|
int |
pos, |
|
|
int |
mode, |
|
|
int |
verbosity, |
|
|
int |
isHidden |
|
) |
| |
Wrapper function for forming naked groups and evaluating them.
- Parameters
-
| [in] | considered | A bitmap of candidate cells in a house |
| [in] | candidCount | The number of candidates in considered |
| [in] | size | The desired size of the candidate group |
| [in] | pos | Specifies the position of the house |
| [in] | mode | Mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [in] | isHidden | Whether the group is hidden or naked |
| [out] | removed | (Bool) 0: False, 1: True |
1533 int candidates[size];
1534 memset(candidates, 0,
sizeof(candidates));
1535 return candid_group(considered, -1, candidCount, candidates, -1, size, 0,
1536 pos, mode, verbosity, isHidden);
◆ find_single()
Gets the next pair of row and column where there is only one possibility.
- Parameters
-
| [out] | pair | The position of the single cell or NULL |
541 for (
int row = 0; row <
VALUES; row++) {
542 for (
int col = 0; col <
VALUES; col++) {
◆ focus_house()
| int focus_house |
( |
int |
houseBM[SUB_SIZE] | ) |
|
Returns overlapping house where possible locations of a value lie in.
- Parameters
-
| [in] | houseBM | A bitmap for the house to consult |
| [out] | focus | The relative position of the overlapping house or -1 |
927 for (
int i = 0; i <
SUB_SIZE; i++) {
928 if (houseBM[i] == 1) {
◆ get_boxes_bitmap()
| void get_boxes_bitmap |
( |
int |
array[SUB_SIZE][SUB_SIZE][VALUES] | ) |
|
Stores all columns as a bitmap of numbers.
- Parameters
-
| [in,out] | array | The bitmap of numbers to store the output into |
361 for (
int col = 0; col <
SUB_SIZE; col++) {
362 for (
int row = 0; row <
SUB_SIZE; row++) {
363 for (
int subCol = 0; subCol <
SUB_SIZE; subCol++) {
364 for (
int subRow = 0; subRow <
SUB_SIZE; subRow++) {
365 int curRow = row *
SUB_SIZE + subRow;
366 int curCol = col *
SUB_SIZE + subCol;
367 if (strcmp(
grid[curRow][curCol],
"-") == 0) {
370 for (
int val = 0; val <
VALUES; val++) {
371 if (strcmp(
grid[curRow][curCol],
valid[val + 1]) == 0) {
372 array[row][col][val] = 1;
◆ get_columns_bitmap()
| void get_columns_bitmap |
( |
int |
array[VALUES][VALUES] | ) |
|
Stores all columns as a bitmap of numbers.
- Parameters
-
| [in,out] | array | The bitmap of numbers to store the output into |
342 for (
int col = 0; col <
VALUES; col++) {
343 for (
int row = 0; row <
VALUES; row++) {
344 if (strcmp(
grid[row][col],
"-") == 0) {
347 for (
int val = 0; val <
VALUES; val++) {
348 if (strcmp(
grid[row][col],
valid[val + 1]) == 0) {
◆ get_possible_value()
| int get_possible_value |
( |
int * |
pair | ) |
|
Assumes there is only one value in the bitmap and retrieves it.
- Parameters
-
| [in] | pair | The position of the cell to consider |
| [out] | value | The (0-indexed) value at the cell or -1 if multiple |
557 for (
int i = 0; i <
VALUES; i++) {
558 if (
possible[pair[0]][pair[1]][i] == 1) {
◆ get_row_bitmap()
| void get_row_bitmap |
( |
int |
row, |
|
|
int |
array[VALUES] |
|
) |
| |
Stores the current row as a bitmap of numbers.
- Parameters
-
| [in] | row | The row number to use as input for conversion |
| [in,out] | array | The bitmap of numbers to store the output into |
387 for (
int col = 0; col <
VALUES; col++) {
388 if (strcmp(
grid[row][col],
"-") == 0) {
391 for (
int val = 0; val <
VALUES; val++) {
392 if (strcmp(
grid[row][col],
valid[val + 1]) == 0) {
◆ hidden_groups()
| int hidden_groups |
( |
int |
size, |
|
|
int |
verbosity |
|
) |
| |
Top-level function to find and remove hidden groups.
Loop through all houses and find 2 cells with pair that only appear there, and remove all the other values from those cells
- Parameters
-
| [in] | size | The size of the naked groups to consider |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1623 if (verbosity > 0) {
1624 printf(PROCESS
"Finding hidden groups of size %i...\n", size);
1628 int valueFrequency = 0;
1629 int consideredCount = 0;
1633 for (
int row = 0; row <
VALUES; row++) {
1634 consideredCount = 0;
1635 memset(considered, 0,
sizeof(considered));
1636 for (
int value = 0; value <
VALUES; value++) {
1638 for (
int col = 0; col <
VALUES; col++) {
1639 if (
possible[row][col][value] == 1) {
1643 if (valueFrequency >= 2 && valueFrequency <= size) {
1644 considered[value] = 1;
1645 consideredCount += 1;
1649 if (valueFrequency >= size) {
1650 output =
max(output,
1651 find_group(considered, valueFrequency, size, row, 0, verbosity, 1));
1655 for (
int col = 0; col <
VALUES; col++) {
1656 consideredCount = 0;
1657 memset(considered, 0,
sizeof(considered));
1658 for (
int value = 0; value <
VALUES; value++) {
1660 for (
int row = 0; row <
VALUES; row++) {
1661 if (
possible[row][col][value] == 1) {
1665 if (valueFrequency >= 2 && valueFrequency <= size) {
1666 considered[value] = 1;
1667 consideredCount += 1;
1671 if (valueFrequency >= size) {
1672 output =
max(output,
1673 find_group(considered, valueFrequency, size, col, 1, verbosity, 1));
1677 for (
int subRow = 0; subRow <
SUB_SIZE; subRow++) {
1678 for (
int subCol = 0; subCol <
SUB_SIZE; subCol++) {
1679 consideredCount = 0;
1680 memset(considered, 0,
sizeof(considered));
1681 for (
int value = 0; value <
VALUES; value++) {
1683 for (
int pos = 0; pos <
VALUES; pos++) {
1686 if (
possible[curRow][curCol][value] == 1) {
1690 if (valueFrequency >= 2 && valueFrequency <= size) {
1691 considered[value] = 1;
1692 consideredCount += 1;
1696 if (valueFrequency >= size) {
1698 (subRow *
SUB_SIZE) + subCol, 2, verbosity, 1), output);
◆ initialize_globals()
| int initialize_globals |
( |
char |
buffer[ROW_BUF_SIZE], |
|
|
int |
isBulk |
|
) |
| |
Allocates and initializes the global variables.
- Parameters
-
| [in] | buffer | A buffer containing the file contents to be parsed from |
| [in] | isBulk | Whether the file has a bulk format |
| [out] | status | 0: Success, 1: Invalid sudoku |
158 for (
int i = 0; buffer[i]; i++) {
159 values += (buffer[i] ==
',');
162 float root = sqrt((
float)
VALUES);
163 if (floor(root) != root) {
164 fprintf(stderr,
"File doesn't have square number of values\n");
172 for (
int i = 0; i <
VALUES; i++) {
177 for (
int i = 0; i <
VALUES; i++) {
179 for (
int j = 0; j <
VALUES; j++) {
185 for (
int i = 0; i <
VALUES; i++) {
190 valid[0] = strdup(
"-");
◆ intersection_removal()
| int intersection_removal |
( |
int |
verbosity | ) |
|
Find value in only overlapping house and remove from rest of other houses.
Aggregation of pointing groups and box line reduction techniques.
- Parameters
-
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
947 printf(PROCESS
"Using pointing groups...\n");
952 for (
int subRow = 0; subRow <
SUB_SIZE; subRow++) {
953 for (
int subCol = 0; subCol <
SUB_SIZE; subCol++) {
954 for (
int value = 1; value <=
VALUES; value++) {
955 memset(rowBM, 0,
sizeof(rowBM));
956 memset(colBM, 0,
sizeof(colBM));
957 for (
int pos = 0; pos <
VALUES; pos++) {
960 if (
possible[curRow][curCol][value] == 1) {
968 int curRow = subRow *
SUB_SIZE + focus;
969 for (
int i = 0; i <
VALUES; i++) {
977 printf(FOUND
"Using pointing groups on %s to remove from"
978 " the box's %ith row:\n",
valid[value + 1], focus);
981 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
982 valid[value + 1], curRow, i);
990 int curCol = subCol *
SUB_SIZE + focus;
991 for (
int i = 0; i <
VALUES; i++) {
999 printf(FOUND
"Using pointing groups on %s to remove from"
1000 " the box's %ith column:\n",
valid[value + 1], focus);
1003 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
1004 valid[value + 1], i, curCol);
1012 if (verbosity > 0) {
1013 printf(PROCESS
"Using box line reduction...\n");
1017 for (
int row = 0; row <
VALUES; row++) {
1018 for (
int value = 0; value <
VALUES; value++) {
1019 memset(houseBM, 0,
sizeof(houseBM));
1020 for (
int col = 0; col <
VALUES; col++) {
1021 if (
possible[row][col][value] == 1) {
1030 for (
int pos = 0; pos <
VALUES; pos++) {
1032 int curRow = subRow + pos /
SUB_SIZE;
1033 int curCol = subCol + pos %
SUB_SIZE;
1034 if (curRow != row &&
possible[curRow][curCol][value] == 1) {
1036 possible[curRow][curCol][value] = 0;
1038 if (verbosity > 0) {
1040 printf(FOUND
"Using box line reduction to remove %s from the"
1041 " box except its %ith row:\n",
valid[value + 1], focus);
1044 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
1045 valid[value + 1], curRow, curCol);
1053 for (
int col = 0; col <
VALUES; col++) {
1054 for (
int value = 0; value <
VALUES; value++) {
1055 memset(houseBM, 0,
sizeof(houseBM));
1056 for (
int row = 0; row <
VALUES; row++) {
1057 if (
possible[row][col][value] == 1) {
1066 for (
int pos = 0; pos <
VALUES; pos++) {
1068 int curRow = subRow + pos /
SUB_SIZE;
1069 int curCol = subCol + pos %
SUB_SIZE;
1070 if (curCol != col &&
possible[curRow][curCol][value] == 1) {
1072 possible[curRow][curCol][value] = 0;
1074 if (verbosity > 0) {
1076 printf(FOUND
"Using box line reduction to remove %s from the"
1077 " box except its %ith column:\n",
valid[value + 1], focus);
1080 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
1081 valid[value + 1], curRow, curCol);
◆ main()
| int main |
( |
int |
argc, |
|
|
char * |
argv[] |
|
) |
| |
Called initially and encompasses the program's functionality.
- Parameters
-
| [in] | argc | The number of command line arguments |
| [in] | argv | The command line arguments |
2003 char* outCsv = NULL;
2004 char* missing = NULL;
2011 &forceFlag, &debugFlag, &inCsv, &outCsv, &missing) != 0) {
2012 fprintf(stderr,
"\nUsage: ./sudoku.out [[-v]|[-vv]] [-b] [-t] [[-f]|[-nf]]"
2013 " [-d] [-o <new_csv_name>] [-m <missing_arg>] <csv_path>\n"
2015 " -v verbose output, lists steps in solving\n"
2016 " -vv extra verbose output, lists brute force steps\n"
2017 " -b solves a batch execution of sudokus (one per line)\n"
2018 " -t shows the benchmarked time for reading and execution\n"
2019 " -f uses brute force for solving immediately\n"
2020 " -nf disables use of brute force\n"
2021 " -d debug mode, shows all possibilities for each cell\n"
2022 " -o exports solved grid to a new csv\n"
2023 " -m provide missing argument if not in the grid\n");
2028 if (timeFlag == 1) {
2033 switch (
read_file(inCsv, missing, bulkFlag, forceFlag)) {
2037 fprintf(stderr,
"Error reading file\n");
2042 if (bulkFlag == 1) {
2043 printf(
"Bulk file processed\n");
2044 if (timeFlag == 1) {
2045 time = clock() - time;
2046 printf(
"Time elasped: %f\n", ((
double) time) / CLOCKS_PER_SEC);
2056 if (forceFlag == 1) {
2061 while (
process_next(&cellsLeft, verbosity, forceFlag) != 1) {}
2065 printf(
"\nOutput:");
2067 if (debugFlag == 1) {
2070 if (outCsv != NULL) {
2079 if (timeFlag == 1) {
2080 time = clock() - time;
2081 printf(
"Time elasped: %f\n", ((
double) time) / CLOCKS_PER_SEC);
◆ make_pair()
| int* make_pair |
( |
int |
row, |
|
|
int |
col |
|
) |
| |
Dynamically allocated and initializes a pair of values.
- Parameters
-
| [in] | row,col | The values to fill the pair with |
| [out] | pair | An int array of length two storing row and col |
530 int* pair = calloc(2,
sizeof(
int));
◆ max()
Returns the maximum of two integers.
- Parameters
-
| [in] | a,b | The two integers to compare |
| [out] | max | The bigger number from a and b |
◆ naked_groups()
| int naked_groups |
( |
int |
size, |
|
|
int |
verbosity |
|
) |
| |
Top-level function to find and remove naked groups.
Loop through all houses and find cells containing same group of values, and remove from these values from all other linked houses
- Parameters
-
| [in] | size | The size of the naked groups to consider |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1549 if (verbosity > 0) {
1550 printf(PROCESS
"Finding naked groups of size %i...\n", size);
1558 for (
int row = 0; row <
VALUES; row++) {
1560 memset(considered, 0,
sizeof(considered));
1561 for (
int col = 0; col <
VALUES; col++) {
1564 considered[col] = 1;
1568 if (count >= size) {
1569 output =
max(output,
1570 find_group(considered, count, size, row, 0, verbosity, 0));
1574 for (
int col = 0; col <
VALUES; col++) {
1576 memset(considered, 0,
sizeof(considered));
1577 for (
int row = 0; row <
VALUES; row++) {
1580 considered[row] = 1;
1584 if (count >= size) {
1585 output =
max(output,
1586 find_group(considered, count, size, col, 1, verbosity, 0));
1590 for (
int subRow = 0; subRow <
SUB_SIZE; subRow++) {
1591 for (
int subCol = 0; subCol <
SUB_SIZE; subCol++) {
1593 memset(considered, 0,
sizeof(considered));
1594 for (
int pos = 0; pos <
VALUES; pos++) {
1598 if (possibilities >= 2 && possibilities <= size) {
1600 considered[pos] = 1;
1604 if (count >= size) {
1606 (subRow *
SUB_SIZE) + subCol, 2, verbosity, 0), output);
◆ pre_process()
| void pre_process |
( |
int * |
cellsLeft | ) |
|
Initializes a bitmap to hold possible values.
- Parameters
-
| [in,out] | cellsLeft | The number of cells left to solve the sudoku |
405 memset(allCols, 0,
sizeof(allCols));
409 memset(boxes, 0,
sizeof(boxes));
413 for (
int row = 0; row <
VALUES; row++) {
414 memset(curRow, 0,
sizeof(curRow));
418 for (
int col = 0; col <
VALUES; col++) {
419 for (
int val = 0; val <
VALUES; val++) {
421 if (strcmp(
grid[row][col],
"-") == 0
422 && curRow[val] == 0 && allCols[col][val] == 0
◆ print_array()
| void print_array |
( |
int * |
array, |
|
|
int |
len, |
|
|
int |
isPadded |
|
) |
| |
Prints a grid cell's possible contents.
- Parameters
-
| [in] | array | The array to be printed out |
| [in] | len | The length of the array |
| [in] | isPadded | Whether the output should be padded |
447 for (
int i = 0; i < len; i++) {
450 printf(
"%s",
valid[i + 1]);
453 printf(
" %s",
valid[i + 1]);
462 for (; count < PAD_SIZE; count++) {
◆ print_line()
| void print_line |
( |
char |
type, |
|
|
int |
length |
|
) |
| |
Prints a line of given length with a given character.
- Parameters
-
| [in] | type | The character to use to print the line |
| [in] | length | The length of the line to be printed |
493 for (
int i = 0; i < length; i++) {
◆ process_arguments()
| int process_arguments |
( |
int |
argc, |
|
|
char * |
argv[], |
|
|
int * |
verbosity, |
|
|
int * |
bulkFlag, |
|
|
int * |
timeFlag, |
|
|
int * |
forceFlag, |
|
|
int * |
debugFlag, |
|
|
char ** |
inCsv, |
|
|
char ** |
outCsv, |
|
|
char ** |
missing |
|
) |
| |
Processes the command line arguments provided.
- Parameters
-
| [in] | argc | The number of command line arguments |
| [in] | argv | The command line arguments |
| [in,out] | verbosity | How verbose the output has been set to |
| [in,out] | bulkFlag | Whether we are evaluating a bulk file |
| [in,out] | timeFlag | Whether we are benchmarking the time taken |
| [in,out] | forceFlag | How much brute force we can apply |
| [in,out] | debugFlag | Whether to print the possibilities at the end |
| [in,out] | inCsv | The input CSV file to read from |
| [in,out] | outCsv | The output CSV file to write to (if at all) |
| [in,out] | missing | The missing token to use (if required) |
| [out] | status | 0: Success, 1: Invalid arguments |
48 fprintf(stderr,
"Not enough arguments\n");
53 for (
int i = 1; i < argc; i++) {
54 if (strcmp(
"-v", argv[i]) == 0) {
57 }
else if (*verbosity == 1) {
58 fprintf(stderr,
"Duplicate -v flag found\n");
61 }
else if (strcmp(
"-vv", argv[i]) == 0) {
65 fprintf(stderr,
"Duplicate -vv flag found\n");
68 }
else if (strcmp(
"-t", argv[i]) == 0) {
72 fprintf(stderr,
"Duplicate -t flag found\n");
75 }
else if (strcmp(
"-b", argv[i]) == 0) {
79 fprintf(stderr,
"Duplicate -b flag found\n");
82 }
else if (strcmp(
"-d", argv[i]) == 0) {
83 if (*debugFlag == 0) {
86 fprintf(stderr,
"Duplicate -d flag found\n");
89 }
else if (strcmp(
"-o", argv[i]) == 0) {
90 if (*outCsv == NULL) {
91 if (++i != argc && argv[i][0] !=
'-') {
94 fprintf(stderr,
"Output file path for -o not specified\n");
98 fprintf(stderr,
"Duplicate -o flag found\n");
101 }
else if (strcmp(
"-m", argv[i]) == 0) {
102 if (*missing == NULL) {
103 if (++i != argc && argv[i][0] !=
'-') {
106 fprintf(stderr,
"Missing argument for -m not specified\n");
110 fprintf(stderr,
"Duplicate -m flag found\n");
113 }
else if (strcmp(
"-f", argv[i]) == 0) {
114 if (*forceFlag == 0) {
117 if (*forceFlag == 1) {
118 fprintf(stderr,
"Duplicate -f flag found\n");
120 fprintf(stderr,
"Conflicting -f flag found\n");
124 }
else if (strcmp(
"-nf", argv[i]) == 0) {
125 if (*forceFlag == 0) {
128 if (*forceFlag == -1) {
129 fprintf(stderr,
"Duplicate -nf flag found\n");
131 fprintf(stderr,
"Conflicting -nf flag found\n");
140 fprintf(stderr,
"Unexpected argument found\n");
◆ process_next()
| int process_next |
( |
int * |
cellsLeft, |
|
|
int |
verbosity, |
|
|
int |
forceFlag |
|
) |
| |
Process the next iteration of the loop.
- Parameters
-
| [in,out] | cellsLeft | The number of cells left to solve the sudoku |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [in] | forceFlag | How much brute force we can apply |
| [out] | status | 0: Success, 1: Failure (Stalemate) |
1753 if (*cellsLeft == 0) {
1759 for (
int mode = 0; mode < 3; mode++) {
1769 if (verbosity > 0 && forceFlag == -1) {
1770 fprintf(stderr,
"Didn't find next pair. Cells left: %i\n",
1773 if (forceFlag != -1) {
1783 if (verbosity > 0 && value != -1) {
1784 printf(ADD
"Added %s at (%i, %i) as single possibility\n",
1785 valid[value + 1], pair[0], pair[1]);
1789 fprintf(stderr,
"Empty cell processed\n");
1793 grid[pair[0]][pair[1]] =
valid[value + 1];
1795 for (
int val = 0; val <
VALUES; val++) {
1796 possible[pair[0]][pair[1]][val] = 0;
1802 memset(mask, 0,
sizeof(mask));
◆ process_token()
| int process_token |
( |
int * |
tokenCount, |
|
|
char * |
token, |
|
|
int |
row, |
|
|
int |
col |
|
) |
| |
Sanitize, and set the grid to reference a valid token.
- Parameters
-
| [in,out] | tokenCount | The number of tokens currently parsed |
| [in] | token | A candidate token for the array of valid tokens |
| [in] | row,col | The position of the token |
| [out] | status | 0: Success, 1: Invalid sudoku |
253 if (strchr(token,
'\n') != NULL) {
254 printf(
"\\n converted at (%i, %i)\n", row, col);
255 *strchr(token,
'\n') =
'\0';
257 if (strchr(token,
'\r') != NULL) {
258 *strchr(token,
'\r') =
'\0';
265 for (
int i = 0; i < *tokenCount; i++) {
266 if (strcmp(
valid[i], token) == 0) {
◆ read_bulk()
| int read_bulk |
( |
const char * |
fileName, |
|
|
int |
forceFlag |
|
) |
| |
Reads, solves and checks all sudokus in a bulk sudoku file.
This is dependant on single character value tokens as opposed to strings.
- Parameters
-
| [in] | fileName | The path of the file to read from |
| [out] | status | -1: Invalid pre-global, 0: Success, 1: Failure |
1873 FILE* input = fopen(fileName,
"r");
1874 if (input == NULL) {
1875 fprintf(stderr,
"Bulk CSV file could not be opened for reading\n");
1878 int solvedCount = 0;
1879 char buffer[ROW_BUF_SIZE];
1880 char* current = buffer;
1881 fgets(buffer, ROW_BUF_SIZE, input);
1882 while (fgets(buffer, ROW_BUF_SIZE, input)) {
1885 int len = strcspn(current,
",");
1887 VALUES = (int) sqrt(len);
1888 float root = sqrt((
float)
VALUES);
1889 if (floor(root) != root) {
1890 fprintf(stderr,
"File doesn't have square number of values\n");
1901 for (
int curChar = 0; curChar < len; curChar++) {
1903 char inChar = current[curChar];
1904 if (inChar ==
'0') {
1907 char token[] = {inChar,
'\0'};
1916 if (tokenCount ==
VALUES) {
1918 }
else if (tokenCount <
VALUES) {
1919 fprintf(stderr,
"Not enough values provided, expected: %i\n",
VALUES);
1924 if (forceFlag == 1) {
1933 current = &buffer[len + 1];
1934 int diff = strcspn(current,
",") - len;
1936 fprintf(stderr,
"Solution smaller than the question\n");
1944 for (
int curChar = 0; curChar < len - diff; curChar++) {
1945 char inChar = current[curChar];
1946 if (inChar ==
'0') {
1962 fprintf(stderr,
"Sudoku solution does not match expected answer\n");
1970 printf(
"Solved %i\n", solvedCount);
◆ read_csv()
| int read_csv |
( |
const char * |
fileName, |
|
|
char * |
missing |
|
) |
| |
Reads from a csv file and loads into the grid.
- Parameters
-
| [in] | fileName | The path to the file to use as input and read from |
| [in] | missing | The missing token to use (if required) |
| [out] | status | -1: Invalid pre-global, 0: Success, 1: Invalid |
280 FILE* input = fopen(fileName,
"r");
282 fprintf(stderr,
"CSV file could not be opened for reading\n");
285 char buffer[ROW_BUF_SIZE];
294 buffer[strcspn(buffer,
"\n")] = 0;
295 char* token = strtok(buffer,
",");
297 while (token != NULL && col <
VALUES) {
302 token = strtok(NULL,
",");
306 fprintf(stderr,
"Too few columns in row %i: Expected %i, not %i\n",
312 memset(buffer, 0,
sizeof(buffer));
313 }
while (fgets(buffer, ROW_BUF_SIZE, input) && row <
VALUES);
316 fprintf(stderr,
"Too few rows in grid: Expected %i, not %i\n",
VALUES, row);
320 if (tokenCount ==
VALUES) {
321 if (missing != NULL) {
324 fprintf(stderr,
"Missing one values so X substituted\n");
327 }
else if (tokenCount <
VALUES) {
328 fprintf(stderr,
"Not enough values provided, expected: %i\n",
VALUES);
◆ read_file()
| int read_file |
( |
char * |
inCsv, |
|
|
char * |
missing, |
|
|
int |
isBulk, |
|
|
int |
forceFlag |
|
) |
| |
Adapter function to handle the reading of a file depending on its structure.
- Parameters
-
| [in] | inCsv | The input CSV file to read from |
| [in] | missing | The missing token to use (if required) |
| [in] | bulkFlag | Whether we are evaluating a bulk file |
| [in] | forceFlag | How much brute force we can apply |
| [out] | status | -1: Invalid pre-global, 0: Success, 1: Failure |
◆ remove_hidden_group()
| int remove_hidden_group |
( |
int * |
rows, |
|
|
int * |
cols, |
|
|
int * |
shared, |
|
|
int |
size, |
|
|
int |
mode, |
|
|
int |
verbosity |
|
) |
| |
Removes values according to the contents of a known hidden group.
- Parameters
-
| [in] | rows,cols | The positions of the cells in the group |
| [in] | shared | The values shared by the group |
| [in] | size | The number of cells in the group |
| [in] | mode | The mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1171 if (verbosity > 0) {
1172 printf(FOUND
"Found hidden group (");
1173 for (
int i = 0; i < size - 1; i++) {
1174 printf(
"%s, ",
valid[shared[i] + 1]);
1176 printf(
"%s) using %s at ",
valid[shared[size - 1] + 1], MODE_LABELS[mode]);
1177 for (
int i = 0; i < size; i++) {
1178 printf(
"(%i, %i) ", rows[i], cols[i]);
1184 for (
int pos = 0; pos < size; pos++) {
1185 for (
int value = 0; value <
VALUES; value++) {
1188 for (
int i = 0; i < size; i++) {
1189 if (value == shared[i]) {
1198 if (
possible[rows[pos]][cols[pos]][value] == 1) {
1200 possible[rows[pos]][cols[pos]][value] = 0;
1202 if (verbosity > 0) {
1203 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
1204 valid[value + 1], rows[pos], cols[pos]);
◆ remove_naked_group()
| int remove_naked_group |
( |
int * |
rows, |
|
|
int * |
cols, |
|
|
int * |
shared, |
|
|
int |
size, |
|
|
int |
mode, |
|
|
int |
verbosity |
|
) |
| |
Removes values according to the contents of a known naked group.
- Parameters
-
| [in] | rows,cols | The positions of the cells in the group |
| [in] | shared | The values shared by the group |
| [in] | size | The number of cells in the group |
| [in] | mode | The mode of operation {0: row, 1: column, 2: box} |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
1103 if (verbosity > 0) {
1104 printf(FOUND
"Found naked group (");
1105 for (
int i = 0; i < size - 1; i++) {
1106 printf(
"%s, ",
valid[shared[i] + 1]);
1108 printf(
"%s) using %s at ",
valid[shared[size - 1] + 1], MODE_LABELS[mode]);
1109 for (
int i = 0; i < size; i++) {
1110 printf(
"(%i, %i) ", rows[i], cols[i]);
1116 memset(mask, 0,
sizeof(mask));
1120 for (
int i = 0; i < size; i++) {
1123 for (
int i = 0; i < size; i++) {
1124 output =
max(output,
1131 for (
int i = 0; i < size; i++) {
1134 for (
int i = 0; i < size; i++) {
1135 output =
max(output,
1142 for (
int i = 0; i < size; i++) {
1145 for (
int i = 0; i < size; i++) {
1146 output =
max(output,
1152 fprintf(stderr,
"Invalid mode for removing naked group.");
◆ remove_value_from_box()
| int remove_value_from_box |
( |
int |
row, |
|
|
int |
col, |
|
|
int |
value, |
|
|
int |
mask[VALUES], |
|
|
int |
verbosity |
|
) |
| |
Removes a value from the possibilities of all others in the same box.
- Parameters
-
| [in] | row,col | The position of a cell in the box to be removed from |
| [in] | value | The value to be removed |
| [in] | mask | A bitmap with positions to ignore in removal |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
770 for (
int i = 0; i <
VALUES; i++) {
773 if (mask[i] == 1 || (inCol + subCol == col && inRow + subRow == row)) {
776 if (
possible[subRow + inRow][subCol + inCol][value] == 1) {
778 possible[subRow + inRow][subCol + inCol][value] = 0;
781 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
782 valid[value + 1], subRow + inRow, subCol + inCol);
◆ remove_value_from_column()
| int remove_value_from_column |
( |
int |
col, |
|
|
int |
value, |
|
|
int |
mask[VALUES], |
|
|
int |
verbosity |
|
) |
| |
Removes a value from the possibilities of all others in the same column.
- Parameters
-
| [in] | col | The column to be removed from |
| [in] | value | The value to be removed |
| [in] | mask | A bitmap with positions to ignore in removal |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
739 for (
int row = 0; row <
VALUES; row++) {
740 if (mask[row] == 1) {
744 if (
possible[row][col][value] == 1) {
749 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
750 valid[value + 1], row, col);
◆ remove_value_from_row()
| int remove_value_from_row |
( |
int |
row, |
|
|
int |
value, |
|
|
int |
mask[VALUES], |
|
|
int |
verbosity |
|
) |
| |
Removes a value from the possibilities of all others in the same row.
- Parameters
-
| [in] | row | The row to be removed from |
| [in] | value | The value to be removed |
| [in] | mask | A bitmap with positions to ignore in removal |
| [in] | verbosity | The verbosity of the output (print or hide) |
| [out] | removed | (Bool) 0: False, 1: True |
710 for (
int col = 0; col <
VALUES; col++) {
711 if (mask[col] == 1) {
715 if (
possible[row][col][value] == 1) {
720 printf(REMOVE
"Eliminated: %s at (%i, %i)\n",
721 valid[value + 1], row, col);
◆ unique_in_box()
| int* unique_in_box |
( |
int * |
value | ) |
|
Gets position which is the only place for a possible value in a box.
]
- Parameters
-
| [in,out] | value | The value in this position (0-indexed) |
| [out] | pair | The position of the unique cell or NULL |
632 int checkArray[
VALUES][2];
633 for (
int col = 0; col <
SUB_SIZE; col++) {
634 for (
int row = 0; row <
SUB_SIZE; row++) {
635 memset(checkArray, 0,
sizeof(checkArray));
636 for (
int subCol = 0; subCol <
SUB_SIZE; subCol++) {
637 for (
int subRow = 0; subRow <
SUB_SIZE; subRow++) {
638 int curRow = row *
SUB_SIZE + subRow;
639 int curCol = col *
SUB_SIZE + subCol;
641 for (
int val = 0; val <
VALUES; val++) {
642 if (
possible[curRow][curCol][val] == 1) {
643 checkArray[val][0] += 1;
644 int curIndex = curRow *
SUB_SIZE + curCol;
645 checkArray[val][1] = curIndex;
651 for (
int val = 0; val <
VALUES; val++) {
652 if (checkArray[val][0] == 1) {
◆ unique_in_col()
| int* unique_in_col |
( |
int * |
value | ) |
|
Gets position which is only place for a possible value in a col.
- Parameters
-
| [in,out] | value | The value in this position (0-indexed) |
| [out] | pair | The position of the unique cell or NULL |
603 int checkArray[
VALUES][2];
604 for (
int col = 0; col <
VALUES; col++) {
605 memset(checkArray, 0,
sizeof(checkArray));
606 for (
int row = 0; row <
VALUES; row++) {
608 for (
int val = 0; val <
VALUES; val++) {
610 checkArray[val][0] += 1;
611 checkArray[val][1] = row;
616 for (
int val = 0; val <
VALUES; val++) {
617 if (checkArray[val][0] == 1) {
619 return make_pair(checkArray[val][1], col);
◆ unique_in_range()
| int* unique_in_range |
( |
int |
mode, |
|
|
int * |
value, |
|
|
int |
verbosity |
|
) |
| |
Gets position which is only place for a possible value in a house.
Uses the other three "unique_in" functions to achieve this.
- Parameters
-
| [in,out] | value | The value in this position |
| [out] | pair | The position of the unique cell or NULL |
673 if (verbosity == 1) {
674 printf(ADD
"Added %s at (%i, %i) as unique in row\n",
675 valid[*value + 1], output[0], output[1]);
680 if (verbosity == 1) {
681 printf(ADD
"Added %s at (%i, %i) as unique in column\n",
682 valid[*value + 1], output[0], output[1]);
687 if (verbosity == 1) {
688 printf(ADD
"Added %s at (%i, %i) as unique in box\n",
689 valid[*value + 1], output[0], output[1]);
◆ unique_in_row()
| int* unique_in_row |
( |
int * |
value | ) |
|
Gets position which is only place for a possible value in a row.
- Parameters
-
| [in,out] | value | The value in this position (0-indexed) |
| [out] | pair | The position of the unique cell or NULL |
574 int checkArray[
VALUES][2];
575 for (
int row = 0; row <
VALUES; row++) {
576 memset(checkArray, 0,
sizeof(checkArray));
577 for (
int col = 0; col <
VALUES; col++) {
579 for (
int val = 0; val <
VALUES; val++) {
581 checkArray[val][0] += 1;
582 checkArray[val][1] = col;
587 for (
int val = 0; val <
VALUES; val++) {
588 if (checkArray[val][0] == 1) {
590 return make_pair(row, checkArray[val][1]);
◆ valid_in_box()
| int valid_in_box |
( |
int |
value, |
|
|
int |
row, |
|
|
int |
col |
|
) |
| |
Checks if the value is valid (no duplicates) in the given box.
- Parameters
-
| [in] | value | The value to check the validity of |
| [in] | row,col | A position in the box to check the validity within |
| [out] | valid | (Bool) 0: False, 1: True |
831 for (
int pos = 0; pos <
VALUES; pos++) {
◆ valid_in_col()
| int valid_in_col |
( |
int |
value, |
|
|
int |
col |
|
) |
| |
Checks if the value is valid (no duplicates) in the given column.
- Parameters
-
| [in] | value | The value to check the validity of |
| [in] | col | The col to check the validity within |
| [out] | valid | (Bool) 0: False, 1: True |
814 for (
int row = 0; row <
VALUES; row++) {
◆ valid_in_row()
| int valid_in_row |
( |
int |
value, |
|
|
int |
row |
|
) |
| |
Checks if the value is valid (no duplicates) in the given row.
- Parameters
-
| [in] | value | The value to check the validity of |
| [in] | row | The row to check the validity within |
| [out] | valid | (Bool) 0: False, 1: True |
799 for (
int col = 0; col <
VALUES; col++) {
◆ write_to_file()
| void write_to_file |
( |
FILE * |
output | ) |
|
Writes the contents of the grid to a file in csv format.
- Parameters
-
| [in] | output | The file to write the output to |
1823 char buffer[ROW_BUF_SIZE];
1824 for (
int row = 0; row <
VALUES; row++) {
1826 memset(buffer,
'\0',
sizeof(buffer));
1827 for (
int col = 0; col <
VALUES; col++) {
1828 int len = strlen(
grid[row][col]);
1829 strncpy(&buffer[bufPos],
grid[row][col], len);
1831 buffer[bufPos] =
',';
1834 buffer[bufPos - 1] =
'\0';
1835 fprintf(output,
"%s\n", buffer);
int * make_pair(int row, int col)
Dynamically allocated and initializes a pair of values.
Definition: sudoku.c:529
int find_group(int considered[VALUES], int candidCount, int size, int pos, int mode, int verbosity, int isHidden)
Wrapper function for forming naked groups and evaluating them.
Definition: sudoku.c:1531
int * unique_in_box(int *value)
Gets position which is the only place for a possible value in a box.
Definition: sudoku.c:631
void free_globals()
Frees the dynamically allocated global variables.
Definition: sudoku.c:195
void print_possible()
Prints all possible values for each cell in the grid (FOR TESTING).
Definition: sudoku.c:469
char *** grid
A string 2-D array storing known or determined values.
Definition: sudoku.c:18
int max(int a, int b)
Returns the maximum of two integers.
Definition: sudoku.c:912
int process_token(int *tokenCount, char *token, int row, int col)
Sanitize, and set the grid to reference a valid token.
Definition: sudoku.c:252
int * find_single()
Gets the next pair of row and column where there is only one possibility.
Definition: sudoku.c:540
int read_csv(const char *fileName, char *missing)
Reads from a csv file and loads into the grid.
Definition: sudoku.c:279
void pre_process(int *cellsLeft)
Initializes a bitmap to hold possible values.
Definition: sudoku.c:403
int candid_group(int considered[VALUES], int curConsidered, int candidCount, int *candidates, int curCandid, int targetSize, int curSize, int pos, int mode, int verbosity, int isHidden)
Recursive function to create groups of candidate numbers of the given size.
Definition: sudoku.c:1478
int remove_value_from_row(int row, int value, int mask[VALUES], int verbosity)
Removes a value from the possibilities of all others in the same row.
Definition: sudoku.c:707
int read_bulk(const char *fileName, int forceFlag)
Reads, solves and checks all sudokus in a bulk sudoku file.
Definition: sudoku.c:1872
int initialize_globals(char buffer[ROW_BUF_SIZE], int isBulk)
Allocates and initializes the global variables.
Definition: sudoku.c:154
int process_next(int *cellsLeft, int verbosity, int forceFlag)
Process the next iteration of the loop.
Definition: sudoku.c:1752
int VALUES
The number of values that the sudoku can hold.
Definition: sudoku.c:22
int focus_house(int houseBM[SUB_SIZE])
Returns overlapping house where possible locations of a value lie in.
Definition: sudoku.c:925
int naked_groups(int size, int verbosity)
Top-level function to find and remove naked groups.
Definition: sudoku.c:1547
void get_boxes_bitmap(int array[SUB_SIZE][SUB_SIZE][VALUES])
Stores all columns as a bitmap of numbers.
Definition: sudoku.c:360
int intersection_removal(int verbosity)
Find value in only overlapping house and remove from rest of other houses.
Definition: sudoku.c:944
int hidden_groups(int size, int verbosity)
Top-level function to find and remove hidden groups.
Definition: sudoku.c:1621
int read_file(char *inCsv, char *missing, int isBulk, int forceFlag)
Adapter function to handle the reading of a file depending on its structure.
Definition: sudoku.c:1985
int eval_hidden_group(int *candidates, int size, int pos, int mode, int verbosity)
Evaluates a hidden group by checking validity and removing redundancy.
Definition: sudoku.c:1368
int valid_in_col(int value, int col)
Checks if the value is valid (no duplicates) in the given column.
Definition: sudoku.c:813
void write_to_file(FILE *output)
Writes the contents of the grid to a file in csv format.
Definition: sudoku.c:1822
int process_arguments(int argc, char *argv[], int *verbosity, int *bulkFlag, int *timeFlag, int *forceFlag, int *debugFlag, char **inCsv, char **outCsv, char **missing)
Processes the command line arguments provided.
Definition: sudoku.c:43
int export_grid(char *outCsv)
Exports the solved grid as a csv file.
Definition: sudoku.c:1844
int remove_hidden_group(int *rows, int *cols, int *shared, int size, int mode, int verbosity)
Removes values according to the contents of a known hidden group.
Definition: sudoku.c:1168
int eval_naked_group(int *candidates, int size, int pos, int mode, int verbosity)
Evaluates a naked group by checking validity and removing redundancy.
Definition: sudoku.c:1221
int valid_in_box(int value, int row, int col)
Checks if the value is valid (no duplicates) in the given box.
Definition: sudoku.c:828
int eliminate_redundant(int verbosity)
Elminates redundant possibilities using the techniques the solver knows.
Definition: sudoku.c:1712
char ** valid
Stores the valid tokens that can be used in the sudoku grid.
Definition: sudoku.c:21
int * unique_in_col(int *value)
Gets position which is only place for a possible value in a col.
Definition: sudoku.c:602
int remove_value_from_box(int row, int col, int value, int mask[VALUES], int verbosity)
Removes a value from the possibilities of all others in the same box.
Definition: sudoku.c:765
void print_grid()
Prints the current state of the grid in a formatted output.
Definition: sudoku.c:500
int addToValid(int *tokenCount, char *token)
Add the token to the valid array if not full.
Definition: sudoku.c:227
int get_possible_value(int *pair)
Assumes there is only one value in the bitmap and retrieves it.
Definition: sudoku.c:556
int valid_in_row(int value, int row)
Checks if the value is valid (no duplicates) in the given row.
Definition: sudoku.c:798
int * unique_in_range(int mode, int *value, int verbosity)
Gets position which is only place for a possible value in a house.
Definition: sudoku.c:670
int *** possible
Stores all possible values for each cell in the grid.
Definition: sudoku.c:19
int SUB_SIZE
The root of the values; i.e. the length of the boxes.
Definition: sudoku.c:23
void get_columns_bitmap(int array[VALUES][VALUES])
Stores all columns as a bitmap of numbers.
Definition: sudoku.c:341
int ** possibleCount
Stores the number of possibilities for each cell.
Definition: sudoku.c:20
int brute_force_rec(int curRow, int curCol, int verbosity)
Attempts to solve using a brute force mechanism.
Definition: sudoku.c:846
void brute_force(int verbosity)
Wrapper function to handle result of recursive brute force appropriately.
Definition: sudoku.c:895
void get_row_bitmap(int row, int array[VALUES])
Stores the current row as a bitmap of numbers.
Definition: sudoku.c:386
int remove_naked_group(int *rows, int *cols, int *shared, int size, int mode, int verbosity)
Removes values according to the contents of a known naked group.
Definition: sudoku.c:1100
int * unique_in_row(int *value)
Gets position which is only place for a possible value in a row.
Definition: sudoku.c:573
int remove_value_from_column(int col, int value, int mask[VALUES], int verbosity)
Removes a value from the possibilities of all others in the same column.
Definition: sudoku.c:736