mirror of https://github.com/dnomd343/klotski.git
Dnomd343
7 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 <algorithm> |
||||
|
|
||||
#include "ranges/ranges.h" |
|
||||
#include "utils/utility.h" |
#include "utils/utility.h" |
||||
|
#include "ranges/ranges.h" |
||||
|
|
||||
template<int N> |
using klotski::cases::Ranges; |
||||
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
|
|
||||
|
|
||||
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_01 = N - n_10; |
||||
|
int n_00 = 16 - N * 2 - n_11; |
||||
|
|
||||
std::array<int, num> series {}; |
std::array<int, 16 - N> series {}; |
||||
|
std::fill_n(series.begin() + n_00, n_01, 0b01); |
||||
auto kk = std::fill_n(series.begin() + n_00, n_01, 0b01); |
std::fill_n(series.begin() + n_00 + n_01, n_10, 0b10); |
||||
auto pp = std::fill_n(kk, n_10, 0b10); |
std::fill_n(series.begin() + n_00 + n_01 + n_10, n_11, 0b11); |
||||
std::fill_n(pp, n_11, 0b11); |
|
||||
|
|
||||
// std::vector<uint32_t> ranges;
|
|
||||
|
|
||||
do { |
do { |
||||
uint32_t range = 0; |
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; |
(range <<= 2) |= x; |
||||
ranges.emplace_back(range << offset); |
} |
||||
|
ranges.emplace_back(range << (N * 2)); |
||||
} while (std::ranges::next_permutation(series).found); |
} 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 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); |
||||
// }
|
|
||||
|
|
||||
void klotski::cases::Ranges::spawn_more(int n, int n_2x1, int n_1x1) { |
|
||||
// spawn_ranges(ranges_, n, n_2x1, n_1x1);
|
|
||||
|
|
||||
switch (n) { |
switch (n) { |
||||
case 0: return demo<0>(ranges_, n_2x1, n_1x1); |
case 0: return build_ranges<0>(*this, n_2x1, n_1x1); |
||||
case 1: return demo<1>(ranges_, n_2x1, n_1x1); |
case 1: return build_ranges<1>(*this, n_2x1, n_1x1); |
||||
case 2: return demo<2>(ranges_, n_2x1, n_1x1); |
case 2: return build_ranges<2>(*this, n_2x1, n_1x1); |
||||
case 3: return demo<3>(ranges_, n_2x1, n_1x1); |
case 3: return build_ranges<3>(*this, n_2x1, n_1x1); |
||||
case 4: return demo<4>(ranges_, n_2x1, n_1x1); |
case 4: return build_ranges<4>(*this, n_2x1, n_1x1); |
||||
case 5: return demo<5>(ranges_, n_2x1, n_1x1); |
case 5: return build_ranges<5>(*this, n_2x1, n_1x1); |
||||
case 6: return demo<6>(ranges_, n_2x1, n_1x1); |
case 6: return build_ranges<6>(*this, n_2x1, n_1x1); |
||||
case 7: return demo<7>(ranges_, n_2x1, n_1x1); |
case 7: return build_ranges<7>(*this, n_2x1, n_1x1); |
||||
default: return; |
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
Loading…
Reference in new issue