It works!
But some optimizations left to do.
This commit is contained in:
parent
b1bcc49e3f
commit
3561fea707
165
main.cpp
165
main.cpp
@ -1,79 +1,168 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#define BOARD_SIZE 81
|
#define BOARD_SIZE 81
|
||||||
#define BOARD_DIMENSION 9
|
#define BOARD_DIMENSION 9
|
||||||
|
|
||||||
class Sudoku {
|
typedef std::pair<std::vector<int>, std::list<int>> move;
|
||||||
private:
|
|
||||||
int board[BOARD_SIZE];
|
|
||||||
|
|
||||||
|
class Board {
|
||||||
public:
|
public:
|
||||||
|
int values[BOARD_SIZE];
|
||||||
Sudoku(std::string s) {
|
|
||||||
for (unsigned int i = 0; i < s.length(); i++) {
|
|
||||||
board[i] = (int) (s[i] - '0');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void solve() {
|
|
||||||
// Very naive first attempt: Fails because it sets stuff wrongly and doesn't backtrack
|
|
||||||
for (int y = 0; y < BOARD_DIMENSION; y++) {
|
|
||||||
for (int x = 0; x < BOARD_DIMENSION; x++) {
|
|
||||||
if (get(x, y) == 0) {
|
|
||||||
auto possibilities = get_possibilities(x, y);
|
|
||||||
|
|
||||||
set(x, y, possibilities.front());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Real search:
|
|
||||||
// 1. Sort possibilities by how many new constraints they create
|
|
||||||
// 2. Start with the one creating the smallest amount of new constraints
|
|
||||||
// 3. Continue until dead end
|
|
||||||
// 4. If dead end: Try the next one
|
|
||||||
}
|
|
||||||
|
|
||||||
int coordinates_to_id(int x, int y) {
|
int coordinates_to_id(int x, int y) {
|
||||||
return y * BOARD_DIMENSION + x;
|
return y * BOARD_DIMENSION + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get(int x, int y) {
|
int get(int x, int y) {
|
||||||
return board[coordinates_to_id(x, y)];
|
return values[coordinates_to_id(x, y)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(int x, int y, int value) {
|
void set(int x, int y, int value) {
|
||||||
board[coordinates_to_id(x, y)] = value;
|
values[coordinates_to_id(x, y)] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Cell {
|
||||||
|
public:
|
||||||
|
Board *board;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
int value;
|
||||||
|
std::list<int> possible_values;
|
||||||
|
|
||||||
|
Cell(Board *board, int x, int y) : board(board), x(x), y(y), value(board->get(x, y)) {}
|
||||||
|
|
||||||
|
void set_value(int new_value) {
|
||||||
|
value = new_value;
|
||||||
|
update_possible_values();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<int> get_possibilities(int x, int y) {
|
void update_possible_values() {
|
||||||
std::list<int> possibilities{1, 2, 3, 4, 5, 6, 7, 8 ,9};
|
std::list<int> possibilities{1, 2, 3, 4, 5, 6, 7, 8 ,9};
|
||||||
|
|
||||||
// Remove all from this row
|
// Remove all from this row
|
||||||
for (int dx = 0; dx < BOARD_DIMENSION; dx++) {
|
for (int dx = 0; dx < BOARD_DIMENSION; dx++) {
|
||||||
possibilities.remove(get(dx, y));
|
possibilities.remove(board->get(dx, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all from this column
|
// Remove all from this column
|
||||||
for (int dy = 0; dy < BOARD_DIMENSION; dy++) {
|
for (int dy = 0; dy < BOARD_DIMENSION; dy++) {
|
||||||
possibilities.remove(get(x, dy));
|
possibilities.remove(board->get(x, dy));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all from this quadrant
|
// Remove all from this quadrant
|
||||||
for (int dy = 0; dy < 3; dy++) {
|
for (int dy = 0; dy < 3; dy++) {
|
||||||
for (int dx = 0; dx < 3; dx++) {
|
for (int dx = 0; dx < 3; dx++) {
|
||||||
possibilities.remove(get((x - x % 3) + dx, (y - y % 3) + dy));
|
possibilities.remove(board->get((x - x % 3) + dx, (y - y % 3) + dy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return possibilities;
|
possible_values = possibilities;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sudoku {
|
||||||
|
private:
|
||||||
|
Board *board = new Board();
|
||||||
|
std::vector<Cell> heap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Sudoku(std::string s) {
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < s.length(); i++) {
|
||||||
|
board->values[i] = (int) (s[i] - '0');
|
||||||
|
|
||||||
|
if (board->values[i] == 0) {
|
||||||
|
Cell cell(board, x, y);
|
||||||
|
heap.emplace_back(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
x++;
|
||||||
|
if (x == BOARD_DIMENSION) {
|
||||||
|
x -= BOARD_DIMENSION;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update values of cells initially
|
||||||
|
for (Cell &cell : heap) {
|
||||||
|
cell.update_possible_values();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::make_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sort_cells(const Cell& a, const Cell& b) {
|
||||||
|
return a.possible_values.size() < b.possible_values.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_all_cells() {
|
||||||
|
for (Cell &cell : heap) {
|
||||||
|
cell.update_possible_values();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell get_next_best_empty_cell() {
|
||||||
|
std::pop_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
|
Cell c = heap.back();
|
||||||
|
heap.pop_back();
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void solve() {
|
||||||
|
solve_recurse();
|
||||||
|
|
||||||
|
print_board();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool solve_recurse() {
|
||||||
|
// If there are no more possible moves in the heap...
|
||||||
|
if (heap.empty()) {
|
||||||
|
// Check whether there are empty fields left
|
||||||
|
for (int y = 0; y < BOARD_DIMENSION; y++) {
|
||||||
|
for (int x = 0; x < BOARD_DIMENSION; x++) {
|
||||||
|
if (board->get(x, y) == 0) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, we're done!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (heap.empty()) return true;
|
||||||
|
|
||||||
|
Cell cell = get_next_best_empty_cell();
|
||||||
|
|
||||||
|
for (int value : cell.possible_values) {
|
||||||
|
board->set(cell.x, cell.y, value);
|
||||||
|
update_all_cells();
|
||||||
|
|
||||||
|
if (solve_recurse()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
board->set(cell.x, cell.y, 0);
|
||||||
|
update_all_cells();
|
||||||
|
}
|
||||||
|
|
||||||
|
heap.push_back(cell);
|
||||||
|
std::push_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_board() {
|
void print_board() {
|
||||||
std::cout << board[0] << " ";
|
std::cout << board->values[0] << " ";
|
||||||
for (unsigned int i = 1; i < BOARD_SIZE; i++) {
|
for (unsigned int i = 1; i < BOARD_SIZE; i++) {
|
||||||
if (i % 3 == 0 && i % 9 != 0) {
|
if (i % 3 == 0 && i % 9 != 0) {
|
||||||
std::cout << "| ";
|
std::cout << "| ";
|
||||||
@ -84,7 +173,7 @@ public:
|
|||||||
if (i % 27 == 0) {
|
if (i % 27 == 0) {
|
||||||
std::cout << "------+-------+------" << std::endl;
|
std::cout << "------+-------+------" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << board[i] << " ";
|
std::cout << board->values[i] << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@ -98,7 +187,7 @@ int main() {
|
|||||||
Sudoku solver("006001849030000000000020006000400320400003000600008000010060003000005004029074005");
|
Sudoku solver("006001849030000000000020006000400320400003000600008000010060003000005004029074005");
|
||||||
//Sudoku solver("850002400720000009004000000000107002305000900040000000000080070017000000000036040");
|
//Sudoku solver("850002400720000009004000000000107002305000900040000000000080070017000000000036040");
|
||||||
solver.solve();
|
solver.solve();
|
||||||
solver.print_board();
|
//solver.print_board();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user