mirror of https://github.com/dnomd343/klotski.git
Dnomd343
7 months ago
15 changed files with 258 additions and 301 deletions
@ -0,0 +1,57 @@ |
|||
#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
|
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
#include <list> |
|||
#include <algorithm> |
|||
|
|||
#include "ranges/ranges.h" |
|||
#include "utils/utility.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
|
|||
|
|||
int n_00 = 16 - N * 2 - n_11; |
|||
int n_01 = N - n_10; |
|||
|
|||
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;
|
|||
|
|||
do { |
|||
uint32_t range = 0; |
|||
for (const auto x : series) // store every 2-bit
|
|||
(range <<= 2) |= x; |
|||
ranges.emplace_back(range << offset); |
|||
} 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);
|
|||
|
|||
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; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,77 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <cstdint> |
|||
|
|||
#include "utils/utility.h" |
|||
|
|||
namespace klotski::cases { |
|||
|
|||
// void spawn_ranges(std::vector<uint32_t> &ranges, int n, int n_2x1, int n_1x1);
|
|||
|
|||
// std::vector<uint32_t> basic_ranges();
|
|||
|
|||
// TODO: should we inherit on `std::vector<uint32_t>` ?
|
|||
class Ranges { |
|||
public: |
|||
void spawn_more(int n, int n_2x1, int n_1x1); |
|||
|
|||
using iterator = std::vector<uint32_t>::iterator; |
|||
using size_type = std::vector<uint32_t>::size_type; |
|||
using const_iterator = std::vector<uint32_t>::const_iterator; |
|||
|
|||
using value_type = std::vector<uint32_t>::value_type; |
|||
|
|||
using reference = std::vector<uint32_t>::reference; |
|||
|
|||
using const_reference = std::vector<uint32_t>::const_reference; |
|||
|
|||
iterator begin() { |
|||
return ranges_.begin(); |
|||
} |
|||
|
|||
iterator end() { |
|||
return ranges_.end(); |
|||
} |
|||
|
|||
[[nodiscard]] const_iterator begin() const { |
|||
return ranges_.begin(); |
|||
} |
|||
|
|||
[[nodiscard]] const_iterator end() const { |
|||
return ranges_.end(); |
|||
} |
|||
|
|||
void clear() { |
|||
ranges_.clear(); |
|||
} |
|||
|
|||
[[nodiscard]] size_type size() const { |
|||
return ranges_.size(); |
|||
} |
|||
|
|||
void reserve(const size_type cap) { |
|||
ranges_.reserve(cap); |
|||
} |
|||
|
|||
void with_head(int head, Ranges &release) const; |
|||
|
|||
void reverse() { |
|||
for (auto &x : ranges_) { |
|||
x = range_reverse(x); // flip every 2-bit
|
|||
} |
|||
} |
|||
|
|||
const_reference operator[](const size_type n) const { |
|||
return ranges_[n]; |
|||
} |
|||
|
|||
[[nodiscard]] const value_type* data() const { |
|||
return ranges_.data(); |
|||
} |
|||
|
|||
// private:
|
|||
std::vector<uint32_t> ranges_ {}; |
|||
}; |
|||
|
|||
} // namespace klotski::cases
|
Loading…
Reference in new issue