Browse Source

refactor: split out Range module

master
Dnomd343 1 month ago
parent
commit
9d77fc118e
  1. 3
      src/core/CMakeLists.txt
  2. 6
      src/core/all_cases/all_cases.h
  3. 54
      src/core/all_cases/internal/all_cases.cc
  4. 76
      src/core/all_cases/internal/basic_ranges.cc
  5. 11
      src/core/all_cases/internal/basic_ranges.inl
  6. 23
      src/core/benchmark/group.cc
  7. 4
      src/core/group/group.h
  8. 131
      src/core/group/internal/group.cc
  9. 40
      src/core/main.cc
  10. 57
      src/core/ranges/internal/head.cc
  11. 54
      src/core/ranges/internal/ranges.cc
  12. 77
      src/core/ranges/ranges.h
  13. 2
      src/core_test/cases/all_cases.cc
  14. 2
      src/core_test/cases/basic_ranges.cc
  15. 19
      src/core_test/group_tmp/group_extend.cc

3
src/core/CMakeLists.txt

@ -23,6 +23,9 @@ set(KLOTSKI_CORE_SRC
fast_cal/internal/fast_cal.cc
group/internal/group.cc
ranges/internal/ranges.cc
ranges/internal/head.cc
)
add_library(klotski_core STATIC ${KLOTSKI_CORE_SRC})

6
src/core/all_cases/all_cases.h

@ -45,13 +45,12 @@
#include <functional>
#include "utils/utility.h"
#include "ranges/ranges.h"
namespace klotski::cases {
// ------------------------------------------------------------------------------------- //
typedef uint32_t Range;
typedef std::vector<Range> Ranges;
typedef std::array<Ranges, 16> RangesUnion;
typedef std::function<void()> Notifier;
@ -95,9 +94,6 @@ private:
/// Search and sort all possible basic-ranges permutations.
static void build_ranges(Ranges &ranges);
/// Spawn all range permutations of specified conditions.
static void spawn_ranges(Ranges &ranges, int, int, int, int);
KLSK_INSTANCE(BasicRanges)
};

54
src/core/all_cases/internal/all_cases.cc

@ -2,7 +2,7 @@
#include "all_cases/all_cases.h"
namespace klotski::cases {
using klotski::cases::AllCases;
/// Calculate all possible klotski heads.
consteval static std::array<int, 12> case_heads() {
@ -15,58 +15,10 @@ consteval static std::array<int, 12> case_heads() {
return heads;
}
/// 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 = 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 AllCases::build_cases(const int head, Ranges &release) {
release.clear();
release.reserve(ALL_CASES_NUM[head]);
auto &basic_ranges = BasicRanges::instance().fetch();
for (uint32_t index = 0; index < basic_ranges.size(); ++index) {
auto offset = check_range(head, basic_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 += range_reverse(basic_ranges[index]) & ~(tmp - 1);
while (range_reverse(basic_ranges[++index]) < tmp); // located next range
--index;
continue;
}
release.emplace_back(range_reverse(basic_ranges[index])); // release valid case
}
BasicRanges::instance().fetch().with_head(head, release);
}
void AllCases::build() {
@ -122,5 +74,3 @@ void AllCases::build_parallel_async(Executor &&executor, Notifier &&callback) {
});
}
}
} // namespace klotski::cases

76
src/core/all_cases/internal/basic_ranges.cc

@ -1,29 +1,33 @@
#include <list>
#include <algorithm>
#include "ranges/ranges.h"
#include "all_cases/all_cases.h"
namespace klotski::cases {
using klotski::cases::Ranges;
using klotski::cases::BasicRanges;
typedef std::vector<Range>::iterator RangeIter;
typedef std::tuple<int, int, int, int> RangeType;
typedef std::tuple<int, int, int> RangeType;
typedef std::array<RangeType, 204> RangeTypeUnion;
/// Calculate all possible basic-ranges permutations.
/// Generate all possible basic-ranges permutations.
consteval static RangeTypeUnion range_types() {
RangeTypeUnion data;
for (int i = 0, n = 0; n <= 7; ++n) // 1x2 and 2x1 -> 0 ~ 7
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) // 2x1 -> 0 ~ n
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) // 1x1 -> 0 ~ (14 - 2n)
data[i++] = {16 - n * 2 - n_1x1, n - n_2x1, n_2x1, n_1x1};
for (int i = 0, n = 0; n <= 7; ++n) { // 1x2 + 2x1 -> 0 ~ 7
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) { // 2x1 -> 0 ~ n
// TODO: skip n == 7 && n_2x1 == 7
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // 1x1 -> 0 ~ (14 - 2n)
data[i++] = {n, n_2x1, n_1x1};
}
}
}
return data;
}
/// Combine two consecutive sorted arrays into one sorted arrays.
static void combine_sort(RangeIter begin, RangeIter mid, RangeIter end) noexcept {
Ranges tmp = {begin, mid}; // left array backup
auto p = tmp.begin();
for (;;) {
static void inplace_merge(Ranges::iterator begin, Ranges::iterator mid, const Ranges::iterator end) {
std::vector<uint32_t> tmp = {begin, mid}; // left array backup
for (auto p = tmp.begin();;) {
if (*p <= *mid) {
*(begin++) = *(p++); // stored in original span
if (p == tmp.end()) // left array is consumed
@ -38,58 +42,24 @@ static void combine_sort(RangeIter begin, RangeIter mid, RangeIter end) noexcept
}
}
void BasicRanges::spawn_ranges(Ranges &ranges, const int n1, const int n2, const int n3, const int n4) {
auto num = n1 + n2 + n3 + n4;
auto offset = (16 - num) << 1; // offset of low bits
std::vector<int> series;
series.reserve(num);
series.insert(series.end(), n1, 0b00);
series.insert(series.end(), n2, 0b01);
series.insert(series.end(), n3, 0b10);
series.insert(series.end(), n4, 0b11);
do { // full permutation traversal
uint32_t range = 0;
for (const auto x : series) // store every 2-bit
(range <<= 2) |= x;
ranges.emplace_back(range << offset);
} while (next_permutation(series.begin(), series.end()));
}
void BasicRanges::build_ranges(Ranges &ranges) {
ranges.clear();
ranges.reserve(BASIC_RANGES_NUM);
std::list<RangeIter> flags {ranges.begin()}; // mark ordered interval
for (auto &t : range_types()) {
spawn_ranges(ranges, std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
flags.emplace_back(ranges.end());
std::list flags { ranges.begin() };
for (auto [n, n_2x1, n_1x1] : range_types()) {
ranges.spawn_more(n, n_2x1, n_1x1);
flags.emplace_back(ranges.end()); // mark ordered interval
}
do {
decltype(flags.begin()) begin = flags.begin(), mid, end;
while (++(mid = begin) != flags.end() && ++(end = mid) != flags.end()) {
combine_sort(*begin, *mid, *end); // merge two ordered interval
inplace_merge(*begin, *mid, *end); // merge two ordered interval
flags.erase(mid);
begin = end;
}
} while (flags.size() > 2); // merge until only one interval remains
for (auto &x : ranges) {
x = range_reverse(x); // flip every 2-bit
}
}
void BasicRanges::build() {
if (available_) {
return; // reduce consumption of mutex
}
std::lock_guard guard(building_);
if (available_) {
return; // data is already available
}
build_ranges(get_ranges());
available_ = true;
ranges.reverse(); // flip every 2-bit
}
} // namespace klotski::cases

11
src/core/all_cases/internal/basic_ranges.inl

@ -14,6 +14,17 @@ inline const Ranges& BasicRanges::fetch() {
return get_ranges();
}
inline void BasicRanges::build() {
if (available_) {
return; // reduce consumption of mutex
}
std::lock_guard guard {building_};
if (!available_) {
build_ranges(get_ranges());
available_ = true;
}
}
inline bool BasicRanges::is_available() const {
return available_; // no mutex required in one-way state
}

23
src/core/benchmark/group.cc

@ -4,6 +4,9 @@
#define private public
#include "group/group.h"
#include <ranges/ranges.h>
#include "all_cases/all_cases.h"
#undef private
@ -13,7 +16,7 @@ using klotski::cases::AllCases;
static std::vector<uint64_t> all_common_codes() {
std::vector<uint64_t> codes;
for (uint64_t head = 0; head < 16; ++head) {
for (const auto range : AllCases::instance().fetch()[head]) {
for (const auto range : AllCases::instance().fetch()[head].ranges_) {
codes.emplace_back(head << 32 | range);
}
}
@ -151,17 +154,13 @@ static void SpawnRanges(benchmark::State &state) {
auto nums = target_nums();
for (auto _ : state) {
for (auto [n, n_2x1, n_1x1] : nums) {
// klotski::cases::spawn_ranges(n, n_2x1, n_1x1);
}
}
}
klotski::cases::Ranges kk {};
kk.reserve(7311921);
static void BasicRanges(benchmark::State &state) {
for (auto _ : state) {
klotski::cases::basic_ranges();
for (auto [n, n_2x1, n_1x1] : nums) {
kk.spawn_more(n, n_2x1, n_1x1);
}
}
}
@ -182,8 +181,6 @@ static void OriginBasicRanges(benchmark::State &state) {
// BENCHMARK(SpawnRanges)->Unit(benchmark::kMillisecond);
BENCHMARK(BasicRanges)->Unit(benchmark::kMillisecond);
// BENCHMARK(OriginBasicRanges)->Unit(benchmark::kMillisecond);
BENCHMARK(OriginBasicRanges)->Unit(benchmark::kMillisecond);
BENCHMARK_MAIN();

4
src/core/group/group.h

@ -80,10 +80,6 @@ uint32_t raw_code_to_type_id(uint64_t raw_code);
std::vector<uint64_t> group_extend_from_seed(uint64_t raw_code);
void spawn_ranges(std::vector<uint32_t> &ranges, int n, int n_2x1, int n_1x1);
std::vector<uint32_t> basic_ranges();
class Group;
// TODO: add constexpr

131
src/core/group/internal/group.cc

@ -61,134 +61,3 @@ std::vector<uint64_t> klotski::cases::group_extend_from_seed(uint64_t raw_code)
return results;
}
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) {
// auto n = n_01 + n_2x1;
// std::vector<uint32_t> ranges;
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;
}
}
consteval std::array<std::tuple<int, int, int>, 204> target_nums() {
std::array<std::tuple<int, int, int>, 204> results;
for (int i = 0, n = 0; n <= 7; ++n) {
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) {
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) {
results[i++] = {n, n_2x1, n_1x1};
}
}
}
return results;
}
using RangeIter = std::vector<uint32_t>::iterator;
static void combine_sort(RangeIter begin, RangeIter mid, RangeIter end) noexcept {
// std::inplace_merge(begin, mid, end);
// return;
// std::vector<uint32_t> results;
// results.resize(end - begin);
// std::merge(begin, mid, mid, end, results.begin());
// std::copy(results.begin(), results.end(), begin);
// return;
std::vector<uint32_t> tmp = {begin, mid}; // left array backup
auto p = tmp.begin();
for (;;) {
if (*p <= *mid) {
*(begin++) = *(p++); // stored in original span
if (p == tmp.end()) // left array is consumed
return;
continue;
}
*(begin++) = *(mid++); // stored in original span
if (mid == end) { // right array is consumed
std::copy(p, tmp.end(), begin); // left array remaining
return;
}
}
}
std::vector<uint32_t> klotski::cases::basic_ranges() {
std::vector<uint32_t> results;
results.reserve(7311921);
std::list<std::vector<uint32_t>::iterator> flags {results.begin()}; // mark ordered interval
for (auto [n, n_2x1, n_1x1] : target_nums()) {
spawn_ranges(results, n, n_2x1, n_1x1);
flags.emplace_back(results.end());
// auto sub_ranges = spawn_ranges(results, n, n_2x1, n_1x1);
// results.insert(results.end(), sub_ranges.begin(), sub_ranges.end());
}
// std::ranges::sort(results.begin(), results.end());
// std::ranges::stable_sort(results.begin(), results.end());
do {
decltype(flags.begin()) begin = flags.begin(), mid, end;
while (++(mid = begin) != flags.end() && ++(end = mid) != flags.end()) {
combine_sort(*begin, *mid, *end); // merge two ordered interval
flags.erase(mid);
begin = end;
}
} while (flags.size() > 2); // merge until only one interval remains
for (auto &x : results) {
x = range_reverse(x);
}
return results;
// std::vector<uint32_t> kk;
// kk.reserve(7311921);
// std::ranges::transform(results.begin(), results.end(), kk.begin(), range_reverse);
// return kk;
}

40
src/core/main.cc

@ -2,6 +2,7 @@
#include <thread>
#include <iostream>
#include <format>
#include <ranges/ranges.h>
#include "core/core.h"
#include "group/group.h"
@ -26,42 +27,13 @@ using klotski::codec::SHORT_CODE_LIMIT;
int main() {
const auto start = clock();
// klotski::cases::spawn_ranges(2, 1, 4, 4);
std::vector<uint32_t> r1 {1, 4, 5, 9, 0, 2, 3, 6, 7, 8};
auto begin = r1.begin();
auto mid = r1.begin() + 4;
auto end = r1.end();
std::vector<uint32_t> results;
results.resize(end - begin);
std::merge(begin, mid, mid, end, results.begin());
std::copy(results.begin(), results.end(), begin);
for (auto x : r1) {
std::cout << x << " ";
}
std::cout << std::endl;
// std::vector<int> series {1, 2, 3, 4};
// do { // full permutation traversal
//
// for (auto s : series) {
// std::cout << s << " ";
// }
// std::cout << std::endl;
// auto kk = klotski::cases::RangesDemo();
//
// } while (std::next_permutation(series.begin(), series.end()));
// std::array a{'a', 'b', 'c'};
// do {
// for (auto x : a) {
// std::cout << x;
// }
// std::cout << std::endl;
// for (auto x : kk) {
// std::cout << x << std::endl;
// }
// while (std::ranges::next_permutation(a).found);
// klotski::cases::spawn_ranges(2, 1, 4, 4);
// auto raw_code = RawCode::from_common_code(0x1A9BF0C00)->unwrap();
// auto ret = klotski::cases::group_extend_from_seed(raw_code);

57
src/core/ranges/internal/head.cc

@ -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
}
}

54
src/core/ranges/internal/ranges.cc

@ -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;
}
}

77
src/core/ranges/ranges.h

@ -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

2
src/core_test/cases/all_cases.cc

@ -39,7 +39,7 @@ protected:
EXPECT_EQ(all_cases_num, ALL_CASES_NUM_); // verify all cases global size
for (int head = 0; head < 16; ++head) {
EXPECT_EQ(hash::xxh3(all_cases[head]), ALL_CASES_XXH3[head]); // verify all cases checksum
EXPECT_EQ(hash::xxh3(all_cases[head].ranges_), ALL_CASES_XXH3[head]); // verify all cases checksum
}
}
};

2
src/core_test/cases/basic_ranges.cc

@ -24,7 +24,7 @@ protected:
static void Verify() {
const auto &basic_ranges = BasicRanges::instance().fetch();
EXPECT_EQ(basic_ranges.size(), BASIC_RANGES_NUM); // verify basic ranges size
EXPECT_EQ(hash::xxh3(basic_ranges), BASIC_RANGES_XXH3); // verify basic ranges checksum
EXPECT_EQ(hash::xxh3(basic_ranges.ranges_), BASIC_RANGES_XXH3); // verify basic ranges checksum
}
};

19
src/core_test/group_tmp/group_extend.cc

@ -1,6 +1,7 @@
#include <hash.h>
#include <group/group.h>
#include <gtest/gtest.h>
#include <ranges/ranges.h>
#include <__format/format_functions.h>
TEST(Group, group_extend) {
@ -45,32 +46,36 @@ TEST(Group, ranges) {
// auto hash_ret = hash::xxh3(ret.data(), ret.size() * 4);
// EXPECT_EQ(hash_ret, 0xF6F87606E4205EAF);
std::vector<uint32_t> ranges;
klotski::cases::Ranges kk {};
// std::vector<uint32_t> ranges;
for (auto [n, n_2x1, n_1x1] : target_nums()) {
kk.spawn_more(n, n_2x1, n_1x1);
// auto kk = klotski::cases::spawn_ranges(n, n_2x1, n_1x1);
// ranges.insert(ranges.end(), kk.begin(), kk.end());
}
EXPECT_EQ(ranges.size(), 7311921);
EXPECT_EQ(kk.ranges_.size(), 7311921);
auto hash_ret = hash::xxh3(ranges.data(), ranges.size() * 4);
auto hash_ret = hash::xxh3(kk.ranges_);
EXPECT_EQ(hash_ret, 0xA1E247B01D5A9545);
}
TEST(Group, basic_ranges) {
auto ret = klotski::cases::basic_ranges();
// auto ret = klotski::cases::basic_ranges();
// std::cout << ret.size() << std::endl;
EXPECT_EQ(ret.size(), 7311921);
// EXPECT_EQ(ret.size(), 7311921);
auto hash_ret = hash::xxh3(ret);
// auto hash_ret = hash::xxh3(ret);
// std::cout << std::format("{:X}", hash_ret) << std::endl;
// EXPECT_EQ(hash_ret, 0xA1E247B01D5A9545); // no sorted
// EXPECT_EQ(hash_ret, 0x00A926AB1121230D); // no reversed
EXPECT_EQ(hash_ret, 0x82B040060044E336);
// EXPECT_EQ(hash_ret, 0x82B040060044E336);
}

Loading…
Cancel
Save