mirror of https://github.com/dnomd343/klotski.git
Dnomd343
6 months ago
13 changed files with 140 additions and 191 deletions
@ -0,0 +1,48 @@ |
|||
#include "utils/utility.h" |
|||
#include "ranges/ranges.h" |
|||
|
|||
using klotski::cases::Ranges; |
|||
|
|||
/// Check whether the combination of head and range is valid.
|
|||
static int check_range(const int head, uint32_t range) { |
|||
uint32_t flags = 0b110011 << head; // fill 2x2 block
|
|||
for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit
|
|||
const auto num = std::countr_one(flags); |
|||
addr += num; // next unfilled block
|
|||
flags >>= num; |
|||
switch (range & 0b11) { |
|||
case 0b00: // space
|
|||
case 0b11: // 1x1 block
|
|||
flags |= 0b1; |
|||
continue; |
|||
case 0b01: // 1x2 block
|
|||
if (flags & 0b10 || addr % 4 == 3) { // invalid case
|
|||
return offset; // broken offset
|
|||
} |
|||
flags |= 0b11; |
|||
continue; |
|||
case 0b10: // 2x1 block
|
|||
if (flags & 0b10000 || addr > 15) { // invalid case
|
|||
return offset; // broken offset
|
|||
} |
|||
flags |= 0b10001; |
|||
} |
|||
} |
|||
return 0; // pass check
|
|||
} |
|||
|
|||
void Ranges::derive(const int head, Ranges &output) const { |
|||
for (uint32_t index = 0; index < size(); ++index) { |
|||
if (const auto offset = check_range(head, (*this)[index])) { // invalid case
|
|||
uint32_t tmp = 1U << (32 - offset * 2); // distance to next possible range
|
|||
/// !! <- broken
|
|||
/// ( xx xx xx ) xx xx xx ... [reversed range]
|
|||
/// +1 00 00 00 ... (delta)
|
|||
tmp += range_reverse((*this)[index]) & ~(tmp - 1); |
|||
while (range_reverse((*this)[++index]) < tmp) {} // located next range
|
|||
--index; |
|||
continue; |
|||
} |
|||
output.emplace_back(range_reverse((*this)[index])); // release valid case
|
|||
} |
|||
} |
@ -1,57 +0,0 @@ |
|||
#include "utils/utility.h" |
|||
#include "ranges/ranges.h" |
|||
|
|||
/// Check whether the combination of head and range is valid.
|
|||
static int check_range(const int head, uint32_t range) noexcept { |
|||
constexpr uint32_t M_1x1 = 0b00000001; |
|||
constexpr uint32_t M_1x2 = 0b00000011; |
|||
constexpr uint32_t M_2x1 = 0b00010001; |
|||
constexpr uint32_t M_2x2 = 0b00110011; |
|||
|
|||
uint32_t flags = M_2x2 << head; // fill 2x2 block
|
|||
for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit
|
|||
const auto num = klotski::low_zero_num(~flags); |
|||
addr += num; // next unfilled block
|
|||
flags >>= num; |
|||
switch (range & 0b11) { |
|||
case 0b00: // space
|
|||
case 0b11: // 1x1 block
|
|||
flags |= M_1x1; |
|||
continue; |
|||
case 0b10: // 2x1 block
|
|||
if ((flags >> 4) & 0b1 || addr > 15) { // invalid case
|
|||
return offset; // broken offset
|
|||
} |
|||
flags |= M_2x1; |
|||
continue; |
|||
case 0b01: // 1x2 block
|
|||
if ((flags >> 1) & 0b1 || (addr & 0b11) == 0b11) { // invalid case
|
|||
return offset; // broken offset
|
|||
} |
|||
flags |= M_1x2; |
|||
continue; |
|||
} |
|||
} |
|||
return 0; // pass check
|
|||
} |
|||
|
|||
void klotski::cases::Ranges::with_head(const int head, Ranges &release) const { |
|||
// release.clear();
|
|||
// release.reserve(ALL_CASES_NUM[head]);
|
|||
// auto &basic_ranges = BasicRanges::instance().fetch();
|
|||
|
|||
for (uint32_t index = 0; index < ranges_.size(); ++index) { |
|||
auto offset = check_range(head, ranges_[index]); |
|||
if (offset) { // invalid case
|
|||
auto tmp = (uint32_t)0b1 << (32 - offset * 2); // distance to next possible range
|
|||
/// !! <- broken
|
|||
/// ( xx xx xx ) xx xx xx ... [reversed range]
|
|||
/// +1 00 00 00 ... (delta)
|
|||
tmp += klotski::range_reverse(ranges_[index]) & ~(tmp - 1); |
|||
while (klotski::range_reverse(ranges_[++index]) < tmp); // located next range
|
|||
--index; |
|||
continue; |
|||
} |
|||
release.ranges_.emplace_back(klotski::range_reverse(ranges_[index])); // release valid case
|
|||
} |
|||
} |
@ -1,54 +1,40 @@ |
|||
#include <list> |
|||
#include <algorithm> |
|||
|
|||
#include "ranges/ranges.h" |
|||
#include "utils/utility.h" |
|||
#include "ranges/ranges.h" |
|||
|
|||
template<int N> |
|||
static void demo(std::vector<uint32_t> &ranges, int n_10, int n_11) { |
|||
|
|||
constexpr auto num = 16 - N; |
|||
constexpr auto offset = (16 - num) << 1; // offset of low bits
|
|||
using klotski::cases::Ranges; |
|||
|
|||
int n_00 = 16 - N * 2 - n_11; |
|||
template<int N> |
|||
static void build_ranges(std::vector<uint32_t> &ranges, int n_10, int n_11) { |
|||
int n_01 = N - n_10; |
|||
int n_00 = 16 - N * 2 - n_11; |
|||
|
|||
std::array<int, num> series {}; |
|||
|
|||
auto kk = std::fill_n(series.begin() + n_00, n_01, 0b01); |
|||
auto pp = std::fill_n(kk, n_10, 0b10); |
|||
std::fill_n(pp, n_11, 0b11); |
|||
|
|||
// std::vector<uint32_t> ranges;
|
|||
std::array<int, 16 - N> series {}; |
|||
std::fill_n(series.begin() + n_00, n_01, 0b01); |
|||
std::fill_n(series.begin() + n_00 + n_01, n_10, 0b10); |
|||
std::fill_n(series.begin() + n_00 + n_01 + n_10, n_11, 0b11); |
|||
|
|||
do { |
|||
uint32_t range = 0; |
|||
for (const auto x : series) // store every 2-bit
|
|||
for (const auto x : series) { // store every 2-bit
|
|||
(range <<= 2) |= x; |
|||
ranges.emplace_back(range << offset); |
|||
} |
|||
ranges.emplace_back(range << (N * 2)); |
|||
} while (std::ranges::next_permutation(series).found); |
|||
|
|||
// return ranges;
|
|||
} |
|||
|
|||
// void klotski::cases::spawn_ranges(std::vector<uint32_t> &ranges, int n, int n_2x1, int n_1x1) {
|
|||
//
|
|||
//
|
|||
// }
|
|||
|
|||
void klotski::cases::Ranges::spawn_more(int n, int n_2x1, int n_1x1) { |
|||
// spawn_ranges(ranges_, n, n_2x1, n_1x1);
|
|||
|
|||
void Ranges::spawn(const int n, const int n_2x1, const int n_1x1) { |
|||
KLSK_ASSUME(n >= 0 && n_2x1 >= 0 && n_1x1 >= 0); |
|||
KLSK_ASSUME(n <= 7 && n_2x1 <= n && n_1x1 + n * 2 <= 14); |
|||
switch (n) { |
|||
case 0: return demo<0>(ranges_, n_2x1, n_1x1); |
|||
case 1: return demo<1>(ranges_, n_2x1, n_1x1); |
|||
case 2: return demo<2>(ranges_, n_2x1, n_1x1); |
|||
case 3: return demo<3>(ranges_, n_2x1, n_1x1); |
|||
case 4: return demo<4>(ranges_, n_2x1, n_1x1); |
|||
case 5: return demo<5>(ranges_, n_2x1, n_1x1); |
|||
case 6: return demo<6>(ranges_, n_2x1, n_1x1); |
|||
case 7: return demo<7>(ranges_, n_2x1, n_1x1); |
|||
default: return; |
|||
case 0: return build_ranges<0>(*this, n_2x1, n_1x1); |
|||
case 1: return build_ranges<1>(*this, n_2x1, n_1x1); |
|||
case 2: return build_ranges<2>(*this, n_2x1, n_1x1); |
|||
case 3: return build_ranges<3>(*this, n_2x1, n_1x1); |
|||
case 4: return build_ranges<4>(*this, n_2x1, n_1x1); |
|||
case 5: return build_ranges<5>(*this, n_2x1, n_1x1); |
|||
case 6: return build_ranges<6>(*this, n_2x1, n_1x1); |
|||
case 7: return build_ranges<7>(*this, n_2x1, n_1x1); |
|||
} |
|||
|
|||
} |
|||
|
Loading…
Reference in new issue