Compare commits

...

2 Commits

Author SHA1 Message Date
cc5210a71f Update only cells affected by change
+ some more minor optimizations
2020-12-02 16:17:00 +01:00
b5dfd9743a Move sort_cells to operator< of Cell class 2020-12-02 15:57:43 +01:00
2 changed files with 37 additions and 21 deletions

View File

@ -1,5 +1,5 @@
CXX = g++ CXX = g++
CXXFLAGS = -Wall CXXFLAGS = -Wall -O3
q: main.o q: main.o
$(CXX) $(CXXFLAGS) -o q main.o $(CXX) $(CXXFLAGS) -o q main.o

View File

@ -15,15 +15,15 @@ class Board {
public: public:
int values[BOARD_SIZE]; int values[BOARD_SIZE];
int coordinates_to_id(int x, int y) { inline int coordinates_to_id(int x, int y) {
return y * BOARD_DIMENSION + x; return y * BOARD_DIMENSION + x;
} }
int get(int x, int y) { inline int get(int x, int y) {
return values[coordinates_to_id(x, y)]; return values[coordinates_to_id(x, y)];
} }
void set(int x, int y, int value) { inline void set(int x, int y, int value) {
values[coordinates_to_id(x, y)] = value; values[coordinates_to_id(x, y)] = value;
} }
}; };
@ -39,33 +39,35 @@ public:
Cell(Board *board, int x, int y) : board(board), x(x), y(y), value(board->get(x, y)) {} Cell(Board *board, int x, int y) : board(board), x(x), y(y), value(board->get(x, y)) {}
void set_value(int new_value) { inline void set_value(int new_value) {
value = new_value; value = new_value;
update_possible_values(); update_possible_values();
} }
void update_possible_values() { void update_possible_values() {
// Start off with all possible numbers // Start off with all possible numbers
std::list<int> possibilities{1, 2, 3, 4, 5, 6, 7, 8 ,9}; possible_values = {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(board->get(dx, y)); possible_values.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(board->get(x, dy)); possible_values.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(board->get((x - x % 3) + dx, (y - y % 3) + dy)); possible_values.remove(board->get((x - x % 3) + dx, (y - y % 3) + dy));
} }
} }
}
possible_values = possibilities; bool operator<(const Cell &other) {
return possible_values.size() < other.possible_values.size();
} }
}; };
@ -101,12 +103,7 @@ public:
cell.update_possible_values(); cell.update_possible_values();
} }
std::make_heap(heap.begin(), heap.end(), sort_cells); std::make_heap(heap.begin(), heap.end());
}
// TODO: Turn this into a member of Cell as opterator<
static bool sort_cells(const Cell& a, const Cell& b) {
return a.possible_values.size() < b.possible_values.size();
} }
// Update the possible values which a cell can take for every cell in the heap // Update the possible values which a cell can take for every cell in the heap
@ -115,12 +112,31 @@ public:
cell.update_possible_values(); cell.update_possible_values();
} }
std::sort_heap(heap.begin(), heap.end(), sort_cells); std::sort_heap(heap.begin(), heap.end());
}
// Update the possible values of all cells in the heap which are affected by
// the value of the cell at the given position
void update_affected_cells(int x, int y) {
int x_quadrant = x - x % 3;
int y_quadrant = y - y % 3;
for (Cell &cell : heap) {
if (cell.x == x // Column
|| cell.y == y // Row
|| (cell.x - cell.x % 3 == x_quadrant // Quadrant
&& cell.y - cell.y % 3 == y_quadrant)) {
cell.update_possible_values();
}
}
std::sort_heap(heap.begin(), heap.end());
} }
// Returns the best cell in the heap (the one with the most obvious choice) // 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());
Cell c = heap.back(); Cell c = heap.back();
heap.pop_back(); heap.pop_back();
@ -165,7 +181,7 @@ public:
for (int value : cell.possible_values) { for (int value : cell.possible_values) {
// Apply this value // Apply this value
board->set(cell.x, cell.y, value); board->set(cell.x, cell.y, value);
update_all_cells(); // TODO: We'd only need to re-rate the neighbours update_affected_cells(cell.x, cell.y);
// Recurse; if we find a solution, we're done and can return true // Recurse; if we find a solution, we're done and can return true
if (solve_recurse()) { if (solve_recurse()) {
@ -174,12 +190,12 @@ public:
// Seems like this was a dead end -- reset this move // 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(); // TODO: We could save and reuse the rating from before update_affected_cells(cell.x, cell.y);
} }
// Put the cell back into the heap -- it couldn't be used for any valid solution, so we'll need it somewhere else later // 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());
return false; return false;
} }