From 4e3abd460102d74fe55f80882a71345ea34ee86a Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 29 Oct 2021 13:05:46 -0500 Subject: [PATCH] [feat/fix/docs]: Improvements in the `backtracking` folder (#1553) * [feat/fix/docs]: Improvements in the... ...`backtracking` folder, and minor fixes in the `others/iterative_tree_traversals.cpp` and the `math/check_prime.cpp` files. * clang-format and clang-tidy fixes for 9cc3951d Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> --- backtracking/graph_coloring.cpp | 40 ++- backtracking/knight_tour.cpp | 143 +++++----- backtracking/minimax.cpp | 36 +-- backtracking/n_queens.cpp | 157 ++++++----- .../n_queens_all_solution_optimised.cpp | 4 +- backtracking/nqueen_print_all_solutions.cpp | 25 +- backtracking/rat_maze.cpp | 24 +- backtracking/sudoku_solve.cpp | 260 ++++++++++-------- 8 files changed, 367 insertions(+), 322 deletions(-) diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp index baa10ab46..8fb328a1a 100644 --- a/backtracking/graph_coloring.cpp +++ b/backtracking/graph_coloring.cpp @@ -17,29 +17,38 @@ * @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include + +#include /// for std::array +#include /// for IO operations +#include /// for std::vector /** - * @namespace + * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { -/** A utility function to print solution +/** + * @namespace graph_coloring + * @brief Functions for the [Graph + * Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm, + */ +namespace graph_coloring { +/** + * @brief A utility function to print the solution * @tparam V number of vertices in the graph * @param color array of colors assigned to the nodes */ template void printSolution(const std::array& color) { - std::cout << "Following are the assigned colors" << std::endl; + std::cout << "Following are the assigned colors\n"; for (auto& col : color) { std::cout << col; } - std::cout << std::endl; + std::cout << "\n"; } -/** A utility function to check if the current color assignment is safe for +/** + * @brief Utility function to check if the current color assignment is safe for * vertex v * @tparam V number of vertices in the graph * @param v index of graph vertex to check @@ -60,7 +69,8 @@ bool isSafe(int v, const std::array, V>& graph, return true; } -/** A recursive utility function to solve m coloring problem +/** + * @brief Recursive utility function to solve m coloring problem * @tparam V number of vertices in the graph * @param graph matrix of graph nonnectivity * @param m number of colors @@ -74,28 +84,30 @@ void graphColoring(const std::array, V>& graph, int m, // base case: // If all vertices are assigned a color then return true if (v == V) { - backtracking::printSolution(color); + printSolution(color); return; } // Consider this vertex v and try different colors for (int c = 1; c <= m; c++) { // Check if assignment of color c to v is fine - if (backtracking::isSafe(v, graph, color, c)) { + if (isSafe(v, graph, color, c)) { color[v] = c; // recur to assign colors to rest of the vertices - backtracking::graphColoring(graph, m, color, v + 1); + graphColoring(graph, m, color, v + 1); // If assigning color c doesn't lead to a solution then remove it color[v] = 0; } } } +} // namespace graph_coloring } // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { // Create following graph and test whether it is 3 colorable @@ -113,6 +125,6 @@ int main() { int m = 3; // Number of colors std::array color{}; - backtracking::graphColoring(graph, m, color, 0); + backtracking::graph_coloring::graphColoring(graph, m, color, 0); return 0; } diff --git a/backtracking/knight_tour.cpp b/backtracking/knight_tour.cpp index 88883ee07..0223462db 100644 --- a/backtracking/knight_tour.cpp +++ b/backtracking/knight_tour.cpp @@ -1,6 +1,7 @@ /** * @file - * @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm + * @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour) + * algorithm * * @details * A knight's tour is a sequence of moves of a knight on a chessboard @@ -12,92 +13,102 @@ * @author [Nikhil Arora](https://github.com/nikhilarora068) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include +#include /// for std::array +#include /// for IO operations /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * A utility function to check if i,j are valid indexes for N*N chessboard - * @tparam V number of vertices in array - * @param x current index in rows - * @param y current index in columns - * @param sol matrix where numbers are saved - * @returns `true` if .... - * @returns `false` if .... - */ - template - bool issafe(int x, int y, const std::array , V>& sol) { - return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1); - } - - /** - * Knight's tour algorithm - * @tparam V number of vertices in array - * @param x current index in rows - * @param y current index in columns - * @param mov movement to be done - * @param sol matrix where numbers are saved - * @param xmov next move of knight (x coordinate) - * @param ymov next move of knight (y coordinate) - * @returns `true` if solution exists - * @returns `false` if solution does not exist - */ - template - bool solve(int x, int y, int mov, std::array , V> &sol, - const std::array &xmov, std::array &ymov) { - int k, xnext, ynext; - - if (mov == V * V) { - return true; - } - - for (k = 0; k < V; k++) { - xnext = x + xmov[k]; - ynext = y + ymov[k]; - - if (backtracking::issafe(xnext, ynext, sol)) { - sol[xnext][ynext] = mov; - - if (backtracking::solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) { - return true; - } - else { - sol[xnext][ynext] = -1; - } - } - } - return false; - } -} // namespace backtracking +/** + * @namespace knight_tour + * @brief Functions for the [Knight's + * tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm + */ +namespace knight_tour { +/** + * A utility function to check if i,j are valid indexes for N*N chessboard + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param sol matrix where numbers are saved + * @returns `true` if .... + * @returns `false` if .... + */ +template +bool issafe(int x, int y, const std::array, V> &sol) { + return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1); +} /** - * Main function + * Knight's tour algorithm + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param mov movement to be done + * @param sol matrix where numbers are saved + * @param xmov next move of knight (x coordinate) + * @param ymov next move of knight (y coordinate) + * @returns `true` if solution exists + * @returns `false` if solution does not exist + */ +template +bool solve(int x, int y, int mov, std::array, V> &sol, + const std::array &xmov, std::array &ymov) { + int k = 0, xnext = 0, ynext = 0; + + if (mov == V * V) { + return true; + } + + for (k = 0; k < V; k++) { + xnext = x + xmov[k]; + ynext = y + ymov[k]; + + if (issafe(xnext, ynext, sol)) { + sol[xnext][ynext] = mov; + + if (solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) { + return true; + } else { + sol[xnext][ynext] = -1; + } + } + } + return false; +} +} // namespace knight_tour +} // namespace backtracking + +/** + * @brief Main function + * @returns 0 on exit */ int main() { const int n = 8; - std::array , n> sol = { 0 }; + std::array, n> sol = {0}; - int i, j; + int i = 0, j = 0; for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { sol[i][j] = -1; } + for (j = 0; j < n; j++) { + sol[i][j] = -1; + } } - std::array xmov = { 2, 1, -1, -2, -2, -1, 1, 2 }; - std::array ymov = { 1, 2, 2, 1, -1, -2, -2, -1 }; + std::array xmov = {2, 1, -1, -2, -2, -1, 1, 2}; + std::array ymov = {1, 2, 2, 1, -1, -2, -2, -1}; sol[0][0] = 0; - bool flag = backtracking::solve(0, 0, 1, sol, xmov, ymov); + bool flag = backtracking::knight_tour::solve(0, 0, 1, sol, xmov, ymov); if (flag == false) { std::cout << "Error: Solution does not exist\n"; - } - else { + } else { for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { std::cout << sol[i][j] << " "; } + for (j = 0; j < n; j++) { + std::cout << sol[i][j] << " "; + } std::cout << "\n"; } } diff --git a/backtracking/minimax.cpp b/backtracking/minimax.cpp index c39018805..b27c85e10 100644 --- a/backtracking/minimax.cpp +++ b/backtracking/minimax.cpp @@ -6,33 +6,34 @@ * @details * Minimax (sometimes MinMax, MM or saddle point) is a decision rule used in * artificial intelligence, decision theory, game theory, statistics, - * and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario. - * When dealing with gains, it is referred to as "maximin"—to maximize the minimum gain. - * Originally formulated for two-player zero-sum game theory, covering both the cases where players take - * alternate moves and those where they make simultaneous moves, it has also been extended to more - * complex games and to general decision-making in the presence of uncertainty. - * + * and philosophy for minimizing the possible loss for a worst case (maximum + * loss) scenario. When dealing with gains, it is referred to as "maximin"—to + * maximize the minimum gain. Originally formulated for two-player zero-sum game + * theory, covering both the cases where players take alternate moves and those + * where they make simultaneous moves, it has also been extended to more complex + * games and to general decision-making in the presence of uncertainty. + * * @author [Gleison Batista](https://github.com/gleisonbs) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include -#include +#include /// for std::max, std::min +#include /// for std::array +#include /// for log2 +#include /// for IO operations -/** +/** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { /** - * Check which number is the maximum/minimum in the array + * @brief Check which is the maximum/minimum number in the array * @param depth current depth in game tree * @param node_index current index in array * @param is_max if current index is the longest number * @param scores saved numbers in array * @param height maximum height for game tree - * @return maximum or minimum number + * @returns the maximum or minimum number */ template int minimax(int depth, int node_index, bool is_max, @@ -46,16 +47,17 @@ int minimax(int depth, int node_index, bool is_max, return is_max ? std::max(v1, v2) : std::min(v1, v2); } -} // namespace backtracking +} // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { std::array scores = {90, 23, 6, 33, 21, 65, 123, 34423}; double height = log2(scores.size()); - std::cout << "Optimal value: " << backtracking::minimax(0, 0, true, scores, height) - << std::endl; + std::cout << "Optimal value: " + << backtracking::minimax(0, 0, true, scores, height) << std::endl; return 0; } diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index 89d907750..f9742eb7a 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -15,115 +15,114 @@ * @author [David Leal](https://github.com/Panquesito7) * */ -#include #include +#include /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * @namespace n_queens - * @brief Functions for [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle. - */ - namespace n_queens { - /** - * Utility function to print matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - */ - template - void printSolution(const std::array, n> &board) { - std::cout << "\n"; - for (int i = 0; i < n; i++) { +/** + * @namespace n_queens + * @brief Functions for [Eight + * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle. + */ +namespace n_queens { +/** + * Utility function to print matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + */ +template +void printSolution(const std::array, n> &board) { + std::cout << "\n"; + for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - std::cout << "" << board[i][j] << " "; + std::cout << "" << board[i][j] << " "; } std::cout << "\n"; - } } +} - /** - * Check if a queen can be placed on matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param row current index in rows - * @param col current index in columns - * @returns `true` if queen can be placed on matrix - * @returns `false` if queen can't be placed on matrix - */ - template - bool isSafe(const std::array, n> &board, const int &row, - const int &col) { - int i = 0, j = 0; +/** + * Check if a queen can be placed on matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param row current index in rows + * @param col current index in columns + * @returns `true` if queen can be placed on matrix + * @returns `false` if queen can't be placed on matrix + */ +template +bool isSafe(const std::array, n> &board, const int &row, + const int &col) { + int i = 0, j = 0; - // Check this row on left side - for (i = 0; i < col; i++) { + // Check this row on left side + for (i = 0; i < col; i++) { if (board[row][i]) { - return false; + return false; } - } - - // Check upper diagonal on left side - for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { - if (board[i][j]) { - return false; - } - } - // Check lower diagonal on left side - for (i = row, j = col; j >= 0 && i < n; i++, j--) { - if (board[i][j]) { - return false; - } - } - return true; } - /** - * Solve n queens problem - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param col current index in columns - */ - template - void solveNQ(std::array, n> board, const int &col) { - if (col >= n) { + // Check upper diagonal on left side + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { + if (board[i][j]) { + return false; + } + } + // Check lower diagonal on left side + for (i = row, j = col; j >= 0 && i < n; i++, j--) { + if (board[i][j]) { + return false; + } + } + return true; +} + +/** + * Solve n queens problem + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param col current index in columns + */ +template +void solveNQ(std::array, n> board, const int &col) { + if (col >= n) { printSolution(board); return; - } + } - // Consider this column and try placing - // this queen in all rows one by one - for (int i = 0; i < n; i++) { + // Consider this column and try placing + // this queen in all rows one by one + for (int i = 0; i < n; i++) { // Check if queen can be placed // on board[i][col] if (isSafe(board, i, col)) { - // Place this queen in matrix - board[i][col] = 1; + // Place this queen in matrix + board[i][col] = 1; - // Recursive to place rest of the queens - solveNQ(board, col + 1); + // Recursive to place rest of the queens + solveNQ(board, col + 1); - board[i][col] = 0; // backtrack + board[i][col] = 0; // backtrack } - } } - } // namespace n_queens -} // namespace backtracking +} +} // namespace n_queens +} // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { - const int n = 4; - std::array, n> board = { - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}) - }; + const int n = 4; + std::array, n> board = { + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0})}; - backtracking::n_queens::solveNQ(board, 0); - return 0; + backtracking::n_queens::solveNQ(board, 0); + return 0; } diff --git a/backtracking/n_queens_all_solution_optimised.cpp b/backtracking/n_queens_all_solution_optimised.cpp index bd150a98d..525d4c2db 100644 --- a/backtracking/n_queens_all_solution_optimised.cpp +++ b/backtracking/n_queens_all_solution_optimised.cpp @@ -111,7 +111,7 @@ int main() { std::array, n> board{}; if (n % 2 == 0) { - for (int i = 0; i <= n / 2 - 1; i++) { // 😎 + for (int i = 0; i <= n / 2 - 1; i++) { if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) { board[i][0] = 1; backtracking::n_queens_optimized::NQueenSol(board, 1); @@ -119,7 +119,7 @@ int main() { } } } else { - for (int i = 0; i <= n / 2; i++) { // 😏 + for (int i = 0; i <= n / 2; i++) { if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) { board[i][0] = 1; backtracking::n_queens_optimized::NQueenSol(board, 1); diff --git a/backtracking/nqueen_print_all_solutions.cpp b/backtracking/nqueen_print_all_solutions.cpp index 5aa5c71a2..8824cf0a8 100644 --- a/backtracking/nqueen_print_all_solutions.cpp +++ b/backtracking/nqueen_print_all_solutions.cpp @@ -1,14 +1,14 @@ /** * @file - * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) + * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) * puzzle, printing all solutions * * @author [Himani Negi](https://github.com/Himani2000) * @author [David Leal](https://github.com/Panquesito7) * */ -#include -#include +#include /// for std::array +#include /// for IO operations /** * @namespace backtracking @@ -17,12 +17,13 @@ namespace backtracking { /** * @namespace n_queens_all_solutions - * @brief Functions for [Eight - * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle with all solutions. + * @brief Functions for the [Eight + * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle with all + * solutions. */ namespace n_queens_all_solutions { /** - * Utility function to print matrix + * @brief Utility function to print matrix * @tparam n number of matrix size * @param board matrix where numbers are saved */ @@ -38,7 +39,7 @@ void PrintSol(const std::array, n>& board) { } /** - * Check if a queen can be placed on matrix + * @brief Check if a queen can be placed on the matrix * @tparam n number of matrix size * @param board matrix where numbers are saved * @param row current index in rows @@ -47,7 +48,8 @@ void PrintSol(const std::array, n>& board) { * @returns `false` if queen can't be placed on matrix */ template -bool CanIMove(const std::array, n>& board, int row, int col) { +bool CanIMove(const std::array, n>& board, int row, + int col) { /// check in the row for (int i = 0; i < col; i++) { if (board[row][i] == 1) { @@ -70,7 +72,7 @@ bool CanIMove(const std::array, n>& board, int row, int col) } /** - * Solve n queens problem + * @brief Main function to solve the N Queens problem * @tparam n number of matrix size * @param board matrix where numbers are saved * @param col current index in columns @@ -89,11 +91,12 @@ void NQueenSol(std::array, n> board, int col) { } } } -} // namespace n_queens_all_solutions +} // namespace n_queens_all_solutions } // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { const int n = 4; diff --git a/backtracking/rat_maze.cpp b/backtracking/rat_maze.cpp index 6dfda965c..60bc521c8 100644 --- a/backtracking/rat_maze.cpp +++ b/backtracking/rat_maze.cpp @@ -16,9 +16,9 @@ * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include +#include /// for std::array +#include /// for assert +#include /// for IO operations /** * @namespace backtracking @@ -39,12 +39,14 @@ namespace rat_maze { * @param currposcol current position in columns * @param maze matrix where numbers are saved * @param soln matrix to problem solution - * @returns 0 on end + * @returns `true` if there exists a solution to move one step ahead in a column + * or in a row + * @returns `false` for the backtracking part */ template bool solveMaze(int currposrow, int currposcol, - const std::array, size> &maze, - std::array, size> soln) { + const std::array, size> &maze, + std::array, size> soln) { if ((currposrow == size - 1) && (currposcol == size - 1)) { soln[currposrow][currposcol] = 1; for (int i = 0; i < size; ++i) { @@ -78,10 +80,10 @@ bool solveMaze(int currposrow, int currposcol, } // namespace backtracking /** - * @brief Test implementations + * @brief Self-test implementations * @returns void */ -static void test(){ +static void test() { const int size = 4; std::array, size> maze = { std::array{1, 0, 1, 0}, std::array{1, 0, 1, 1}, @@ -96,8 +98,8 @@ static void test(){ } } - int currposrow = 0; // Current position in rows - int currposcol = 0; // Current position in columns + int currposrow = 0; // Current position in the rows + int currposcol = 0; // Current position in the columns assert(backtracking::rat_maze::solveMaze(currposrow, currposcol, maze, soln) == 1); @@ -108,6 +110,6 @@ static void test(){ * @returns 0 on exit */ int main() { - test(); // run the tests + test(); // run self-test implementations return 0; } diff --git a/backtracking/sudoku_solve.cpp b/backtracking/sudoku_solve.cpp index d631d5dfd..38ccfa0b4 100644 --- a/backtracking/sudoku_solve.cpp +++ b/backtracking/sudoku_solve.cpp @@ -3,155 +3,171 @@ * @brief [Sudoku Solver](https://en.wikipedia.org/wiki/Sudoku) algorithm. * * @details - * Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, originally called - * Number Place) is a logic-based, combinatorial number-placement puzzle. - * In classic sudoku, the objective is to fill a 9×9 grid with digits so that each column, - * each row, and each of the nine 3×3 subgrids that compose the grid (also called "boxes", "blocks", or "regions") + * Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, + * originally called Number Place) is a logic-based, combinatorial + * number-placement puzzle. In classic sudoku, the objective is to fill a 9×9 + * grid with digits so that each column, each row, and each of the nine 3×3 + * subgrids that compose the grid (also called "boxes", "blocks", or "regions") * contain all of the digits from 1 to 9. The puzzle setter provides a - * partially completed grid, which for a well-posed puzzle has a single solution. + * partially completed grid, which for a well-posed puzzle has a single + * solution. * * @author [DarthCoder3200](https://github.com/DarthCoder3200) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include +#include /// for assert +#include /// for IO operations /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * Checks if it's possible to place a number 'no' - * @tparam V number of vertices in the array - * @param mat matrix where numbers are saved - * @param i current index in rows - * @param j current index in columns - * @param no number to be added in matrix - * @param n number of times loop will run - * @returns `true` if 'mat' is different from 'no' - * @returns `false` if 'mat' equals to 'no' - */ - template - bool isPossible(const std::array , V> &mat, int i, int j, int no, int n) { - /// 'no' shouldn't be present in either row i or column j - for (int x = 0; x < n; x++) { - if (mat[x][j] == no || mat[i][x] == no) { +/** + * @namespace sudoku_solver + * @brief Functions for the [Sudoku + * Solver](https://en.wikipedia.org/wiki/Sudoku) implementation + */ +namespace sudoku_solver { +/** + * @brief Check if it's possible to place a number (`no` parameter) + * @tparam V number of vertices in the array + * @param mat matrix where numbers are saved + * @param i current index in rows + * @param j current index in columns + * @param no number to be added in matrix + * @param n number of times loop will run + * @returns `true` if 'mat' is different from 'no' + * @returns `false` if 'mat' equals to 'no' + */ +template +bool isPossible(const std::array, V> &mat, int i, int j, + int no, int n) { + /// `no` shouldn't be present in either row i or column j + for (int x = 0; x < n; x++) { + if (mat[x][j] == no || mat[i][x] == no) { + return false; + } + } + + /// `no` shouldn't be present in the 3*3 subgrid + int sx = (i / 3) * 3; + int sy = (j / 3) * 3; + + for (int x = sx; x < sx + 3; x++) { + for (int y = sy; y < sy + 3; y++) { + if (mat[x][y] == no) { return false; } } + } - /// 'no' shouldn't be present in the 3*3 subgrid - int sx = (i / 3) * 3; - int sy = (j / 3) * 3; - - for (int x = sx; x < sx + 3; x++) { - for (int y = sy; y < sy + 3; y++) { - if (mat[x][y] == no) { - return false; - } + return true; +} +/** + * @brief Utility function to print the matrix + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param starting_mat copy of mat, required by printMat for highlighting the + * differences + * @param n number of times loop will run + * @return void + */ +template +void printMat(const std::array, V> &mat, + const std::array, V> &starting_mat, int n) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (starting_mat[i][j] != mat[i][j]) { + std::cout << "\033[93m" << mat[i][j] << "\033[0m" + << " "; + } else { + std::cout << mat[i][j] << " "; + } + if ((j + 1) % 3 == 0) { + std::cout << '\t'; } } - - return true; - } - /** - * Utility function to print matrix - * @tparam V number of vertices in array - * @param mat matrix where numbers are saved - * @param starting_mat copy of mat, required by printMat for highlighting the differences - * @param n number of times loop will run - * @return void - */ - template - void printMat(const std::array , V> &mat, const std::array , V> &starting_mat, int n) { - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - if (starting_mat[i][j] != mat[i][j]) { - std::cout << "\033[93m" << mat[i][j] << "\033[0m" << " "; - } else { - std::cout << mat[i][j] << " "; - } - if ((j + 1) % 3 == 0) { - std::cout << '\t'; - } - } - if ((i + 1) % 3 == 0) { - std::cout << std::endl; - } + if ((i + 1) % 3 == 0) { std::cout << std::endl; } + std::cout << std::endl; } - - /** - * Sudoku algorithm - * @tparam V number of vertices in array - * @param mat matrix where numbers are saved - * @param starting_mat copy of mat, required by printMat for highlighting the differences - * @param i current index in rows - * @param j current index in columns - * @returns `true` if 'no' was placed - * @returns `false` if 'no' was not placed - */ - template - bool solveSudoku(std::array , V> &mat, const std::array , V> &starting_mat, int i, int j) { - /// Base Case - if (i == 9) { - /// Solved for 9 rows already - backtracking::printMat(mat, starting_mat, 9); - return true; - } - - /// Crossed the last Cell in the row - if (j == 9) { - return backtracking::solveSudoku(mat, starting_mat, i + 1, 0); - } - - /// Blue Cell - Skip - if (mat[i][j] != 0) { - return backtracking::solveSudoku(mat, starting_mat, i, j + 1); - } - /// White Cell - /// Try to place every possible no - for (int no = 1; no <= 9; no++) { - if (backtracking::isPossible(mat, i, j, no, 9)) { - /// Place the 'no' - assuming a solution will exist - mat[i][j] = no; - bool solution_found = backtracking::solveSudoku(mat, starting_mat, i, j + 1); - if (solution_found) { - return true; - } - /// Couldn't find a solution - /// loop will place the next no. - } - } - /// Solution couldn't be found for any of the numbers provided - mat[i][j] = 0; - return false; - } -} // namespace backtracking +} /** - * Main function + * @brief Main function to implement the Sudoku algorithm + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param starting_mat copy of mat, required by printMat for highlighting the + * differences + * @param i current index in rows + * @param j current index in columns + * @returns `true` if 'no' was placed + * @returns `false` if 'no' was not placed + */ +template +bool solveSudoku(std::array, V> &mat, + const std::array, V> &starting_mat, int i, + int j) { + /// Base Case + if (i == 9) { + /// Solved for 9 rows already + printMat(mat, starting_mat, 9); + return true; + } + + /// Crossed the last Cell in the row + if (j == 9) { + return solveSudoku(mat, starting_mat, i + 1, 0); + } + + /// Blue Cell - Skip + if (mat[i][j] != 0) { + return solveSudoku(mat, starting_mat, i, j + 1); + } + /// White Cell + /// Try to place every possible no + for (int no = 1; no <= 9; no++) { + if (isPossible(mat, i, j, no, 9)) { + /// Place the 'no' - assuming a solution will exist + mat[i][j] = no; + bool solution_found = solveSudoku(mat, starting_mat, i, j + 1); + if (solution_found) { + return true; + } + /// Couldn't find a solution + /// loop will place the next `no`. + } + } + /// Solution couldn't be found for any of the numbers provided + mat[i][j] = 0; + return false; +} +} // namespace sudoku_solver +} // namespace backtracking + +/** + * @brief Main function + * @returns 0 on exit */ int main() { const int V = 9; - std::array , V> mat = { - std::array {5, 3, 0, 0, 7, 0, 0, 0, 0}, - std::array {6, 0, 0, 1, 9, 5, 0, 0, 0}, - std::array {0, 9, 8, 0, 0, 0, 0, 6, 0}, - std::array {8, 0, 0, 0, 6, 0, 0, 0, 3}, - std::array {4, 0, 0, 8, 0, 3, 0, 0, 1}, - std::array {7, 0, 0, 0, 2, 0, 0, 0, 6}, - std::array {0, 6, 0, 0, 0, 0, 2, 8, 0}, - std::array {0, 0, 0, 4, 1, 9, 0, 0, 5}, - std::array {0, 0, 0, 0, 8, 0, 0, 7, 9} - }; + std::array, V> mat = { + std::array{5, 3, 0, 0, 7, 0, 0, 0, 0}, + std::array{6, 0, 0, 1, 9, 5, 0, 0, 0}, + std::array{0, 9, 8, 0, 0, 0, 0, 6, 0}, + std::array{8, 0, 0, 0, 6, 0, 0, 0, 3}, + std::array{4, 0, 0, 8, 0, 3, 0, 0, 1}, + std::array{7, 0, 0, 0, 2, 0, 0, 0, 6}, + std::array{0, 6, 0, 0, 0, 0, 2, 8, 0}, + std::array{0, 0, 0, 4, 1, 9, 0, 0, 5}, + std::array{0, 0, 0, 0, 8, 0, 0, 7, 9}}; - backtracking::printMat(mat, mat, 9); + backtracking::sudoku_solver::printMat(mat, mat, 9); std::cout << "Solution " << std::endl; - std::array , V> starting_mat = mat; - backtracking::solveSudoku(mat, starting_mat, 0, 0); + std::array, V> starting_mat = mat; + backtracking::sudoku_solver::solveSudoku(mat, starting_mat, 0, 0); return 0; }