diff --git a/Makefile b/Makefile index bf56948..a1ef1cb 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -Wall +CXXFLAGS = -Wall -O3 q: main.o $(CXX) $(CXXFLAGS) -o q main.o diff --git a/main.cpp b/main.cpp index 8346c22..de59cb6 100644 --- a/main.cpp +++ b/main.cpp @@ -15,15 +15,15 @@ class Board { public: 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; } - int get(int x, int y) { + inline int get(int x, int 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; } }; @@ -39,33 +39,31 @@ public: 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; update_possible_values(); } void update_possible_values() { // Start off with all possible numbers - std::list 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 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 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 for (int dy = 0; dy < 3; dy++) { 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) { @@ -117,6 +115,25 @@ public: 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) Cell get_next_best_empty_cell() { std::pop_heap(heap.begin(), heap.end()); @@ -164,7 +181,7 @@ public: 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 + update_affected_cells(cell.x, cell.y); // Recurse; if we find a solution, we're done and can return true if (solve_recurse()) { @@ -173,7 +190,7 @@ public: // Seems like this was a dead end -- reset this move 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