diff --git a/src/core/main.cc b/src/core/main.cc index 7a7cf70..d26256d 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -34,124 +34,6 @@ using klotski::cases::GroupUnion; using klotski::cases::TYPE_ID_LIMIT; using klotski::codec::SHORT_CODE_LIMIT; -struct Pattern { - enum class Mirror { - Full, - V, - HV, - H, - Common, - }; - - Pattern(CommonCode s) : seed(s) {} - - Mirror mirror; - uint32_t size; - CommonCode seed; - uint32_t group_size; - std::array, 4> cases {}; -}; - -std::vector split_group(std::unordered_set &codes, CommonCode origin) { - std::vector group; - for (auto raw_code : Group::extend(origin.to_raw_code())) { - auto common_code = raw_code.to_common_code(); - codes.erase(common_code.unwrap()); - group.emplace_back(common_code); - } - std::sort(group.begin(), group.end()); - return group; -} - -std::vector split_patterns(const std::vector &common_codes) { - std::unordered_set codes; - for (auto code : common_codes) { - codes.emplace(code.unwrap()); - } - - std::vector patterns; - while (true) { - if (codes.empty()) { - break; - } - - auto code_a = CommonCode::unsafe_create(*std::min_element(codes.begin(), codes.end())); - auto code_b = code_a.to_horizontal_mirror(); - auto code_c = code_a.to_vertical_mirror(); - auto code_d = code_b.to_vertical_mirror(); - - auto group_a = split_group(codes, code_a); - auto group_b = split_group(codes, code_b); - auto group_c = split_group(codes, code_c); - auto group_d = split_group(codes, code_d); - - Pattern pattern {code_a}; - pattern.cases[0] = group_a; - pattern.size = group_a.size(); - pattern.group_size = group_a.size(); - - if (group_a.size() != group_b.size() || group_a.size() != group_c.size() || group_a.size() != group_d.size()) { - std::cout << "group size not match" << std::endl; - break; - } - - if (group_a == group_b && group_a == group_c && group_a == group_d) { - pattern.mirror = Pattern::Mirror::Full; - } else if (group_a != group_b && group_a != group_c && group_a != group_d && \ - group_b != group_c && group_b != group_d && group_c != group_d) { - pattern.mirror = Pattern::Mirror::Common; - pattern.cases[1] = group_b; - pattern.cases[2] = group_c; - pattern.cases[3] = group_d; - pattern.size *= 4; - } else if (group_a == group_b && group_c == group_d && group_a != group_c && group_b != group_d) { - pattern.mirror = Pattern::Mirror::V; - pattern.cases[1] = group_c; - pattern.size *= 2; - } else if (group_a == group_c && group_b == group_d && group_a != group_b && group_c != group_d) { - pattern.mirror = Pattern::Mirror::H; - pattern.cases[1] = group_b; - pattern.size *= 2; - } else if (group_a == group_d && group_b == group_c && group_a != group_b && group_c != group_d) { - pattern.mirror = Pattern::Mirror::HV; - pattern.cases[1] = group_b; - pattern.size *= 2; - } else { - std::cout << "unknown pattern" << std::endl; - break; - } - - patterns.emplace_back(pattern); - } - - std::sort(patterns.begin(), patterns.end(), [](const Pattern &lhs, const Pattern &rhs) { - if (lhs.size > rhs.size) { - return true; - } - if (lhs.size < rhs.size) { - return false; - } - - if ((int)lhs.mirror < (int)rhs.mirror) { - return true; - } - if ((int)lhs.mirror > (int)rhs.mirror) { - return false; - } - - if (lhs.seed < rhs.seed) { - return true; - } - if (lhs.seed > rhs.seed) { - return false; - } - - std::cout << "pattern compare error" << std::endl; - return false; - }); - return patterns; -} - int main() { // const auto start = clock(); @@ -171,28 +53,6 @@ int main() { // std::cout << GroupCases::fast_obtain(CommonCode::unsafe_create(0x1A9BF0C00)) << std::endl; // std::cout << GroupCases::fast_obtain(CommonCode::unsafe_create(0x4FEA13400)) << std::endl; - uint32_t flat_id = 0; - for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { - auto gu = GroupUnion::unsafe_create(type_id); - auto patterns = split_patterns(gu.cases().codes()); - if (gu.pattern_num() != patterns.size()) { - std::cout << "pattern number error" << std::endl; - } - - for (auto &pattern : patterns) { - if (pattern.group_size != klotski::cases::GROUP_PRO_SIZE[flat_id]) { - std::cout << "pattern group size error" << std::endl; - } - if ((int)pattern.mirror != klotski::cases::GROUP_PRO_TYPE[flat_id]) { - std::cout << "pattern mirror type error" << std::endl; - } - if (pattern.seed != klotski::cases::GROUP_PRO_SEED[flat_id]) { - std::cout << "pattern seed error" << std::endl; - } - ++flat_id; - } - } - // std::cout << gu.pattern_num() << std::endl; // std::cout << gu.group_num() << std::endl; // std::cout << gu.groups_pro().size() << std::endl; diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index 4a7c11f..04c6a34 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(test_helper helper/internal/concurrent.cc helper/internal/parallel.cc helper/internal/hash.cc + helper/internal/group.cc ) target_link_libraries(test_helper PRIVATE klotski_core bs::thread_pool md5sum::md5 xxHash::xxh3) @@ -30,6 +31,7 @@ set(KLSK_TEST_CASES_SRC cases/group_union.cc cases/group.cc cases/helper/group_impl.cc + cases/group_pro.cc ) add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC}) diff --git a/src/core_test/cases/group_pro.cc b/src/core_test/cases/group_pro.cc new file mode 100644 index 0000000..b196da4 --- /dev/null +++ b/src/core_test/cases/group_pro.cc @@ -0,0 +1,31 @@ +#include + +#include "helper/group.h" +#include "group/group.h" + +using klotski::cases::GroupPro; +using klotski::cases::GroupUnion; + +TEST(GroupPro, demo) { + + std::cout << helper::group_union_num() << std::endl; + + std::cout << helper::group_union_pattern_num(169) << std::endl; + std::cout << GroupUnion::unsafe_create(169).pattern_num() << std::endl; + + std::cout << helper::group_union_group_num(169) << std::endl; + std::cout << GroupUnion::unsafe_create(169).group_num() << std::endl; + + std::cout << (int)helper::pattern_mirror_type(169, 0) << std::endl; + std::cout << (int)GroupPro::unsafe_create(169, 0, 0).mirror_type() << std::endl; + + std::cout << std::format("{}", helper::pattern_toward_list(169, 0)) << std::endl; + std::cout << (int)GroupUnion::unsafe_create(169).groups_pro()[0].mirror_toward() << std::endl; + std::cout << (int)GroupUnion::unsafe_create(169).groups_pro()[1].mirror_toward() << std::endl; + + auto group_1 = GroupUnion::unsafe_create(169).groups_pro()[0]; + EXPECT_EQ(group_1.cases().codes(), helper::group_cases(169, 0, group_1.mirror_toward())); + auto group_2 = GroupUnion::unsafe_create(169).groups_pro()[1]; + EXPECT_EQ(group_2.cases().codes(), helper::group_cases(169, 0, group_2.mirror_toward())); + +} diff --git a/src/core_test/helper/group.h b/src/core_test/helper/group.h new file mode 100644 index 0000000..22247ce --- /dev/null +++ b/src/core_test/helper/group.h @@ -0,0 +1,25 @@ +#pragma once + +#include "common_code/common_code.h" + +namespace helper { + +using klotski::codec::CommonCode; + +/// Get the type_id upper limit. +uint32_t group_union_num(); // TODO: remove it + +/// Get cases contained in the specified type_id. +const std::vector& group_union_cases(uint32_t type_id); + +uint32_t group_union_pattern_num(uint32_t type_id); + +uint32_t group_union_group_num(uint32_t type_id); + +uint8_t pattern_mirror_type(uint32_t type_id, uint32_t pattern_id); + +std::vector pattern_toward_list(uint32_t type_id, uint32_t pattern_id); + +const std::vector& group_cases(uint32_t type_id, uint32_t pattern_id, uint8_t toward); + +} // namespace helper diff --git a/src/core_test/helper/internal/group.cc b/src/core_test/helper/internal/group.cc new file mode 100644 index 0000000..f15d20a --- /dev/null +++ b/src/core_test/helper/internal/group.cc @@ -0,0 +1,288 @@ +#include "helper/group.h" +#include "helper/block_num.h" + +#include "group/group.h" +#include "all_cases/all_cases.h" + +#include +#include + +#include + +using klotski::cases::AllCases; + +using klotski::codec::CommonCode; + +#define STATIC_DATA(name, impl) \ + static const auto& name() { \ + static auto data = [] {impl}(); \ + return data; \ + } + +/// Filter cases with different type_id from AllCases. +STATIC_DATA(group_union_data, { + std::vector> codes; + codes.resize(helper::block_nums().size()); + for (const auto code: AllCases::instance().fetch().codes()) { + const auto block_num = helper::cal_block_num(code.unwrap()); + codes[to_type_id(block_num)].emplace_back(code); + } + return codes; +}) + +uint32_t helper::group_union_num() { + return group_union_data().size(); +} + +const std::vector& helper::group_union_cases(const uint32_t type_id) { + if (type_id >= group_union_data().size()) { + std::abort(); + } + return group_union_data()[type_id]; +} + + + + + + + + + + +/// Extend ordered Group from the specified CommonCode seed. +static std::vector extend_cases(CommonCode seed) { + // TODO: using inner build process -> only allow calling klotski::core + 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; +} + +struct Pattern { + enum class Mirror { + Full = 0, + V = 1, + HV = 2, + H = 3, + Common = 4, + }; + + Pattern(CommonCode s) : seed(s) {} + + Mirror mirror; + uint32_t size; + CommonCode seed; + uint32_t group_size; + std::array, 4> cases {}; +}; + +static std::vector split_group(std::unordered_set &codes, CommonCode origin) { + std::vector group; + for (auto code : extend_cases(origin)) { + codes.erase(code.unwrap()); + group.emplace_back(code); + } + std::sort(group.begin(), group.end()); + return group; +} + +static std::vector split_patterns(const std::vector &common_codes) { + std::unordered_set codes; + for (auto code : common_codes) { + codes.emplace(code.unwrap()); + } + + std::vector patterns; + while (true) { + if (codes.empty()) { + break; + } + + auto code_a = CommonCode::unsafe_create(*std::min_element(codes.begin(), codes.end())); + auto code_b = code_a.to_horizontal_mirror(); + auto code_c = code_a.to_vertical_mirror(); + auto code_d = code_b.to_vertical_mirror(); + + auto group_a = split_group(codes, code_a); + auto group_b = split_group(codes, code_b); + auto group_c = split_group(codes, code_c); + auto group_d = split_group(codes, code_d); + + Pattern pattern {code_a}; + pattern.cases[0] = group_a; + pattern.size = group_a.size(); + pattern.group_size = group_a.size(); + + if (group_a.size() != group_b.size() || group_a.size() != group_c.size() || group_a.size() != group_d.size()) { + std::cout << "group size not match" << std::endl; + break; + } + + if (group_a == group_b && group_a == group_c && group_a == group_d) { + pattern.mirror = Pattern::Mirror::Full; + } else if (group_a != group_b && group_a != group_c && group_a != group_d && \ + group_b != group_c && group_b != group_d && group_c != group_d) { + pattern.mirror = Pattern::Mirror::Common; + pattern.cases[1] = group_b; + pattern.cases[2] = group_c; + pattern.cases[3] = group_d; + pattern.size *= 4; + } else if (group_a == group_b && group_c == group_d && group_a != group_c && group_b != group_d) { + pattern.mirror = Pattern::Mirror::V; + pattern.cases[1] = group_c; + pattern.size *= 2; + } else if (group_a == group_c && group_b == group_d && group_a != group_b && group_c != group_d) { + pattern.mirror = Pattern::Mirror::H; + pattern.cases[1] = group_b; + pattern.size *= 2; + } else if (group_a == group_d && group_b == group_c && group_a != group_b && group_c != group_d) { + pattern.mirror = Pattern::Mirror::HV; + pattern.cases[1] = group_b; + pattern.size *= 2; + } else { + std::cout << "unknown pattern" << std::endl; + break; + } + + patterns.emplace_back(pattern); + } + + std::sort(patterns.begin(), patterns.end(), [](const Pattern &lhs, const Pattern &rhs) { + if (lhs.size > rhs.size) { + return true; + } + if (lhs.size < rhs.size) { + return false; + } + + if ((int)lhs.mirror < (int)rhs.mirror) { + return true; + } + if ((int)lhs.mirror > (int)rhs.mirror) { + return false; + } + + if (lhs.seed < rhs.seed) { + return true; + } + if (lhs.seed > rhs.seed) { + return false; + } + + std::cout << "pattern compare error" << std::endl; + return false; + }); + return patterns; +} + +STATIC_DATA(pattern_data, { + std::vector> patterns; + for (const auto &group_union : group_union_data()) { + patterns.emplace_back(split_patterns(group_union)); + } + return patterns; +}) + +uint32_t helper::group_union_pattern_num(uint32_t type_id) { + if (type_id >= group_union_data().size()) { + std::abort(); + } + return pattern_data()[type_id].size(); +} + +uint32_t helper::group_union_group_num(uint32_t type_id) { + if (type_id >= group_union_data().size()) { + std::abort(); + } + + uint32_t group_num {0}; + for (const auto &pattern : pattern_data()[type_id]) { + switch (pattern.mirror) { + case Pattern::Mirror::Full: + ++group_num; + break; + case Pattern::Mirror::V: + case Pattern::Mirror::HV: + case Pattern::Mirror::H: + group_num += 2; + break; + case Pattern::Mirror::Common: + group_num += 4; + break; + } + } + return group_num; +} + +uint8_t helper::pattern_mirror_type(uint32_t type_id, uint32_t pattern_id) { + if (type_id >= group_union_data().size() || pattern_id >= pattern_data()[type_id].size()) { + std::abort(); + } + + const auto &pattern = pattern_data()[type_id][pattern_id]; + return (uint8_t)pattern.mirror; +} + +std::vector helper::pattern_toward_list(uint32_t type_id, uint32_t pattern_id) { + if (type_id >= group_union_data().size() || pattern_id >= pattern_data()[type_id].size()) { + std::abort(); + } + + const auto &pattern = pattern_data()[type_id][pattern_id]; + switch (pattern.mirror) { + case Pattern::Mirror::Full: + return {0}; + case Pattern::Mirror::V: + return {0, 2}; + case Pattern::Mirror::HV: + case Pattern::Mirror::H: + return {0, 1}; + case Pattern::Mirror::Common: + return {0, 1, 2, 3}; + } +} + +const std::vector &helper::group_cases(uint32_t type_id, uint32_t pattern_id, uint8_t toward) { + if (type_id >= group_union_data().size() || pattern_id >= pattern_data()[type_id].size()) { + std::abort(); + } + + const auto &pattern = pattern_data()[type_id][pattern_id]; + if (toward == 0) { + return pattern.cases[0]; + } else if (toward == 1) { + switch (pattern.mirror) { + case Pattern::Mirror::Full: + case Pattern::Mirror::V: + std::abort(); + case Pattern::Mirror::HV: + case Pattern::Mirror::H: + case Pattern::Mirror::Common: + return pattern.cases[1]; + } + } else if (toward == 2) { + switch (pattern.mirror) { + case Pattern::Mirror::Full: + case Pattern::Mirror::HV: + case Pattern::Mirror::H: + std::abort(); + case Pattern::Mirror::V: + return pattern.cases[1]; + case Pattern::Mirror::Common: + return pattern.cases[2]; + } + } else if (toward == 3) { + switch (pattern.mirror) { + case Pattern::Mirror::Full: + case Pattern::Mirror::V: + case Pattern::Mirror::HV: + case Pattern::Mirror::H: + std::abort(); + case Pattern::Mirror::Common: + return pattern.cases[3]; + } + } else { + std::abort(); + } +}