doasku

Sudoku solver
git clone git://git.dimitrijedobrota.com/doasku.git
Log | Files | Refs | README | LICENSE

commit bcd759724a4653673d65a047a8c56b1d3b026a7f
parent a4a5210429ab211058108e0850c8f284d7a375bc
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu,  4 Apr 2024 14:37:38 +0200

Extract reference logic and general streamlining

Diffstat:
Mmain.cpp | 102++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 60 insertions(+), 42 deletions(-)

diff --git a/main.cpp b/main.cpp @@ -12,6 +12,9 @@ static constexpr const std::int64_t mask_field = (1 << 9) - 1; static constexpr const std::int64_t mask_value = 0x201008040201; +using change_t = std::tuple<uint8_t, uint8_t>; +using changes_t = std::vector<change_t>; + class row_col_t; class row_col_rt; @@ -48,6 +51,35 @@ row_col_rt::row_col_rt(row_col_t rc) : row(2 - rc.col), col(rc.row) {} uint8_t field(row_col_t rc) { return 3 * rc.row + rc.col; } +class Ref { + public: + uint16_t get(row_col_t rc) const { return ref[::field(rc)]; } + + void clear(uint8_t value) { ref[value] = 0; } + + void remove(row_col_t rc, uint8_t value) { ref[value] &= ~(1 << ::field(rc)); } + void remove(row_col_t rc) { + for (uint8_t i = 0; i < 9; i++) { + ref[i] &= ~(1 << ::field(rc)); + } + } + + changes_t lone() const { + changes_t res; + + for (uint8_t i = 0; i < 9; i++) { + if (std::popcount(ref[i]) != 1) continue; + res.emplace_back(std::countr_zero(ref[i]), i); + } + + return res; + } + + private: + uint16_t ref[9] = {mask_field, mask_field, mask_field, mask_field, mask_field, + mask_field, mask_field, mask_field, mask_field}; +}; + class Row { public: Row(uint64_t value = 0) : val(value) {} @@ -89,7 +121,7 @@ class Subgrid { uint64_t get(row_col_t rc) const { return rows[rc.row].get(rc.col); } uint64_t get(row_col_rt rc) const { return rows[rc.row].get(rc.col + 3); } - uint16_t get_ref(row_col_t rc) const { return ref[::field(rc)]; } + uint16_t get_ref(row_col_t rc) const { return ref.get(rc); } uint8_t value(row_col_t rc) const { if (!is_finished(rc)) return 0; @@ -109,12 +141,10 @@ class Subgrid { set(row_col_t(field), value); set(row_col_rt(field), value); - for (int i = 0; i < 9; i++) { - ref[i] &= ~(1 << field); - } + ref.remove(field); + ref.clear(value); finished |= 1 << field; - ref[value] = 0; } void clear_row(uint8_t row, uint8_t value) { @@ -122,7 +152,7 @@ class Subgrid { for (uint8_t i = 0; i < 3; i++) { const row_col_t rc = {row, i}; - ref[value] &= ~(1 << ::field(rc)); + ref.remove(rc, value); clear(row_col_rt(rc), value); clear(rc, value); } @@ -133,30 +163,23 @@ class Subgrid { for (uint8_t i = 0; i < 3; i++) { const row_col_t rc = {i, col}; - ref[value] &= ~(1 << ::field(rc)); + ref.remove(rc, value); clear(row_col_rt(rc), value); clear(rc, value); } } - using change_t = std::tuple<uint8_t, uint8_t>; - using changes_t = std::vector<change_t>; - changes_t check_lone() { if (is_finished()) return {}; - changes_t res; + changes_t res = ref.lone(); + for (int field = 0, mask = 1; field < 9; field++, mask <<= 1) { if (finished & mask) continue; if (std::popcount(get(field)) != 1) continue; res.emplace_back(field, std::countr_zero(get(field))); } - for (int i = 0; i < 9; i++) { - if (std::popcount(ref[i]) != 1) continue; - res.emplace_back(std::countr_zero(ref[i]), i); - } - return res; } @@ -209,7 +232,6 @@ class Subgrid { static uint8_t count[512]; static uint64_t value[9]; - std::memset(count, 0x00, sizeof(count)); for (uint8_t i = 0; i < 3; i++) { for (uint8_t j = 0; j < 3; j++) { const auto field = ::field({i, j}); @@ -230,28 +252,25 @@ class Subgrid { // if current is not part of a tuple continue if (popcnt <= 1 || popcnt != found) continue; - for (uint8_t k = 0; k < 3; k++) { - for (uint8_t l = 0; l < 3; l++) { - const row_col_t rc = {k, l}; - const uint8_t nfield = ::field(rc); + for (uint8_t nfield = 0; nfield < 9; nfield++) { + const row_col_t rc(nfield); - // skip part of the tuple - if (value[field] == value[nfield]) continue; + // skip part of the tuple + if (value[field] == value[nfield]) continue; - // are we going to clear any bits? - if (value[field] & value[nfield]) { - mask(row_col_rt(rc), value[field]); - mask(rc, value[field]); + // are we going to clear any bits? + if (value[field] & value[nfield]) { + mask(row_col_rt(rc), value[field]); + mask(rc, value[field]); - res = true; + res = true; - // remove cleared from reference - uint64_t tvalue = value[field]; - while (tvalue) { - uint16_t idx = std::countr_zero(tvalue); - ref[idx] &= ~(1 << nfield); - tvalue ^= 1ull << idx; - } + // remove cleared from reference + uint64_t tvalue = value[field]; + while (tvalue) { + uint16_t idx = std::countr_zero(tvalue); + ref.remove(nfield, idx); + tvalue ^= 1ull << idx; } } } @@ -299,8 +318,7 @@ class Subgrid { void mask(row_col_rt rcr, uint8_t value) { rows[rcr.row].mask(rcr.col + 3, value); } Row rows[3] = {~0, ~0, ~0}; - uint16_t ref[9] = {mask_field, mask_field, mask_field, mask_field, mask_field, - mask_field, mask_field, mask_field, mask_field}; + Ref ref; uint16_t finished = 0; uint64_t shot = 0; @@ -310,8 +328,8 @@ class Grid { public: Grid(const std::string &s) { int idx = 0; - for (int i = 0; i < 9; i++) { - for (int j = 0; j < 9; j++, idx++) { + for (uint8_t i = 0; i < 9; i++) { + for (uint8_t j = 0; j < 9; j++, idx++) { if (s[idx] == '0') continue; set((i / 3) * 3 + j / 3, (i % 3) * 3 + j % 3, s[idx] - '1'); } @@ -340,7 +358,7 @@ class Grid { while (iter--) { uint8_t changes = 0; - for (int i = 0; i < 9; i++) { + for (uint8_t i = 0; i < 9; i++) { const auto lones = subgrids[i].check_lone(); for (const auto [field, val] : lones) { set(i, field, val); @@ -348,7 +366,7 @@ class Grid { } } - for (int i = 0; i < 9; i++) { + for (uint8_t i = 0; i < 9; i++) { changes += subgrids[i].check_force(); } @@ -375,7 +393,7 @@ class Grid { if (changes) iter++; } - for (int i = 0; i < 9; i++) { + for (uint8_t i = 0; i < 9; i++) { if (!subgrids[i].is_finished()) return false; } return true;