333 lines
8.2 KiB
C
Raw Normal View History

2025-01-10 21:53:10 +00:00
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#define PUZZLE_ROWS 9
#define PUZZLE_COLS 9
#define PUZZLE_SIZE PUZZLE_ROWS*PUZZLE_COLS
#define ANSII_BLUE_BG "\033[44m"
#define ANSII_RED_BG "\033[41m"
#define ANSII_GREEN_BG "\033[42m"
#define ANSII_CLEAR "\033[0m"
typedef struct sudoku_cell_t
{
char c;
bool predefined;
bool sure;
bool empty;
} sudoku_cell_t;
sudoku_cell_t *get_cell(sudoku_cell_t *puzzle, unsigned int row, unsigned int column)
{
sudoku_cell_t *cell = &puzzle[row * PUZZLE_COLS + column];
return cell;
}
void set_cell(sudoku_cell_t *puzzle, unsigned int row, unsigned int column, bool predefined, bool sure, char c)
{
sudoku_cell_t *cell = get_cell(puzzle, row, column);
cell->predefined = predefined;
cell->sure = predefined ? true : sure;
cell->c = c;
cell->empty = c == 0;
}
void set_cellc(sudoku_cell_t *puzzle, char column, unsigned int row, bool predefined, bool sure, char c)
{
unsigned int irow = row - 1;
unsigned int icol = column - 65;
set_cell(puzzle, irow, icol, predefined, sure, c);
}
void set_predefinedc(sudoku_cell_t *puzzle, char row, unsigned int column, char c)
{
set_cellc(puzzle, row, column, true, true, c);
}
void set_sure(sudoku_cell_t *puzzle, char row, unsigned int column, char c)
{
set_cell(puzzle, row, column, false, true, c);
}
void set_guess(sudoku_cell_t *puzzle, char row, unsigned int column, char c)
{
set_cell(puzzle, row, column, false, false, c);
}
void set_guessc(sudoku_cell_t *puzzle, char row, unsigned int column, char c)
{
set_cellc(puzzle, row, column, false, false, c);
}
void set_zero(sudoku_cell_t *puzzle, char row, unsigned int column)
{
set_cellc(puzzle, row, column, false, false, 0);
}
void init_puzzle(sudoku_cell_t *puzzle, unsigned int rows, unsigned int cols)
{
for (unsigned int i = 0; i < rows * cols; i++)
{
puzzle[i].c = 0;
puzzle[i].empty = true;
puzzle[i].predefined = false;
puzzle[i].sure = true;
}
}
void draw_cell(sudoku_cell_t *cell)
{
if (cell->predefined)
{
printf("%s", ANSII_BLUE_BG);
}
else if (cell->empty)
{
printf("%s", ANSII_CLEAR);
}
else if (cell->sure)
{
printf("%s", ANSII_GREEN_BG);
}
else if (!cell->empty)
{
printf("%s", ANSII_RED_BG);
}
printf(" %c ", cell->c == 0 ? ' ' : cell->c);
printf("%s", ANSII_CLEAR);
}
void draw_puzzle(sudoku_cell_t *puzzle, unsigned int rows, unsigned int cols)
{
for (unsigned int i = 0; i < cols; i++)
{
for (unsigned int j = 0; j < rows; j++)
{
sudoku_cell_t *cell = &puzzle[i * cols + j];
draw_cell(cell);
}
printf("\n");
}
}
sudoku_cell_t *get_col(sudoku_cell_t *puzzle, unsigned int rows, unsigned int col)
{
static sudoku_cell_t box[4096];
for (unsigned int i = 0; i < rows; i++)
{
box[i] = *get_cell(puzzle, i, col);
}
return box;
}
sudoku_cell_t *get_row(sudoku_cell_t *puzzle, unsigned int cols, unsigned int row)
{
static sudoku_cell_t box[4096];
for (unsigned int i = 0; i < cols; i++)
{
box[i] = *get_cell(puzzle, row, i);
}
return box;
}
sudoku_cell_t *get_box(sudoku_cell_t *puzzle, unsigned int rows, unsigned int cols, unsigned int row, unsigned int col)
{
unsigned int col_box_column = col / 3;
unsigned int row_box_row = row / 3;
static sudoku_cell_t box[4096];
unsigned int counter = 0;
for (unsigned int i = row_box_row * (rows / 3); i < (row_box_row * rows / 3) + (rows / 3); i++)
{
for (unsigned int j = col_box_column * (cols / 3); j < (col_box_column * cols / 3) + (cols / 3); j++)
{
box[counter] = *get_cell(puzzle, i, j);
counter++;
}
}
return box;
}
unsigned int *get_options(sudoku_cell_t *puzzle, unsigned int rows, unsigned int cols, unsigned int row, unsigned int col)
{
static unsigned int options[4096];
memset(options, 0, sizeof(options));
for (unsigned int i = 0; i < cols; i++)
{
options[i] = true;
}
for (unsigned int i = 0; i < cols; i++)
{
sudoku_cell_t *c = get_col(puzzle, rows, col);
for (unsigned int j = 0; j < cols; j++)
{
if (!c[j].empty)
options[c[i].c - '0' - 1] = false;
}
c = get_row(puzzle, cols, row);
for (unsigned int j = 0; j < cols; j++)
{
if (!c[j].empty)
options[c[j].c - '0' - 1] = false;
}
c = get_box(puzzle, rows, cols, row, col);
for (unsigned int j = 0; j < cols * cols; j++)
{
if (!c[j].empty)
options[c[j].c - '0' - 1] = false;
}
}
return options;
}
unsigned int get_option(unsigned int *options, unsigned int offset)
{
unsigned int result = 0;
unsigned int current_offset = 0;
for (unsigned int i = 0; i < PUZZLE_COLS; i++)
{
if (options[i])
{
if (current_offset == offset)
{
return i;
}
offset++;
}
}
return result;
}
unsigned int get_options_count(unsigned int *options)
{
unsigned int result = 0;
for (unsigned int i = 0; i < PUZZLE_COLS; i++)
{
if (options[i])
{
result++;
}
}
return result;
}
unsigned int count_empty(sudoku_cell_t * puzzle, unsigned int size){
unsigned int count = 0;
for(unsigned int i = 0; i < size;i++){
if(puzzle[i].empty){
count++;
}
}
return count;
}
unsigned int set_sures(sudoku_cell_t *puzzle, unsigned int rows, unsigned int cols, unsigned int accuracy)
{
for (unsigned int i = 0; i < rows; i++)
{
for (unsigned int j = 0; j < cols; j++)
{
sudoku_cell_t *cell = get_cell(puzzle, i, j);
unsigned int *options = get_options(puzzle, rows, cols, i, j);
if (cell->empty && get_options_count(options) == accuracy)
{
unsigned int option = get_option(options, 0);
if (accuracy > 1)
{
set_guess(puzzle, i, j, option + '0' + 1);
}
else
{
set_sure(puzzle, i, j, option + '0' + 1);
}
set_sures(puzzle, rows, cols, accuracy);
return count_empty(puzzle,rows*cols);
}
}
}
return count_empty(puzzle,rows*cols);
}
unsigned int solve(char *charpuzzle)
{
sudoku_cell_t puzzle[PUZZLE_SIZE];
init_puzzle(puzzle, PUZZLE_ROWS, PUZZLE_COLS);
for (unsigned int i = 0; i < PUZZLE_ROWS; i++)
{
for (unsigned int j = 0; j < PUZZLE_COLS; j++)
{
if (charpuzzle[j * PUZZLE_COLS + i] != ' ')
set_predefinedc(puzzle, i + 65, j + 1, charpuzzle[j * PUZZLE_COLS + i]);
}
}
set_sures(puzzle, PUZZLE_ROWS, PUZZLE_COLS, 1);
unsigned int result = set_sures(puzzle, PUZZLE_ROWS, PUZZLE_COLS, 2);
if(result){
printf("Unresolved. %d cells left:\n",result);
}else{
printf("Succesfully resolved:\n");
}
draw_puzzle(puzzle, PUZZLE_ROWS, PUZZLE_COLS);
return result;
}
int main()
{
solve(
"913 5 "
"6 7 24"
" 5 8 7 "
" 79 "
" 2 9 43"
" 4 9 "
" 4 19 "
"7 6 9 5"
" 1 64 7");
printf("\n");
solve(
"5 3 7 "
"6 195 "
" 98 6 "
"8 6 3"
"4 8 3 "
"7 2 6"
" 6 28 "
" 419 5"
" 8 79");
printf("\n");
solve(
" 4 8 3 "
" 1 9 5"
"7 2 6 "
" 5 7 2"
" 4 "
"9 5 7 "
" 2 6 8"
"6 3 1 "
" 8 7 9 ");
printf("\n");
solve(
" 7429 8 "
"2 83 "
"896 351 4"
" 1 6 9 "
"7 1 2 6"
"6 973 1"
" 6 "
"5 8 9 "
"46 58 1 ");
printf("\n");
solve(
"2 5 74 6"
" 31 "
" 23 "
" 2 "
"86 31 "
" 45 "
" 9 7 "
" 695 2"
" 1 6 8");
printf("\n");
return 0;
}