mirror of https://github.com/dnomd343/klotski.git
				
				
			
				 6 changed files with 186 additions and 95 deletions
			
			
		@ -0,0 +1,76 @@ | 
				
			|||||
 | 
					#include <ranges> | 
				
			||||
 | 
					#include <vector> | 
				
			||||
 | 
					#include <unordered_map> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "cases.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/// Build the sequence list of all block numbers.
 | 
				
			||||
 | 
					static std::vector<block_num_t> build_block_nums() { | 
				
			||||
 | 
					    std::vector<std::pair<uint32_t, block_num_t>> 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 flag = (n << 7) | ((n - n_1x2) << 4) | n_1x1; | 
				
			||||
 | 
					                nums.emplace_back(flag, block_num_t { | 
				
			||||
 | 
					                    .n_1x1 = n_1x1, | 
				
			||||
 | 
					                    .n_1x2 = n_1x2, | 
				
			||||
 | 
					                    .n_2x1 = n - n_1x2, | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    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<std::vector>(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					block_num_t cal_block_num(uint32_t range) { | 
				
			||||
 | 
					    block_num_t result {}; | 
				
			||||
 | 
					    for (range = range_reverse(range); 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; | 
				
			||||
 | 
					        default:; // space
 | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return result; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const std::vector<block_num_t>& 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]; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    std::abort(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					uint32_t to_type_id(const block_num_t block_num) { | 
				
			||||
 | 
					    static auto data = [] { | 
				
			||||
 | 
					        std::unordered_map<block_num_t, uint32_t> map; | 
				
			||||
 | 
					        for (auto i = 0; i < block_nums().size(); ++i) { | 
				
			||||
 | 
					            map.emplace(block_nums()[i], i); // TODO: using `std::views::enumerate`
 | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return map; | 
				
			||||
 | 
					    }(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    if (const auto match = data.find(block_num); match != data.end()) { | 
				
			||||
 | 
					        return match->second; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    std::abort(); | 
				
			||||
 | 
					} | 
				
			||||
@ -1,90 +0,0 @@ | 
				
			|||||
#include <iostream> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include "cases.h" | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include <ranges> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
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<block_num_t> 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<std::pair<uint32_t, block_num_t>> 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<std::vector>(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
uint32_t to_type_id(block_num_t block_num) { | 
					 | 
				
			||||
    auto f = []() { | 
					 | 
				
			||||
        auto ret = build_block_nums(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
        std::unordered_map<block_num_t, uint32_t> 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_num_t> block_nums() { | 
					 | 
				
			||||
    static auto data = build_block_nums(); | 
					 | 
				
			||||
    return data; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
@ -0,0 +1,67 @@ | 
				
			|||||
 | 
					#include <iostream> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "cases.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/// Filter cases with different type_id from AllCases.
 | 
				
			||||
 | 
					static std::vector<std::vector<CommonCode>> build_all_cases() { | 
				
			||||
 | 
					    std::vector<std::vector<CommonCode>> 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; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					std::vector<CommonCode> extend_cases(CommonCode seed) { | 
				
			||||
 | 
					    auto raw_codes = klotski::cases::Group::extend(seed.to_raw_code()); // TODO: using inner build process
 | 
				
			||||
 | 
					    std::vector<CommonCode> common_codes {raw_codes.begin(), raw_codes.end()}; | 
				
			||||
 | 
					    std::ranges::sort(common_codes.begin(), common_codes.end()); | 
				
			||||
 | 
					    return common_codes; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					std::vector<CommonCode> remove_sub(const std::vector<CommonCode> &all, const std::vector<CommonCode> &sub) { | 
				
			||||
 | 
					    std::vector<CommonCode> 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; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					static std::vector<std::vector<CommonCode>> split_groups(std::vector<CommonCode> codes) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    std::vector<std::vector<CommonCode>> groups; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    while (!codes.empty()) { | 
				
			||||
 | 
					        auto sub = extend_cases(codes[0]); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        groups.emplace_back(sub); | 
				
			||||
 | 
					        codes = remove_sub(codes, sub); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    std::ranges::stable_sort(groups.begin(), groups.end(), [](const std::vector<CommonCode> &g1, const std::vector<CommonCode> &g2) { | 
				
			||||
 | 
					        return g1.size() > g2.size(); | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    return groups; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const std::vector<CommonCode>& group_union_cases(const uint32_t type_id) { | 
				
			||||
 | 
					    static auto data = build_all_cases(); | 
				
			||||
 | 
					    if (type_id < data.size()) { | 
				
			||||
 | 
					        return data[type_id]; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    std::abort(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// TODO: maybe using multi-threads
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					std::vector<CommonCode> group_cases(uint32_t type_id, uint32_t group_id) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    auto groups = split_groups(group_union_cases(type_id)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    return groups[group_id]; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue