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:
M | main.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;