diff --git a/.gitignore b/.gitignore index ea8c4bf..e3318bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/c_version/sudk_c diff --git a/c_version/clangtest b/c_version/clangtest new file mode 100755 index 0000000..b7ce4e8 --- /dev/null +++ b/c_version/clangtest @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +clang -Wall -Wextra -Weverything -Werror -O3 -march=native -flto -std=c17 -fstack-protector-all -s -o sudk_c "$1" + +time ./sudk_c diff --git a/c_version/gcctest b/c_version/gcctest new file mode 100755 index 0000000..6b0eeb7 --- /dev/null +++ b/c_version/gcctest @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +gcc -Wall -Wextra -Werror --std=c17 -march=native -O3 -fstack-protector-all -flto -s -o sudk_c "$1" + +time ./sudk_c diff --git a/c_version/sudk_lots_of_allocs_for_tmp_rows_cols_blocks.c b/c_version/sudk_lots_of_allocs_for_tmp_rows_cols_blocks.c new file mode 100644 index 0000000..e05caa8 --- /dev/null +++ b/c_version/sudk_lots_of_allocs_for_tmp_rows_cols_blocks.c @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include + +#define PFSALLOC(bytes) malloc(bytes) + +static inline void Print_Clear() { printf("\x1b\x5b\x48\x1b\x5b\x32\x4a"); } + +typedef struct Sudoku { + size_t *field; + size_t *fixed; + size_t *known; + size_t size; + size_t block_size; + size_t pos; + size_t pos_last_placed; + size_t num_fields; +} Sudoku; + +static Sudoku *Sudoku_New(size_t block_size) { + + Sudoku *s = calloc(1, sizeof(Sudoku)); + + size_t many_solutions_field[81] = { + 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 8, 9, 0, 2, 0, 0, 0, 0, + 0, 2, 0, 4, 0, 0, 0, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 6, 5, 0, 0, 2, 0, 7, 4, 0, 3, 0, 0, 0, 5, 0, 4, 0, + 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 6, 0, + }; + + size_t size = block_size * block_size; + size_t *field = calloc(size * size, sizeof(size_t)); + size_t *fixed = calloc(size * size, sizeof(size_t)); + size_t *known = calloc(size * size, sizeof(size_t)); + + printf("num_fields: %zu\n", size * size); + + s->field = field; + s->fixed = fixed; + s->known = known; + + for (size_t idx = 0; idx < 81; idx++) { + s->field[idx] = many_solutions_field[idx]; + } + + for (size_t idx = 0; idx < 81; idx++) { + if (s->field[idx] != 0) { + s->fixed[idx] = 1; + s->known[idx] = 1; + } + } + + s->size = size; + s->block_size = block_size; + s->pos = 0; + s->pos_last_placed = 0; + s->num_fields = size * size; + + return s; +} + +static void Sudoku_Print(Sudoku *s) { + for (size_t idx = 0; idx < s->size * s->size; idx++) { + + // newline + if (idx != 0 && idx % s->size == 0) + printf("\n"); + + // nr + printf("%zu", s->field[idx]); + + // space + if ((idx + 1) % s->size != 0) + printf(" "); + } + printf("\n"); +} + +static inline bool Sudoku_Next(Sudoku *s) { + if (s->pos == s->num_fields - 1) { + /*printf("there is no next\n");*/ + return false; + } + + s->pos++; + return true; +} + +static inline bool Sudoku_Prev(Sudoku *s) { + if (s->pos == 0) + return false; + + s->pos--; + return true; +} + +static inline bool Sudoku_IsFixed(Sudoku *s) { return s->fixed[s->pos] == 1; } + +static inline size_t Sudoku_GetFieldAtPos(Sudoku *s, size_t pos) { + return s->field[pos]; +} + +static inline void Sudoku_Set(Sudoku *s, size_t nr) { + s->field[s->pos] = nr; + s->pos_last_placed = s->pos; +} + +static inline void Sudoku_ClearCurrentField(Sudoku *s) { Sudoku_Set(s, 0); } + +/*static void Array_Print(char *name, size_t *arr, size_t len) {*/ +/*printf("%s: ", name);*/ +/*for (size_t idx = 0; idx < len; idx++) {*/ +/*if (idx < len - 1)*/ +/*printf("%zu ", arr[idx]);*/ +/*else*/ +/*printf("%zu", arr[idx]);*/ +/*}*/ +/*printf("\n");*/ +/*}*/ + +static inline bool Array_Contains(size_t *arr, size_t len, size_t nr) { + /*printf("ARRAY_CONTAINS_LEN: %zu\n", len);*/ + for (size_t idx = 0; idx < len; idx++) { + if (arr[idx] == nr) { + /*printf("SEARCH FOR %zu --- ", nr);*/ + /*Array_Print("ARRAY_CONTAINS_TRUE", arr, len);*/ + return true; + } + } + /*printf("SEARCH FOR %zu --- ", nr);*/ + /*Array_Print("ARRAY_CONTAINS_FALSE", arr, len);*/ + return false; +} + +static inline bool Sudoku_IsEnd(Sudoku *s) { + return !Array_Contains(s->field, s->num_fields, 0); +} + +static inline bool Sudoku_GotoPrevFreeField(Sudoku *s) { + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Prev(s)); + + return false; +} + +static inline bool Sudoku_GotoNextFreeField(Sudoku *s) { + /*printf("Sudoku_GotoNextFreeField\n");*/ + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Next(s)); + + return false; +} + +static inline size_t *Sudoku_GetRow(Sudoku *s) { + size_t *tmp = PFSALLOC(s->size * sizeof(size_t)); + for (size_t pos = 0; pos < s->size; pos++) { + tmp[pos] = Sudoku_GetFieldAtPos(s, (s->pos / s->size) * s->size + pos); + } + return tmp; +} + +static inline size_t *Sudoku_GetCol(Sudoku *s) { + size_t *tmp = PFSALLOC(s->size * sizeof(size_t)); + for (size_t pos = 0; pos < s->size; pos++) { + tmp[pos] = Sudoku_GetFieldAtPos(s, pos * s->size + s->pos % s->size); + } + return tmp; +} + +static inline size_t *Sudoku_GetBlock(Sudoku *s) { + size_t *tmp = PFSALLOC(s->size * sizeof(size_t)); + + size_t block_start_row = s->pos / s->size / s->block_size * s->block_size; + size_t block_start_col = s->pos % s->size / s->block_size * s->block_size; + + for (size_t r = 0; r < s->block_size; r++) { + for (size_t c = 0; c < s->block_size; c++) { + tmp[r * s->block_size + c] = Sudoku_GetFieldAtPos( + s, s->size * (block_start_row + r) + block_start_col + c); + } + } + return tmp; +} + +static inline bool Sudoku_BlockOk(Sudoku *s, size_t nr) { + size_t *block = Sudoku_GetBlock(s); + /*Array_Print("BLOCK", block, s->size);*/ + bool ok = !Array_Contains(block, s->size, nr); + return ok; +} + +static inline bool Sudoku_RowOk(Sudoku *s, size_t nr) { + size_t *row = Sudoku_GetRow(s); + bool ok = !Array_Contains(row, s->size, nr); + return ok; +} + +static inline bool Sudoku_ColOk(Sudoku *s, size_t nr) { + size_t *col = Sudoku_GetCol(s); + bool ok = !Array_Contains(col, s->size, nr); + return ok; +} + +static inline bool Sudoku_Ok(Sudoku *s, size_t nr) { + return Sudoku_BlockOk(s, nr) && Sudoku_ColOk(s, nr) && Sudoku_RowOk(s, nr); +} + +static inline bool Sudoku_PutValidNr(Sudoku *s) { + size_t current_nr = Sudoku_GetFieldAtPos(s, s->pos); + + /*printf("%s() pos=%zu current_nr=%zu\n", __func__, s->pos, current_nr);*/ + + for (size_t nr = current_nr; nr < s->size + 1; nr++) { + if (Sudoku_Ok(s, nr)) { + /*printf("%s() pos=%zu current_nr=%zu nr=%zu\n", __func__, s->pos,*/ + /*current_nr, nr);*/ + Sudoku_Set(s, nr); + return true; + } + } + return false; +} + +static bool Sudoku_SolveBacktracking(Sudoku *s) { + bool found_solution = false; + size_t num_solutions = 0; + while (1) { + /*printf("LOOP: pos=%zu\n", s->pos);*/ + /*Sudoku_Print(s);*/ + if (Sudoku_IsEnd(s)) { + /*printf("END\n");*/ + found_solution = true; + num_solutions++; + if (num_solutions % 100 == 0) { + Print_Clear(); + printf("Solutions: %zu\n", num_solutions); + Sudoku_Print(s); + } + + if (Sudoku_IsFixed(s)) { + /*printf("fixed\n");*/ + continue; + } + Sudoku_ClearCurrentField(s); + Sudoku_Prev(s); + Sudoku_GotoPrevFreeField(s); + } + + if (Sudoku_IsFixed(s)) { + /*printf("fixed -> goto next\n");*/ + Sudoku_Next(s); + continue; + } + + if (Sudoku_GotoNextFreeField(s)) { + if (Sudoku_PutValidNr(s)) { + Sudoku_Next(s); + continue; + } else { + Sudoku_ClearCurrentField(s); + if (!Sudoku_Prev(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + if (!Sudoku_GotoPrevFreeField(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + } + } + } + + return found_solution; +} + +int main() { + Sudoku *s = Sudoku_New(3); + Sudoku_Print(s); + Sudoku_SolveBacktracking(s); + /*Sudoku_Print(s);*/ +} diff --git a/c_version/sudk_no_alloc_instead_use_global_mut_mem_once_initialized_on_start.c b/c_version/sudk_no_alloc_instead_use_global_mut_mem_once_initialized_on_start.c new file mode 100644 index 0000000..4f8b508 --- /dev/null +++ b/c_version/sudk_no_alloc_instead_use_global_mut_mem_once_initialized_on_start.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include + +static size_t *tmpArr; + +static inline void Print_Clear() { printf("\x1b\x5b\x48\x1b\x5b\x32\x4a"); } + +typedef struct Sudoku { + size_t *field; + size_t *fixed; + size_t size; + size_t block_size; + size_t pos; + size_t pos_last_placed; + size_t num_fields; +} Sudoku; + +static Sudoku *Sudoku_New(size_t block_size) { + + Sudoku *s = calloc(1, sizeof(Sudoku)); + + size_t many_solutions_field[81] = { + 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 8, 9, 0, 2, 0, 0, 0, 0, + 0, 2, 0, 4, 0, 0, 0, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 6, 5, 0, 0, 2, 0, 7, 4, 0, 3, 0, 0, 0, 5, 0, 4, 0, + 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 6, 0, + }; + + size_t size = block_size * block_size; + size_t *field = calloc(size * size, sizeof(size_t)); + size_t *fixed = calloc(size * size, sizeof(size_t)); + + printf("num_fields: %zu\n", size * size); + + s->field = field; + s->fixed = fixed; + + for (size_t idx = 0; idx < 81; idx++) { + s->field[idx] = many_solutions_field[idx]; + } + + for (size_t idx = 0; idx < 81; idx++) { + if (s->field[idx] != 0) { + s->fixed[idx] = 1; + } + } + + s->size = size; + s->block_size = block_size; + s->pos = 0; + s->pos_last_placed = 0; + s->num_fields = size * size; + + tmpArr = calloc(s->size, sizeof(size_t)); + + return s; +} + +static void Sudoku_Print(Sudoku *s) { + for (size_t idx = 0; idx < s->size * s->size; idx++) { + + // newline + if (idx != 0 && idx % s->size == 0) + printf("\n"); + + // nr + printf("%zu", s->field[idx]); + + // space + if ((idx + 1) % s->size != 0) + printf(" "); + } + printf("\n"); +} + +static inline bool Sudoku_Next(Sudoku *s) { + if (s->pos == s->num_fields - 1) { + /*printf("there is no next\n");*/ + return false; + } + + s->pos++; + return true; +} + +static inline bool Sudoku_Prev(Sudoku *s) { + if (s->pos == 0) + return false; + + s->pos--; + return true; +} + +static inline bool Sudoku_IsFixed(Sudoku *s) { return s->fixed[s->pos] == 1; } + +static inline size_t Sudoku_GetFieldAtPos(Sudoku *s, size_t pos) { + return s->field[pos]; +} + +static inline void Sudoku_Set(Sudoku *s, size_t nr) { + s->field[s->pos] = nr; + s->pos_last_placed = s->pos; +} + +static inline void Sudoku_ClearCurrentField(Sudoku *s) { Sudoku_Set(s, 0); } + +static inline bool Array_Contains(size_t *arr, size_t len, size_t nr) { + /*printf("ARRAY_CONTAINS_LEN: %zu\n", len);*/ + for (size_t idx = 0; idx < len; idx++) { + if (arr[idx] == nr) { + /*printf("SEARCH FOR %zu --- ", nr);*/ + /*Array_Print("ARRAY_CONTAINS_TRUE", arr, len);*/ + return true; + } + } + /*printf("SEARCH FOR %zu --- ", nr);*/ + /*Array_Print("ARRAY_CONTAINS_FALSE", arr, len);*/ + return false; +} + +static inline bool Sudoku_IsEnd(Sudoku *s) { + return !Array_Contains(s->field, s->num_fields, 0); +} + +static inline bool Sudoku_GotoPrevFreeField(Sudoku *s) { + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Prev(s)); + + return false; +} + +static inline bool Sudoku_GotoNextFreeField(Sudoku *s) { + /*printf("Sudoku_GotoNextFreeField\n");*/ + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Next(s)); + + return false; +} + +static inline size_t *Sudoku_GetRow(Sudoku *s) { + for (size_t pos = 0; pos < s->size; pos++) { + tmpArr[pos] = Sudoku_GetFieldAtPos(s, (s->pos / s->size) * s->size + pos); + } + return tmpArr; +} + +static inline size_t *Sudoku_GetCol(Sudoku *s) { + for (size_t pos = 0; pos < s->size; pos++) { + tmpArr[pos] = Sudoku_GetFieldAtPos(s, pos * s->size + s->pos % s->size); + } + return tmpArr; +} + +static inline size_t *Sudoku_GetBlock(Sudoku *s) { + size_t block_start_row = s->pos / s->size / s->block_size * s->block_size; + size_t block_start_col = s->pos % s->size / s->block_size * s->block_size; + + for (size_t r = 0; r < s->block_size; r++) { + for (size_t c = 0; c < s->block_size; c++) { + tmpArr[r * s->block_size + c] = Sudoku_GetFieldAtPos( + s, s->size * (block_start_row + r) + block_start_col + c); + } + } + return tmpArr; +} + +static inline bool Sudoku_BlockOk(Sudoku *s, size_t nr) { + size_t *block = Sudoku_GetBlock(s); + /*Array_Print("BLOCK", block, s->size);*/ + bool ok = !Array_Contains(block, s->size, nr); + return ok; +} + +static inline bool Sudoku_RowOk(Sudoku *s, size_t nr) { + size_t *row = Sudoku_GetRow(s); + bool ok = !Array_Contains(row, s->size, nr); + return ok; +} + +static inline bool Sudoku_ColOk(Sudoku *s, size_t nr) { + size_t *col = Sudoku_GetCol(s); + bool ok = !Array_Contains(col, s->size, nr); + return ok; +} + +static inline bool Sudoku_Ok(Sudoku *s, size_t nr) { + return Sudoku_BlockOk(s, nr) && Sudoku_ColOk(s, nr) && Sudoku_RowOk(s, nr); +} + +static inline bool Sudoku_PutValidNr(Sudoku *s) { + size_t current_nr = Sudoku_GetFieldAtPos(s, s->pos); + + /*printf("%s() pos=%zu current_nr=%zu\n", __func__, s->pos, current_nr);*/ + + for (size_t nr = current_nr; nr < s->size + 1; nr++) { + if (Sudoku_Ok(s, nr)) { + /*printf("%s() pos=%zu current_nr=%zu nr=%zu\n", __func__, s->pos,*/ + /*current_nr, nr);*/ + Sudoku_Set(s, nr); + return true; + } + } + return false; +} + +static bool Sudoku_SolveBacktracking(Sudoku *s) { + bool found_solution = false; + size_t num_solutions = 0; + while (1) { + /*printf("LOOP: pos=%zu\n", s->pos);*/ + /*Sudoku_Print(s);*/ + if (Sudoku_IsEnd(s)) { + /*printf("END\n");*/ + found_solution = true; + num_solutions++; + if (num_solutions % 100 == 0) { + Print_Clear(); + printf("Solutions: %zu\n", num_solutions); + Sudoku_Print(s); + } + + if (Sudoku_IsFixed(s)) { + /*printf("fixed\n");*/ + continue; + } + Sudoku_ClearCurrentField(s); + Sudoku_Prev(s); + Sudoku_GotoPrevFreeField(s); + } + + if (Sudoku_IsFixed(s)) { + /*printf("fixed -> goto next\n");*/ + Sudoku_Next(s); + continue; + } + + if (Sudoku_GotoNextFreeField(s)) { + if (Sudoku_PutValidNr(s)) { + Sudoku_Next(s); + continue; + } else { + Sudoku_ClearCurrentField(s); + if (!Sudoku_Prev(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + if (!Sudoku_GotoPrevFreeField(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + } + } + } + + return found_solution; +} + +static void Sudoku_Free(Sudoku *s) { + free(s->field); + free(s->fixed); + free(s); + s = NULL; +} + +int main() { + Sudoku *s = Sudoku_New(3); + Sudoku_Print(s); + Sudoku_SolveBacktracking(s); + Sudoku_Free(s); + free(tmpArr); +} diff --git a/c_version/sudk_stack.c b/c_version/sudk_stack.c new file mode 100644 index 0000000..ae97249 --- /dev/null +++ b/c_version/sudk_stack.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include + +static inline void Print_Clear() { printf("\x1b\x5b\x48\x1b\x5b\x32\x4a"); } + +typedef struct Sudoku { + size_t *field; + size_t *fixed; + size_t size; + size_t block_size; + size_t pos; + size_t pos_last_placed; + size_t num_fields; +} Sudoku; + +static Sudoku *Sudoku_New(size_t block_size) { + + Sudoku *s = calloc(1, sizeof(Sudoku)); + + // clang-format off + size_t many_solutions_field[81] = { + 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 8, 9, 0, 2, 0, + 0, 0, 0, 0, 2, 0, 4, 0, 0, + 0, 0, 4, 0, 6, 0, 0, 0, 8, + 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 6, 5, 0, 0, 2, 0, 7, 4, + 0, 3, 0, 0, 0, 5, 0, 4, 0, + 0, 0, 1, 8, 0, 0, 0, 0, 0, + 0, 0, 8, 2, 0, 0, 0, 6, 0, + }; + // clang-format on + + size_t size = block_size * block_size; + size_t *field = calloc(size * size, sizeof(size_t)); + size_t *fixed = calloc(size * size, sizeof(size_t)); + + printf("num_fields: %zu\n", size * size); + + s->field = field; + s->fixed = fixed; + + for (size_t idx = 0; idx < 81; idx++) { + s->field[idx] = many_solutions_field[idx]; + } + + for (size_t idx = 0; idx < 81; idx++) { + if (s->field[idx] != 0) { + s->fixed[idx] = 1; + } + } + + s->size = size; + s->block_size = block_size; + s->pos = 0; + s->pos_last_placed = 0; + s->num_fields = size * size; + + return s; +} + +static inline void Sudoku_Print(Sudoku *s) { + for (size_t idx = 0; idx < s->num_fields; idx++) { + + // newline + if (idx != 0 && idx % s->size == 0) + printf("\n"); + + // nr + printf("%zu", s->field[idx]); + + // space + if ((idx + 1) % s->size != 0) + printf(" "); + } + printf("\n"); +} + +static inline bool Sudoku_Next(Sudoku *s) { + if (s->pos == s->num_fields - 1) { + return false; + } + + s->pos++; + return true; +} + +static inline bool Sudoku_Prev(Sudoku *s) { + if (s->pos == 0) + return false; + + s->pos--; + return true; +} + +static inline bool Sudoku_IsFixed(Sudoku *s) { return s->fixed[s->pos] == 1; } + +static inline size_t Sudoku_GetFieldAtPos(Sudoku *s, size_t pos) { + return s->field[pos]; +} + +static inline void Sudoku_Set(Sudoku *s, size_t nr) { + s->field[s->pos] = nr; + s->pos_last_placed = s->pos; +} + +static inline void Sudoku_ClearCurrentField(Sudoku *s) { Sudoku_Set(s, 0); } + +static inline bool Array_Contains(size_t *arr, size_t len, size_t nr) { + for (size_t idx = 0; idx < len; idx++) { + if (arr[idx] == nr) { + return true; + } + } + return false; +} + +static inline bool Sudoku_IsEnd(Sudoku *s) { + return !Array_Contains(s->field, s->num_fields, 0); +} + +static inline bool Sudoku_GotoPrevFreeField(Sudoku *s) { + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Prev(s)); + + return false; +} + +static inline bool Sudoku_GotoNextFreeField(Sudoku *s) { + do { + if (!Sudoku_IsFixed(s)) + return true; + } while (Sudoku_Next(s)); + + return false; +} + +static inline void Sudoku_GetRow(Sudoku *s, size_t *row) { + for (size_t pos = 0; pos < s->size; pos++) { + row[pos] = Sudoku_GetFieldAtPos(s, (s->pos / s->size) * s->size + pos); + } +} + +static inline void Sudoku_GetCol(Sudoku *s, size_t *col) { + for (size_t pos = 0; pos < s->size; pos++) { + col[pos] = Sudoku_GetFieldAtPos(s, pos * s->size + s->pos % s->size); + } +} + +static inline void Sudoku_GetBlock(Sudoku *s, size_t *block) { + size_t block_start_row = s->pos / s->size / s->block_size * s->block_size; + size_t block_start_col = s->pos % s->size / s->block_size * s->block_size; + + for (size_t r = 0; r < s->block_size; r++) { + for (size_t c = 0; c < s->block_size; c++) { + block[r * s->block_size + c] = Sudoku_GetFieldAtPos( + s, s->size * (block_start_row + r) + block_start_col + c); + } + } +} + +static inline bool Sudoku_BlockOk(Sudoku *s, size_t nr) { + bool ok; + size_t block[9] = {0}; + Sudoku_GetBlock(s, block); + ok = !Array_Contains(block, s->size, nr); + return ok; +} + +static inline bool Sudoku_RowOk(Sudoku *s, size_t nr) { + bool ok; + size_t row[9] = {0}; + Sudoku_GetRow(s, row); + ok = !Array_Contains(row, s->size, nr); + return ok; +} + +static inline bool Sudoku_ColOk(Sudoku *s, size_t nr) { + bool ok; + size_t col[9] = {0}; + Sudoku_GetCol(s, col); + ok = !Array_Contains(col, s->size, nr); + return ok; +} + +static inline bool Sudoku_Ok(Sudoku *s, size_t nr) { + return Sudoku_BlockOk(s, nr) && Sudoku_ColOk(s, nr) && Sudoku_RowOk(s, nr); +} + +static inline bool Sudoku_PutValidNr(Sudoku *s) { + size_t current_nr = Sudoku_GetFieldAtPos(s, s->pos); + for (size_t nr = current_nr; nr < s->size + 1; nr++) { + if (Sudoku_Ok(s, nr)) { + Sudoku_Set(s, nr); + return true; + } + } + return false; +} + +static bool Sudoku_SolveBacktracking(Sudoku *s) { + bool found_solution = false; + size_t num_solutions = 0; + while (1) { + if (Sudoku_IsEnd(s)) { + found_solution = true; + num_solutions++; + if (num_solutions % 100 == 0) { + Print_Clear(); + printf("Solutions: %zu\n", num_solutions); + Sudoku_Print(s); + } + + if (Sudoku_IsFixed(s)) { + continue; + } + Sudoku_ClearCurrentField(s); + Sudoku_Prev(s); + Sudoku_GotoPrevFreeField(s); + } + + if (Sudoku_IsFixed(s)) { + Sudoku_Next(s); + continue; + } + + if (Sudoku_GotoNextFreeField(s)) { + if (Sudoku_PutValidNr(s)) { + Sudoku_Next(s); + continue; + } else { + Sudoku_ClearCurrentField(s); + if (!Sudoku_Prev(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + if (!Sudoku_GotoPrevFreeField(s)) { + printf("Number of solutions: %zu\n", num_solutions); + break; + } + } + } + } + + return found_solution; +} + +static void Sudoku_Free(Sudoku *s) { + free(s->field); + free(s->fixed); + free(s); + s = NULL; +} + +int main() { + Sudoku *s = Sudoku_New(3); + Sudoku_Print(s); + Sudoku_SolveBacktracking(s); + Sudoku_Free(s); +}