mirror of https://github.com/dnomd343/klotski.git
Dnomd343
7 months ago
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