diff --git a/src/core_test/cases/group_union.cc b/src/core_test/cases/group_union.cc index cbcbafa..a3e2ba2 100644 --- a/src/core_test/cases/group_union.cc +++ b/src/core_test/cases/group_union.cc @@ -1,14 +1,10 @@ #include -#include #include #include #include -// TODO: only for debug -#include - #include "group/group.h" #include "helper/cases.h" #include "common_code/common_code.h" @@ -21,6 +17,7 @@ using klotski::cases::ALL_GROUP_NUM; TEST(GroupUnion, basic) { + // TODO: loop for all EXPECT_TRUE(GroupUnion::create(0).has_value()); EXPECT_EQ(GroupUnion::create(0).value().unwrap(), 0); EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value()); @@ -76,60 +73,18 @@ TEST(GroupUnion, size) { } TEST(GroupUnion, group_num) { - for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { EXPECT_EQ(GroupUnion::unsafe_create(type_id).group_num(), group_num(type_id)); - } } TEST(GroupUnion, cases) { for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) { auto cases = group_union_cases(type_id); - EXPECT_EQ(cases, klotski::cases::GroupUnion::unsafe_create(type_id).cases().codes()); + EXPECT_EQ(cases, GroupUnion::unsafe_create(type_id).cases().codes()); } } -TEST(GroupUnion, demo) { - - // for (auto i = 0; i < block_nums().size(); ++i) { - // 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; - // } - - std::vector> pp; - - pp.resize(block_nums().size()); - - for (uint64_t head = 0; head < 16; ++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)); - - pp[type_id].emplace_back(common_code); - - } - - } - - for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) { - - auto cases = klotski::cases::GroupUnion::unsafe_create(type_id).cases(); - - std::vector extend {}; - for (uint64_t head = 0; head < 16; ++head) { - for (auto range : cases[head]) { - extend.emplace_back(head << 32 | range); - } - } - - std::cout << "type_id " << type_id << " -> " << extend.size() << std::endl; - - EXPECT_EQ(extend, pp[type_id]); - } - +// TODO: test max_group_size -} +// TODO: verify from_raw_code / from_short_code / from_common_code diff --git a/src/core_test/cases/helper/block_num.cc b/src/core_test/cases/helper/block_num.cc index 277d8b4..d68d29d 100644 --- a/src/core_test/cases/helper/block_num.cc +++ b/src/core_test/cases/helper/block_num.cc @@ -24,13 +24,26 @@ static std::vector build_block_nums() { } } } - std::ranges::sort(nums.begin(), nums.end(), [](const auto lhs, const auto rhs) { return lhs.first < rhs.first; }); return std::views::all(nums) | std::views::values | std::ranges::to(); } +/// Build the mapping table from block_num to type_id. +static std::unordered_map build_type_id_map() { + std::unordered_map ids; + for (uint64_t i = 0; i < block_nums().size(); ++i) { + ids.emplace(block_nums()[i], i); // TODO: using `std::views::enumerate` + } + return ids; +} + +const std::vector& block_nums() { + static auto data = build_block_nums(); + return data; +} + block_num_t cal_block_num(uint32_t range) { block_num_t result {}; for (range = range_reverse(range); range; range >>= 2) { @@ -50,11 +63,6 @@ block_num_t cal_block_num(uint32_t range) { return result; } -const std::vector& block_nums() { - static auto data = build_block_nums(); - return data; -} - block_num_t to_block_num(const uint32_t type_id) { if (type_id < block_nums().size()) { return block_nums()[type_id]; @@ -63,14 +71,7 @@ block_num_t to_block_num(const uint32_t type_id) { } uint32_t to_type_id(const block_num_t block_num) { - static auto data = [] { - std::unordered_map map; - for (auto i = 0; i < block_nums().size(); ++i) { - map.emplace(block_nums()[i], i); // TODO: using `std::views::enumerate` - } - return map; - }(); - + static auto data = build_type_id_map(); if (const auto match = data.find(block_num); match != data.end()) { return match->second; } diff --git a/src/core_test/cases/helper/group_impl.cc b/src/core_test/cases/helper/group_impl.cc index b5cfbe3..d74cda1 100644 --- a/src/core_test/cases/helper/group_impl.cc +++ b/src/core_test/cases/helper/group_impl.cc @@ -1,99 +1,81 @@ -#include - #include "cases.h" -/// Filter cases with different type_id from AllCases. -static std::vector> build_all_cases() { - std::vector> codes; - for (auto code : AllCases::instance().fetch().codes()) { - const auto type_id = to_type_id(cal_block_num(code.unwrap())); - if (type_id >= codes.size()) { - codes.resize(type_id + 1); - } - codes[type_id].emplace_back(code); - } - return codes; -} +// TODO: multi-threads builder -std::vector extend_cases(CommonCode seed) { - auto raw_codes = klotski::cases::Group::extend(seed.to_raw_code()); // TODO: using inner build process +/// Extend ordered Group from the specified CommonCode seed. +static std::vector extend_cases(CommonCode seed) { + // TODO: using inner build process + auto raw_codes = klotski::cases::Group::extend(seed.to_raw_code()); std::vector common_codes {raw_codes.begin(), raw_codes.end()}; std::ranges::sort(common_codes.begin(), common_codes.end()); return common_codes; } -std::vector remove_sub(const std::vector &all, const std::vector &sub) { - std::vector tmp; - tmp.reserve(all.size() - sub.size()); - std::ranges::set_difference(all.begin(), all.end(), sub.begin(), sub.end(), std::back_inserter(tmp)); - return tmp; -} - +/// Split Groups from the specified ordered list of CommonCodes. static std::vector> split_groups(std::vector codes) { - std::vector> groups; - while (!codes.empty()) { - auto sub = extend_cases(codes[0]); + auto group = extend_cases(codes[0]); // sorted array + groups.emplace_back(group); - groups.emplace_back(sub); - codes = remove_sub(codes, sub); + std::vector remain; + remain.reserve(codes.size() - group.size()); + std::ranges::set_difference(codes.begin(), codes.end(), group.begin(), group.end(), std::back_inserter(remain)); + codes = remain; // for next loop } - - std::ranges::stable_sort(groups.begin(), groups.end(), [](const std::vector &g1, const std::vector &g2) { - return g1.size() > g2.size(); + std::ranges::stable_sort(groups.begin(), groups.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() > rhs.size(); // sort with group size }); - return groups; +} +/// Filter cases with different type_id from AllCases. +static const std::vector>& group_union_data() { + static auto data = [] { + std::vector> codes; + codes.resize(block_nums().size()); + for (auto code: AllCases::instance().fetch().codes()) { + codes[to_type_id(cal_block_num(code.unwrap()))].emplace_back(code); + } + return codes; + }(); + return data; } -// TODO: static data of `build_all_cases` +/// Construct all valid klotski Groups in different GroupUnion. +static const std::vector>>& group_data() { + static auto data = [] { + std::vector>> groups; + groups.reserve(group_union_num()); + for (uint32_t type_id = 0; type_id < group_union_num(); ++type_id) { + groups.emplace_back(split_groups(group_union_cases(type_id))); + } + return groups; + }(); + return data; +} uint32_t group_union_num() { - static auto data = build_all_cases(); - return data.size(); + return group_union_data().size(); } -const std::vector& group_union_cases(const uint32_t type_id) { - static auto data = build_all_cases(); - if (type_id < data.size()) { - return data[type_id]; +uint32_t group_num(uint32_t type_id) { + if (type_id < group_data().size()) { + return group_data()[type_id].size(); } std::abort(); } -// TODO: multi-threads builder - -static std::vector>> all_groups_builder() { - - std::vector>> data; - - for (uint32_t type_id = 0; type_id < group_union_num(); ++type_id) { - - data.emplace_back(split_groups(group_union_cases(type_id))); - - } - - return data; - -} - -uint32_t group_num(uint32_t type_id) { - static auto data = all_groups_builder(); - if (type_id < data.size()) { - return data[type_id].size(); +const std::vector& group_union_cases(const uint32_t type_id) { + if (type_id < group_union_data().size()) { + return group_union_data()[type_id]; } std::abort(); } const std::vector& group_cases(uint32_t type_id, uint32_t group_id) { - - static auto data = all_groups_builder(); - - if (type_id < data.size() && group_id < data[type_id].size()) { - return data[type_id][group_id]; + if (type_id < group_data().size() && group_id < group_data()[type_id].size()) { + return group_data()[type_id][group_id]; } - std::abort(); }