Compare commits
1 Commits
f145e9bc35
...
8d50ac79d0
Author | SHA1 | Date | |
---|---|---|---|
8d50ac79d0 |
38
main.cpp
38
main.cpp
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
typedef std::pair<std::vector<int>, std::list<int>> move;
|
typedef std::pair<std::vector<int>, std::list<int>> move;
|
||||||
|
|
||||||
|
// Wrapper for the game board with the field data and some utility functions.
|
||||||
class Board {
|
class Board {
|
||||||
public:
|
public:
|
||||||
int values[BOARD_SIZE];
|
int values[BOARD_SIZE];
|
||||||
@ -27,6 +28,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A cell in the game board -- used for the heap
|
||||||
class Cell {
|
class Cell {
|
||||||
public:
|
public:
|
||||||
Board *board;
|
Board *board;
|
||||||
@ -43,6 +45,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_possible_values() {
|
void update_possible_values() {
|
||||||
|
// Start off with all possible numbers
|
||||||
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
|
||||||
@ -70,13 +73,14 @@ class Sudoku {
|
|||||||
private:
|
private:
|
||||||
Board *board = new Board();
|
Board *board = new Board();
|
||||||
std::vector<Cell> heap;
|
std::vector<Cell> heap;
|
||||||
|
int value_count[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Sudoku(std::string s) {
|
Sudoku(std::string s) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
|
|
||||||
|
// Parse the input
|
||||||
for (unsigned int i = 0; i < s.length(); i++) {
|
for (unsigned int i = 0; i < s.length(); i++) {
|
||||||
board->values[i] = (int) (s[i] - '0');
|
board->values[i] = (int) (s[i] - '0');
|
||||||
|
|
||||||
@ -100,10 +104,12 @@ public:
|
|||||||
std::make_heap(heap.begin(), heap.end(), sort_cells);
|
std::make_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Turn this into a member of Cell as opterator<
|
||||||
static bool sort_cells(const Cell& a, const Cell& b) {
|
static bool sort_cells(const Cell& a, const Cell& b) {
|
||||||
return a.possible_values.size() < b.possible_values.size();
|
return a.possible_values.size() < b.possible_values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the possible values which a cell can take for every cell in the heap
|
||||||
void update_all_cells() {
|
void update_all_cells() {
|
||||||
for (Cell &cell : heap) {
|
for (Cell &cell : heap) {
|
||||||
cell.update_possible_values();
|
cell.update_possible_values();
|
||||||
@ -112,6 +118,7 @@ public:
|
|||||||
std::sort_heap(heap.begin(), heap.end(), sort_cells);
|
std::sort_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the best cell in the heap (the one with the most obvious choice)
|
||||||
Cell get_next_best_empty_cell() {
|
Cell get_next_best_empty_cell() {
|
||||||
std::pop_heap(heap.begin(), heap.end(), sort_cells);
|
std::pop_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
Cell c = heap.back();
|
Cell c = heap.back();
|
||||||
@ -120,12 +127,20 @@ public:
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrapper for solve_recurse, to be called from outside
|
||||||
void solve() {
|
void solve() {
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
solve_recurse();
|
solve_recurse();
|
||||||
|
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << " microseconds" << std::endl;
|
||||||
|
|
||||||
print_board();
|
print_board();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recurisvely solve the CSP
|
||||||
bool solve_recurse() {
|
bool solve_recurse() {
|
||||||
// If there are no more possible moves in the heap...
|
// If there are no more possible moves in the heap...
|
||||||
if (heap.empty()) {
|
if (heap.empty()) {
|
||||||
@ -139,28 +154,37 @@ public:
|
|||||||
// If not, we're done!
|
// If not, we're done!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (heap.empty()) return true;
|
|
||||||
|
|
||||||
Cell cell = get_next_best_empty_cell();
|
Cell cell = get_next_best_empty_cell();
|
||||||
|
|
||||||
for (int value : cell.possible_values) {
|
// Sort the possible values by how often that value has been used in the board.
|
||||||
board->set(cell.x, cell.y, value);
|
// This is a simple heuristic based on the thought that a value which hasn't been used often is likely the safer choice.
|
||||||
update_all_cells();
|
cell.possible_values.sort([&](const int& a, const int& b) {return value_count[a - 1] > value_count[b - 1];});
|
||||||
|
|
||||||
|
// Iterate over all possible values this cell can take
|
||||||
|
for (int value : cell.possible_values) {
|
||||||
|
// Apply this value
|
||||||
|
board->set(cell.x, cell.y, value);
|
||||||
|
update_all_cells(); // TODO: We'd only need to re-rate the neighbours
|
||||||
|
|
||||||
|
// Recurse; if we find a solution, we're done and can return true
|
||||||
if (solve_recurse()) {
|
if (solve_recurse()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seems like this was a dead end -- reset this move
|
||||||
board->set(cell.x, cell.y, 0);
|
board->set(cell.x, cell.y, 0);
|
||||||
update_all_cells();
|
update_all_cells(); // TODO: We could save and reuse the rating from before
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put the cell back into the heap -- it couldn't be used for any valid solution, so we'll need it somewhere else later
|
||||||
heap.push_back(cell);
|
heap.push_back(cell);
|
||||||
std::push_heap(heap.begin(), heap.end(), sort_cells);
|
std::push_heap(heap.begin(), heap.end(), sort_cells);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print the game board in a nice format
|
||||||
void print_board() {
|
void print_board() {
|
||||||
std::cout << board->values[0] << " ";
|
std::cout << board->values[0] << " ";
|
||||||
for (unsigned int i = 1; i < BOARD_SIZE; i++) {
|
for (unsigned int i = 1; i < BOARD_SIZE; i++) {
|
||||||
@ -188,6 +212,6 @@ int main() {
|
|||||||
//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