diff --git a/src/core/group/group.h b/src/core/group/group.h index 18e3f4a..add70ef 100644 --- a/src/core/group/group.h +++ b/src/core/group/group.h @@ -27,7 +27,7 @@ /// (10-bit) | (n_1x2 + n_2x1) | (n_2x1) | (n_1x1) | /// | (0 ~ 7) | (0 ~ 7) | (0 ~ 14) | /// -/// flag => ((n_1x2 + n_2x1) << 7) | (n_2x1 << 3) | (n_1x1) +/// flag => ((n_1x2 + n_2x1) << 7) | (n_2x1 << 4) | (n_1x1) /// /// Using the table lookup method, the `type_id` of any case can be obtained /// within O(1), which is encapsulated in `GroupUnion`. @@ -75,6 +75,9 @@ namespace klotski::cases { constexpr uint32_t TYPE_ID_LIMIT = 203; constexpr uint32_t ALL_GROUP_NUM = 25422; +typedef std::vector RawCodes; +typedef std::vector CommonCodes; + class Group; // TODO: add constexpr @@ -142,9 +145,6 @@ private: // ------------------------------------------------------------------------------------- // }; -typedef std::vector RawCodes; -typedef std::vector CommonCodes; - class Group { public: Group() = delete; diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index 0128044..3f97da2 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -24,7 +24,7 @@ set(KLSK_TEST_CASES_SRC cases/basic_ranges.cc cases/all_cases.cc cases/group_union.cc - cases/helper/impl.cc + cases/helper/block_nums.cc ) add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC}) diff --git a/src/core_test/cases/group_union.cc b/src/core_test/cases/group_union.cc index 3d2744f..dee3b2e 100644 --- a/src/core_test/cases/group_union.cc +++ b/src/core_test/cases/group_union.cc @@ -1,151 +1,31 @@ -#include -#include -#include -#include - -#include -#include -#include - #include -struct block_num_t { - int n_1x1; - int n_1x2; - int n_2x1; -}; - -template <> -struct std::hash { - size_t operator()(const block_num_t val) const noexcept { - return std::hash()(val.n_1x1) ^ std::hash()(val.n_1x2) ^ std::hash()(val.n_2x1); - } -}; - -bool operator==(const block_num_t &lhs, const block_num_t &rhs) { - return lhs.n_1x1 == rhs.n_1x1 && lhs.n_1x2 == rhs.n_1x2 && lhs.n_2x1 == rhs.n_2x1; -} - -uint32_t cal_flag(const block_num_t &block_num) { - - return ((block_num.n_1x2 + block_num.n_2x1) << 7) | (block_num.n_2x1 << 3) | block_num.n_1x1; - -} - -std::vector block_nums() { - - std::vector> tmp; - - for (int n = 0; n <= 7; ++n) { - for (int n_1x2 = 0; n_1x2 <= n; ++n_1x2) { - - if (n == 7 && n_1x2 == 0) { - continue; - } - - for (int n_1x1 = 0; n_1x1 <= (20 - 4 - 2 - n * 2); ++n_1x1) { - - auto num = block_num_t { - .n_1x1 = n_1x1, - .n_1x2 = n_1x2, - .n_2x1 = n - n_1x2, - }; - - auto flag = cal_flag(num); - - tmp.emplace_back(flag, num); - - // std::cout << flag << std::endl; - - } - } - } - - std::sort(tmp.begin(), tmp.end(), [](const auto val1, const auto val2) { - return val1.first < val2.first; - }); - - // for (auto [x, _] : tmp) { - // std::cout << x << std::endl; - // } - - std::vector results; - std::ranges::transform(tmp, std::back_inserter(results), [](const auto val) { - return val.second; - }); - - // for (auto x : results) { - // std::cout << std::format("n_1x1 = {} / n_1x2 = {} / n_2x1 = {}", x.n_1x1, x.n_1x2, x.n_2x1) << std::endl; - // } - - return results; - -} - -block_num_t cal_block_num(const uint64_t common_code) noexcept { - block_num_t result {}; - auto range = klotski::range_reverse(static_cast(common_code)); - for (; range; range >>= 2) { - switch (range & 0b11) { - case 0b01: // 1x2 block - ++result.n_1x2; - continue; - case 0b10: // 2x1 block - ++result.n_2x1; - continue; - case 0b11: // 1x1 block - ++result.n_1x1; - continue; - } - } - return result; -} - -uint32_t to_type_id(block_num_t block_num) { - auto f = []() { - auto ret = block_nums(); - - std::unordered_map kk; - - for (auto i = 0; i < ret.size(); ++i) { - kk.emplace(ret[i], i); - } - - return kk; - - }; - - static auto data = f(); +#include +#include +#include - return data[block_num]; +// TODO: only for debug +#include -} +#include "group/group.h" +#include "helper/cases.h" +#include "common_code/common_code.h" TEST(GroupUnion, demo) { - // kk(); - - auto kk = cal_block_num(0x1A9BF0C00); - std::cout << to_type_id(kk) << std::endl; // for (auto i = 0; i < block_nums().size(); ++i) { - // // std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << std::endl; - // - // // std::cout << block_nums()[i].n_2x1 << std::endl; - // + // std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << ", "; + // std::cout << block_nums()[i].n_2x1 << ", "; // std::cout << block_nums()[i].n_1x1 << std::endl; // } - // - // return; std::vector> pp; pp.resize(block_nums().size()); - // std::cout << pp.size() << std::endl; - for (uint64_t head = 0; head < 16; ++head) { - for (auto range : klotski::cases::AllCases::instance().fetch()[head]) { + for (auto range : AllCases::instance().fetch()[head]) { uint64_t common_code = head << 32 | range; auto type_id = to_type_id(cal_block_num(common_code)); @@ -156,15 +36,9 @@ TEST(GroupUnion, demo) { } - // std::cout << pp[0].size() << std::endl; - - // std::cout << pp[169].size() << std::endl; - for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) { - // std::cout << "start cases cal" << std::endl; auto cases = klotski::cases::GroupUnion::unsafe_create(type_id).cases(); - // std::cout << "end cases cal" << std::endl; std::vector extend {}; for (uint64_t head = 0; head < 16; ++head) { @@ -174,7 +48,6 @@ TEST(GroupUnion, demo) { } std::cout << "type_id " << type_id << " -> " << extend.size() << std::endl; - // std::cout << std::endl; EXPECT_EQ(extend, pp[type_id]); } diff --git a/src/core_test/cases/helper/block_nums.cc b/src/core_test/cases/helper/block_nums.cc new file mode 100644 index 0000000..8b0ad5e --- /dev/null +++ b/src/core_test/cases/helper/block_nums.cc @@ -0,0 +1,90 @@ +#include + +#include "cases.h" + +#include + +block_num_t cal_block_num(uint32_t range) { + block_num_t result {}; + range = range_reverse(range); + for (; range; range >>= 2) { + switch (range & 0b11) { + case 0b01: // 1x2 block + ++result.n_1x2; + continue; + case 0b10: // 2x1 block + ++result.n_2x1; + continue; + case 0b11: // 1x1 block + ++result.n_1x1; + continue; + } + } + return result; +} + +static std::vector build_block_nums() { + auto cal_type_flag = [](const block_num_t &block_num) { + const auto n_x2x = block_num.n_1x2 + block_num.n_2x1; + return (n_x2x << 7) | (block_num.n_2x1 << 4) | block_num.n_1x1; + }; + + std::vector> nums; + for (int n = 0; n <= 7; ++n) { + for (int n_1x2 = 0; n_1x2 <= n; ++n_1x2) { + if (n == 7 && n_1x2 == 0) { + continue; + } + for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { + auto num = block_num_t { + .n_1x1 = n_1x1, + .n_1x2 = n_1x2, + .n_2x1 = n - n_1x2, + }; + nums.emplace_back(cal_type_flag(num), num); + } + } + } + + std::ranges::sort(nums.begin(), nums.end(), [](const auto val1, const auto val2) { + return val1.first < val2.first; + }); + + return std::views::all(nums) | std::views::transform([](const auto val) { + return val.second; + }) | std::ranges::to(); +} + +uint32_t to_type_id(block_num_t block_num) { + auto f = []() { + auto ret = build_block_nums(); + + std::unordered_map kk; + + for (auto i = 0; i < ret.size(); ++i) { + kk.emplace(ret[i], i); + } + + return kk; + + }; + + static auto data = f(); + + return data[block_num]; + + // TODO: handle invalid params +} + +block_num_t to_block_num(uint32_t type_id) { + static auto data = build_block_nums(); + + // TODO: handle invalid params + + return data[type_id]; +} + +std::vector block_nums() { + static auto data = build_block_nums(); + return data; +} diff --git a/src/core_test/cases/helper/cases.h b/src/core_test/cases/helper/cases.h index 8708f2a..74040a2 100644 --- a/src/core_test/cases/helper/cases.h +++ b/src/core_test/cases/helper/cases.h @@ -26,6 +26,8 @@ constexpr auto Heads = std::to_array({ 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14 }); +// ------------------------------------------------------------------------------------- // + /// Assert that Ranges are sorted and unique. #define EXPECT_SORTED_AND_UNIQUE(R) \ EXPECT_TRUE(std::ranges::is_sorted(R.begin(), R.end())); \ @@ -40,10 +42,35 @@ constexpr auto Heads = std::to_array({ for (const auto range : ranges) \ EXPECT_TRUE(CommonCode::check(static_cast(head) << 32 | range)) +// ------------------------------------------------------------------------------------- // + +/// The number of blocks in one klotski layout. struct block_num_t { int n_1x1; int n_1x2; int n_2x1; }; -block_num_t get_block_num(uint32_t range); +template <> +struct std::hash { + size_t operator()(const block_num_t val) const noexcept { + return (val.n_1x1 << 6) ^ (val.n_1x2 << 3) ^ val.n_2x1; + } +}; + +constexpr bool operator==(const block_num_t &lhs, const block_num_t &rhs) { + return lhs.n_1x1 == rhs.n_1x1 && lhs.n_1x2 == rhs.n_1x2 && lhs.n_2x1 == rhs.n_2x1; +} + +// ------------------------------------------------------------------------------------- // + +/// Calculate the block number from Range. +block_num_t cal_block_num(uint32_t range); + +/// Calculate type id value from the block number. +uint32_t to_type_id(block_num_t block_num); + +/// Calculate the block number value from type id. +block_num_t to_block_num(uint32_t type_id); + +std::vector block_nums(); diff --git a/src/core_test/cases/helper/impl.cc b/src/core_test/cases/helper/impl.cc deleted file mode 100644 index 34582ae..0000000 --- a/src/core_test/cases/helper/impl.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#include "cases.h" -#include "utils/utility.h" - -block_num_t get_block_num(uint32_t range) { - block_num_t result {}; - range = klotski::range_reverse(range); - for (; range; range >>= 2) { - switch (range & 0b11) { - case 0b01: // 1x2 block - ++result.n_1x2; - continue; - case 0b10: // 2x1 block - ++result.n_2x1; - continue; - case 0b11: // 1x1 block - ++result.n_1x1; - continue; - } - } - return result; -} diff --git a/src/core_test/cases/ranges.cc b/src/core_test/cases/ranges.cc index df72229..d6cda64 100644 --- a/src/core_test/cases/ranges.cc +++ b/src/core_test/cases/ranges.cc @@ -28,7 +28,7 @@ TEST(Ranges, spawn) { EXPECT_SORTED_AND_UNIQUE(ranges); for (const auto range : ranges) { - const auto [val_1x1, val_1x2, val_2x1] = get_block_num(range); + const auto [val_1x1, val_1x2, val_2x1] = cal_block_num(range); EXPECT_EQ(val_1x1, n_1x1); EXPECT_EQ(val_2x1, n_2x1); EXPECT_EQ(val_1x2 + val_2x1, n);