14 if (n == 0 || n == 1)
return n;
15 size_t lo = 1, hi = n;
17 size_t mid = lo + (hi - lo) / 2;
18 if (mid * mid == n)
return mid;
19 if (mid * mid < n) lo = mid + 1;
31 for (
size_t i = 1; i * i <= n; ++i) {
32 if (i * i == n)
return true;
54 using Board = std::array<std::array<int, N>, N>;
79 explicit SudokuSolver(
const std::vector<FixedCell>& fixed_cells);
92 std::expected<Board, SolverError>
solve()
const;
95 std::vector<FixedCell> fixed_cells;
99 static constexpr size_t CELLS = N * N;
100 static constexpr size_t CONSTRAINTS_COUNT = 4;
101 static constexpr size_t TOTAL_COLUMNS = CONSTRAINTS_COUNT * CELLS;
105 std::vector<FixedCell> fixed_cells;
109 static constexpr size_t CELLS = N * N;
110 static constexpr size_t CONSTRAINTS_COUNT = 4;
111 static constexpr size_t TOTAL_COLUMNS = CONSTRAINTS_COUNT * CELLS;
121 static std::array<int, SudokuSolver<N>::CONSTRAINTS_COUNT> getColumnIndices(
int row,
int col,
int digit);
130 static int encodeRowId(
int row,
int col,
int digit);
137 static FixedCell decodeRowId(
int row_id);
157 Board rebuildBoardFromSolution(
const std::vector<int>& solution)
const;
167 : fixed_cells(fixed_cells) {}
171 for (
size_t row = 0; row < N; ++row) {
172 for (
size_t col = 0; col < N; ++col) {
173 if (board[row][col] != 0) {
174 fixed_cells.emplace_back(row, col, board[row][col]);
186 fillExactCoverMatrix(dlx);
189 if (!applyInitialConstraints(dlx)) {
193 auto solution = dlx.
search(CELLS - fixed_cells.size());
194 if (!solution.has_value()) {
198 return rebuildBoardFromSolution(solution.value());
203std::array<int, SudokuSolver<N>::CONSTRAINTS_COUNT> SudokuSolver<N>::getColumnIndices
204(
int row,
int col,
int digit) {
207 int block = (row / BLOCK_SIZE) * BLOCK_SIZE + (col / BLOCK_SIZE);
209 int cell_idx = row * N + col;
210 int row_idx = CELLS + row * N + d;
211 int col_idx = 2 * CELLS + col * N + d;
212 int block_idx = 3 * CELLS + block * N + d;
213 return { cell_idx, row_idx, col_idx, block_idx};
217int SudokuSolver<N>::encodeRowId(
int row,
int col,
int digit) {
218 return ((row * N + col) * N + (digit - 1));
223 int digit_minus_1 = row_id % N;
224 int cell = row_id / N;
227 return { row, col, digit_minus_1 + 1 };
233 for (
size_t row = 0; row != N; ++row) {
234 for (
size_t col = 0; col != N; ++col) {
235 for (
int digit = 1; digit <= N; ++digit) {
237 int row_id = encodeRowId(row, col, digit);
238 auto indices = getColumnIndices(row, col, digit);
240 dlx.
addRow(indices, row_id);
248 for (
const auto& [row, col, digit] : fixed_cells) {
249 for (
int col_idx : getColumnIndices(row, col, digit)) {
250 if (digit < 1 || digit > N || dlx.
isCovered(col_idx)) {
261SudokuSolver<N>::rebuildBoardFromSolution(
const std::vector<int>& solution)
const {
265 for (
const auto& [row, col, digit] : fixed_cells) {
266 board[row][col] = digit;
269 for (
int row_id : solution) {
270 auto [row, col, digit] = decodeRowId(row_id);
271 board[row][col] = digit;
Определения dancing_links_matrix.h:8
void addRow(std::span< const int > col_indices, int row_id)
Добавляет строку в матрицу
Определения dancing_links_matrix.cpp:80
std::optional< std::vector< int > > search(int expected_solution_size=0)
Поиск точного покрытия (алгоритм X).
Определения dancing_links_matrix.cpp:115
void cover(int col_idx)
Покрывает столбец и все конфликтующие с ним строки
Определения dancing_links_matrix.cpp:107
bool isCovered(int col_idx) const
Проверяет, покрыт ли столбец
Определения dancing_links_matrix.cpp:127
SudokuSolver & operator=(const SudokuSolver &)=default
std::array< std::array< int, N >, N > Board
Тип доски: квадратная матрица N×N, 0 обозначает пустую клетку
Определения sudoku_solver.h:54
SudokuSolver(const SudokuSolver &)=default
std::expected< Board, SolverError > solve() const
Решает судоку с заданными начальными условиями
Определения sudoku_solver.h:183
SudokuSolver(const Board &board)
Конструктор от полной доски
Определения sudoku_solver.h:170
SolverError
Ошибки, которые может вернуть метод solve().
Определения sudoku_solver.h:64
@ INVALID_CONSTRAINTS
Начальные данные противоречивы
Определения sudoku_solver.h:65
@ NO_SOLUTION
Решения не существует
Определения sudoku_solver.h:66
SudokuSolver(SudokuSolver &&)=default
std::tuple< int, int, int > FixedCell
Тип ячейки с фиксированным значением: (строка, столбец, цифра).
Определения sudoku_solver.h:59
SudokuSolver & operator=(SudokuSolver &&)=default
Концепт: размер судоку должен быть полным квадратом
Определения sudoku_solver.h:42
constexpr size_t constexpr_sqrt(size_t n)
Вычисление целочисленного квадратного корня на этапе компиляции
Определения sudoku_solver.h:13
constexpr bool isPerfectSquare(size_t n)
Проверяет, является ли число полным квадратом
Определения sudoku_solver.h:30