Created
June 12, 2021 14:06
-
-
Save uysalserkan/2159fed9d2b36ed5527add14bebd841d to your computer and use it in GitHub Desktop.
Sudoku Solver - Recursive function C++17 or above
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file SudokuSolver.cpp | |
* @author Serkan UYSAL (uysalserkan08) | |
* @brief Sudoku Solver with recursive functions and class. | |
* @version 0.1 | |
* @date 2021-06-12 | |
* | |
* @copyright Copyright (c) 2021 | |
* | |
*/ | |
#include <vector> | |
#include <array> | |
#include <bitset> | |
#include <iostream> | |
using namespace std; | |
constexpr size_t get_cell(size_t row, size_t col) noexcept | |
{ | |
return ((row / 3) * 3 + col / 3); | |
} | |
constexpr size_t get_next_row(size_t row, size_t col) noexcept | |
{ | |
return (row + (col + 1) / 9); | |
} | |
constexpr size_t get_next_col(size_t col) noexcept | |
{ | |
return ((col + 1) % 9); | |
} | |
class Solution | |
{ | |
public: | |
void solveSudoku(vector<vector<char>> &board) const noexcept | |
{ | |
// Recursive solution | |
array<bitset<9>, 9> row_contains = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
array<bitset<9>, 9> col_contains = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
array<bitset<9>, 9> cell_contains = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
for (size_t row = 0; row < 9; ++row) | |
{ | |
for (size_t col = 0; col < 9; ++col) | |
{ | |
char digit; | |
if ((digit = board[row][col]) != '.') | |
{ | |
size_t digit_idx = digit - '1'; | |
row_contains[row].set(digit_idx); | |
col_contains[col].set(digit_idx); | |
size_t cell = get_cell(row, col); | |
cell_contains[cell].set(digit_idx); | |
} | |
} | |
} | |
// solve.. | |
solve(board, 0, 0, row_contains, col_contains, cell_contains); | |
} | |
private: | |
static constexpr pair<size_t, size_t> next_empty_position(vector<vector<char>> &board, size_t row, size_t col) noexcept | |
{ | |
while (row != 9) | |
{ | |
if (board[row][col] == '.') | |
{ | |
return {row, col}; | |
} | |
row = get_next_row(row, col); | |
col = get_next_col(col); | |
} | |
return {9, 0}; | |
} | |
static bool solve( | |
vector<vector<char>> &board, | |
size_t const row_start, | |
size_t const col_start, | |
array<bitset<9>, 9> &row_contains, | |
array<bitset<9>, 9> &col_contains, | |
array<bitset<9>, 9> &cell_contains) noexcept | |
{ | |
auto [row, col] = next_empty_position(board, row_start, col_start); | |
if (row == 9) | |
{ | |
return true; | |
} | |
size_t const cell = get_cell(row, col); | |
bitset<9> const contains = row_contains[row] | col_contains[col] | cell_contains[cell]; | |
if (contains.all()) | |
{ | |
return false; | |
} | |
for (size_t digit_idx = 0; digit_idx < 9; ++digit_idx) | |
{ | |
if (!contains[digit_idx]) | |
{ | |
board[row][col] = static_cast<char>(digit_idx + '1'); | |
row_contains[row].set(digit_idx); | |
col_contains[col].set(digit_idx); | |
cell_contains[cell].set(digit_idx); | |
if (solve(board, row, col, row_contains, col_contains, cell_contains)) | |
{ | |
return true; | |
} | |
row_contains[row].reset(digit_idx); | |
col_contains[col].reset(digit_idx); | |
cell_contains[cell].reset(digit_idx); | |
} | |
} | |
board[row][col] = '.'; | |
return false; | |
} | |
}; | |
void print_board(vector<vector<char>> board) | |
{ | |
for (size_t row = 0; row < 9; ++row) | |
{ | |
for (size_t col = 0; col < 9; ++col) | |
{ | |
cout << board[row][col] << ", "; | |
} | |
cout << "\n"; | |
} | |
} | |
vector<vector<char>> flat_board_to_vec_vec(array<char, 81> const flat_board) | |
{ | |
vector<vector<char>> board; | |
board.reserve(9); | |
for (size_t row = 0; row < 9; ++row) | |
{ | |
vector<char> this_row; | |
this_row.reserve(9); | |
for (size_t col = 0; col < 9; ++col) | |
{ | |
this_row.push_back(flat_board[row * 9 + col]); | |
} | |
board.push_back(this_row); | |
} | |
return board; | |
} | |
int main() | |
{ | |
array<char, 81> const flat_board = {'5', '3', '.', '.', '7', '.', '.', '.', '.', '6', '.', '.', '1', '9', '5', '.', '.', '.', '.', '9', '8', '.', '.', '.', '.', '6', '.', '8', '.', '.', '.', '6', '.', '.', '.', '3', '4', '.', '.', '8', '.', '3', '.', '.', '1', '7', '.', '.', '.', '2', '.', '.', '.', '6', '.', '6', '.', '.', '.', '.', '2', '8', '.', '.', '.', '.', '4', '1', '9', '.', '.', '5', '.', '.', '.', '.', '8', '.', '.', '7', '9'}; | |
array<char, 81> const flat_expected = {'5', '3', '4', '6', '7', '8', '9', '1', '2', '6', '7', '2', '1', '9', '5', '3', '4', '8', '1', '9', '8', '3', '4', '2', '5', '6', '7', '8', '5', '9', '7', '6', '1', '4', '2', '3', '4', '2', '6', '8', '5', '3', '7', '9', '1', '7', '1', '3', '9', '2', '4', '8', '5', '6', '9', '6', '1', '5', '3', '7', '2', '8', '4', '2', '8', '7', '4', '1', '9', '6', '3', '5', '3', '4', '5', '2', '8', '6', '1', '7', '9'}; | |
vector<vector<char>> board = flat_board_to_vec_vec(flat_board); | |
vector<vector<char>> const expected = flat_board_to_vec_vec(flat_expected); | |
Solution xSol; | |
xSol.solveSudoku(board); | |
cout << (board == expected ? "success!" : "UH OH :(") << std::endl; | |
cout << "actual\n"; | |
print_board(board); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment