diff --git a/sudoku.c b/sudoku.c new file mode 100644 index 0000000..5c079b7 --- /dev/null +++ b/sudoku.c @@ -0,0 +1,327 @@ +#include +#include + +#define UNDEFINED -1 +#define MULTIPLE -2 +#define FIELD_UNDEFINED UNDEFINED +#define FIELD_MULTIPLE MULTIPLE + +#define VALUE_UNDEFINED UNDEFINED +#define VALUE_MULTIPLE MULTIPLE +#define VALUE_ALREADY_SET -3 + + +// https://en.wikipedia.org/wiki/Sudoku#/media/File:Sudoku_Puzzle_by_L2G-20050714_standardized_layout.svg +/* +int sudoku[9][9] = { + {5,3,0,6,0,0,0,9,8}, + {0,7,0,1,9,5,0,0,0}, + {0,0,0,0,0,0,0,6,0}, + {8,0,0,4,0,0,7,0,0}, + {0,6,0,8,0,3,0,2,0}, + {0,0,3,0,0,1,0,0,6}, + {0,6,0,0,0,0,0,0,0}, + {0,0,0,4,1,9,0,8,0}, + {2,8,0,0,0,5,0,7,9} +}; +*/ + +// https://www.free-sudoku.com/sudoku.php?dchoix=evil +int sudoku[9][9] = { + {VALUE_UNDEFINED,1,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {3,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,8,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,4,VALUE_UNDEFINED,VALUE_UNDEFINED,7,VALUE_UNDEFINED}, + {4,VALUE_UNDEFINED,5,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,8,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {VALUE_UNDEFINED,7,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,2,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,1,VALUE_UNDEFINED,VALUE_UNDEFINED,3,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,7,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {1,VALUE_UNDEFINED,VALUE_UNDEFINED,6,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED}, + {5,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,8,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED,VALUE_UNDEFINED} +}; + +void readQ(int num) { + printf("Enter every number of Q%d from left top to right bottom. Use `0` if on no initial value:\n", num + 1); + for (int i = 0; i < 9; i++) { + scanf("%d", &sudoku[num][i]); + } +} + +int calculateQuadrat(int row, int col) { + return (row / 3) * 3 + col / 3; +} + +int calculateField(int row, int col) { + return (row % 3) * 3 + col % 3; +} + +int calculateRow(int q, int f) { + return (q / 3) * 3 + (f / 3); +} + +int calculateCol(int q, int f) { + return (q % 3) * 3 + (f % 3); +} + +void printDumpSudoku() { + for (int row = 0; row < 9; row++) { + if (row % 3 == 0) { + printf("+-------+-------+-------+\n"); + } + for (int col = 0; col < 9; col++) { + if (col % 3 == 0) { + if (col != 0) { + printf(" "); + } + printf("|"); + } + + int q = calculateQuadrat(row, col); + int f = calculateField(row, col); + if (sudoku[q][f] > VALUE_UNDEFINED) { + printf(" %d", sudoku[q][f]); + } else { + printf(" -"); + } + } + printf(" |\n"); + } + printf("+-------+-------+-------+\n"); +} + +void printDumpQuadrat(int q[]) { + for (int row = 0; row < 3; row++) { + if (row % 3 == 0) { + printf("+-------+\n"); + } + for (int col = 0; col < 3; col++) { + if (col % 3 == 0) { + if (col != 0) { + printf(" "); + } + printf("|"); + } + + int f = calculateField(row, col); + printf(" %d", q[f]); + } + printf(" |\n"); + } + printf("+-------+\n"); +} + +// checks if this value is present anywhere in the row +bool isInRow(int row, int val) { + for (int col = 0; col < 9; col++) { + int q = calculateQuadrat(row, col); + int f = calculateField(row, col); + + if (sudoku[q][f] == val) { + return true; + } + } + + return false; +} + +// checks if this value is present anywhere in the col +bool isInCol(int col, int val) { + for (int row = 0; row < 9; row++) { + int q = calculateQuadrat(row, col); + int f = calculateField(row, col); + + if (sudoku[q][f] == val) { + return true; + } + } + + return false; +} + +// special version of isInRow where it checks if the value +// has to be in the row in special quadrat except the one +// we are currently looking at +bool isOnlyInOneRowQuadrat(int notThisQuadrat, int row, int val) { + int initQ = calculateQuadrat(row, 0); + + for (int q = initQ; q < initQ + 3; q++) { + if (q == notThisQuadrat) { + continue; + } + + bool skipQuadrat = false; + bool possibleRowFound = false; + for (int f = 0; f < 9 && !skipQuadrat; f++) { + int r = calculateRow(q, f); + int c = calculateCol(q, f); + + if (sudoku[q][f] == val) { + if (r == row) { + return true; + } else { + skipQuadrat = true; + continue; + } + } else if (sudoku[q][f] <= VALUE_UNDEFINED && !isInRow(r, val) && !isInCol(c, val)) { + if (r != row) { + return false; + } else { + possibleRowFound = true; + } + } else { + // field is either already set to another value or value is present in current row or col + // either way, this field is not a possible option for the value + } + } + + if (!skipQuadrat && possibleRowFound) { + // we found a possible field in row which may be filled with val + // and we didn't hit any abort condition for current quadrat + return true; + } + } + + // we didn't found a possible field in row and we didn't hit any + // abort condition. This is may happen if val is already set in bot + // quadrats but not in searched row + return false; +} + +// special version of isInCol where it checks if the value +// has to be in the col in special quadrat except the one +// we are currently looking at +bool isOnlyInOneColQuadrat(int notThisQuadrat, int col, int val) { + int initQ = calculateQuadrat(0, col); + + for (int q = initQ; q <= initQ + 6; q += 3) { + if (q == notThisQuadrat) { + continue; + } + + bool skipQuadrat = false; + bool possibleColFound = false; + for (int f = 0; f < 9 && !skipQuadrat; f++) { + int r = calculateRow(q, f); + int c = calculateCol(q, f); + + if (sudoku[q][f] == val) { + if (c == col) { + return true; + } else { + skipQuadrat = true; + continue; + } + } else if (sudoku[q][f] <= VALUE_UNDEFINED && !isInRow(r, val) && !isInCol(c, val)) { + if (c != col) { + return false; + } else { + possibleColFound = true; + } + } else { + // field is either already set to another value or value is present in current row or col + // either way, this field is not a possible option for the value + } + } + + if (!skipQuadrat && possibleColFound) { + // we found a possible field in row which may be filled with val + // and we didn't hit any abort condition for current quadrat + return true; + } + } + + // we didn't found a possible field in row and we didn't hit any + // abort condition. This is may happen if val is already set in bot + // quadrats but not in searched row + return false; +} + +// checks if this value is present anywhere in the quadrat +bool isInQuadrat(int q, int val) { + for (int f = 0; f < 9; f++) { + if (sudoku[q][f] == val) { + return true; + } + } + + return false; +} + +void setValue(int q, int f, int val) { + sudoku[q][f] = val; + printf("=> setting %d in Q %d; F %d\n", val, q, f); + printDumpSudoku(); +} + +int main() { + printDumpSudoku(); + bool somethingChanged; + do { + somethingChanged = false; + for (int q = 0; q < 9; q++) { + int possbileVal[9] = { + VALUE_UNDEFINED, VALUE_UNDEFINED, VALUE_UNDEFINED, + VALUE_UNDEFINED, VALUE_UNDEFINED, VALUE_UNDEFINED, + VALUE_UNDEFINED, VALUE_UNDEFINED, VALUE_UNDEFINED + }; + + for (int val = 1; val <= 9; val++) { + if (isInQuadrat(q, val)) { + continue; + } + + int possibleField = FIELD_UNDEFINED; + for (int f = 0; f < 9; f++) { + int row = calculateRow(q, f); + int col = calculateCol(q, f); + + // look for val in every row and col + // cache evaluation of isInRow and isInCol + if (sudoku[q][f] <= VALUE_UNDEFINED + && !(isInRow(row, val) || isOnlyInOneRowQuadrat(q, row, val)) + && !(isInCol(col, val) || isOnlyInOneColQuadrat(q, col, val))) { + // && !isInRow(row, val) + // && !isInCol(col, val)) { + if (possibleField == FIELD_UNDEFINED) { + possibleField = f; + } else { + possibleField = FIELD_MULTIPLE; + } + + if (possbileVal[f] == VALUE_UNDEFINED) { + possbileVal[f] = val; + } else if (possbileVal[f] > VALUE_UNDEFINED) { + possbileVal[f] = VALUE_MULTIPLE; + } else { + // already set to multiple or any other meta information + } + } + } + + // found possible field? set val + if (possibleField > FIELD_UNDEFINED) { + setValue(q, possibleField, val); + somethingChanged = true; + } + } + + // check if only one field is left undefined -> hast to be the one special value + int undefinedFound = VALUE_UNDEFINED; + for (int f = 0; f < 9; f++) { + // keep in mind that sudoku array might have changed since evaluation + // -> ignore already set values + if (sudoku[q][f] > VALUE_UNDEFINED) { + continue; + } + + if (possbileVal[f] > VALUE_UNDEFINED) { + setValue(q, f, possbileVal[f]); + somethingChanged = true; + } else { + // set to undefined, multiple or any other meta information + } + } + } + } while (somethingChanged); + + // next step: muss in Feld X sein, weil alle anderen Felder irgendwie anders belegt sein müssen (aber noch nicht sind) +} \ No newline at end of file diff --git a/test.c b/test.c new file mode 100644 index 0000000..f792609 --- /dev/null +++ b/test.c @@ -0,0 +1,15 @@ +#include + +int main() { + for (int row = 0; row < 9; row++) { + for (int col = 0; col < 9; col++) { + printf("row: %d col: %d Q: %d F: %d\n", row, col, (row / 3) * 3 + col / 3, (row % 3) * 3 + col % 3); + } + } + + for (int q = 0; q < 9; q++) { + for (int f = 0; f < 9; f++) { + printf("Q: %d F: %d row: %d col: %d\n", q, f, (q / 3) * 3 + (f / 3), (q % 3) * 3 + (f % 3)); + } + } +} \ No newline at end of file