mirror of https://github.com/dnomd343/klotski.git
				
				
			
				 5 changed files with 346 additions and 140 deletions
			
			
		@ -0,0 +1,31 @@ | 
				
			|||||
 | 
					#include <gtest/gtest.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#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())); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
@ -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<CommonCode>& 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<uint8_t> pattern_toward_list(uint32_t type_id, uint32_t pattern_id); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const std::vector<CommonCode>& group_cases(uint32_t type_id, uint32_t pattern_id, uint8_t toward); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} // namespace helper
 | 
				
			||||
@ -0,0 +1,288 @@ | 
				
			|||||
 | 
					#include "helper/group.h" | 
				
			||||
 | 
					#include "helper/block_num.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "group/group.h" | 
				
			||||
 | 
					#include "all_cases/all_cases.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <iostream> | 
				
			||||
 | 
					#include <algorithm> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <unordered_set> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					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<std::vector<CommonCode>> 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<CommonCode>& 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<CommonCode> 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<CommonCode> 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<std::vector<CommonCode>, 4> cases {}; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					static std::vector<CommonCode> split_group(std::unordered_set<uint64_t> &codes, CommonCode origin) { | 
				
			||||
 | 
					    std::vector<CommonCode> 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<Pattern> split_patterns(const std::vector<CommonCode> &common_codes) { | 
				
			||||
 | 
					    std::unordered_set<uint64_t> codes; | 
				
			||||
 | 
					    for (auto code : common_codes) { | 
				
			||||
 | 
					        codes.emplace(code.unwrap()); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    std::vector<Pattern> 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<std::vector<Pattern>> 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<uint8_t> 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<CommonCode> &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(); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue