mirror of https://github.com/dnomd343/klotski.git
Dnomd343
2 years ago
10 changed files with 203 additions and 211 deletions
@ -1,3 +1,3 @@ |
|||
cmake_minimum_required(VERSION 3.0) |
|||
|
|||
add_library(group OBJECT group.cc block_num.cc) |
|||
add_library(group OBJECT group.cc build_cases.cc block_num.cc) |
|||
|
@ -0,0 +1,109 @@ |
|||
#include <queue> |
|||
#include "core.h" |
|||
#include "group.h" |
|||
#include "common.h" |
|||
#include "type_id.h" |
|||
#include "common_code.h" |
|||
#include "absl/container/flat_hash_map.h" |
|||
|
|||
namespace klotski { |
|||
|
|||
using Common::check_range; |
|||
using Common::range_reverse; |
|||
|
|||
std::vector<CommonCode> Group::all_cases(uint32_t type_id) { |
|||
auto tmp = block_num(type_id); |
|||
std::vector<uint32_t> ranges; // basic ranges of type_id
|
|||
BasicRanges::generate(ranges, { // generate target ranges
|
|||
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
|
|||
.n2 = tmp.n_1x2, /// 1x2 -> 01
|
|||
.n3 = tmp.n_2x1, /// 2x1 -> 10
|
|||
.n4 = tmp.n_1x1, /// 1x1 -> 11
|
|||
}); |
|||
for (auto &range : ranges) { |
|||
range = range_reverse(range); // basic ranges reversed
|
|||
} |
|||
|
|||
std::vector<CommonCode> all_cases; |
|||
all_cases.reserve(TYPE_ID_SIZE[type_id]); |
|||
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
|
|||
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
|
|||
if ((head & 0b11) == 0b11) { |
|||
++head; // skip invalid address
|
|||
} |
|||
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
|
|||
for (auto &&range : ranges) { |
|||
if (!check_range(head, range)) { // case valid
|
|||
all_cases.emplace_back(CommonCode::unsafe_create( |
|||
head << 32 | range_reverse(range) // release valid cases
|
|||
)); |
|||
} |
|||
} |
|||
} |
|||
return all_cases; |
|||
} |
|||
|
|||
std::vector<RawCode> Group::group_cases(const RawCode &seed) { |
|||
std::queue<uint64_t> cache; |
|||
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|||
cases.reserve(max_group_size(seed)); |
|||
cases.emplace(seed.unwrap(), 0); // without mask
|
|||
cache.emplace(seed.unwrap()); |
|||
|
|||
auto core = Core( |
|||
[&cache, &cases](auto &&code, auto &&mask) { // callback function
|
|||
auto current = cases.find(code); |
|||
if (current != cases.end()) { |
|||
current->second |= mask; // update mask
|
|||
return; |
|||
} |
|||
cases.emplace(code, mask); |
|||
cache.emplace(code); |
|||
} |
|||
); |
|||
while (!cache.empty()) { // until BFS without elements
|
|||
core.next_cases(cache.front(), cases.find(cache.front())->second); |
|||
cache.pop(); // case dequeue
|
|||
} |
|||
|
|||
auto result = std::vector<RawCode>(); |
|||
result.reserve(cases.size()); |
|||
for (auto &&raw_code : cases) { // export group cases
|
|||
result.emplace_back(RawCode::unsafe_create(raw_code.first)); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) { |
|||
auto all_cases = Group::all_cases(type_id); |
|||
std::vector<std::vector<CommonCode>> groups; |
|||
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
|
|||
auto first_group = Group::group_cases(min->to_raw_code()); // expand the first group
|
|||
groups.emplace_back(first_group.begin(), first_group.end()); |
|||
if (first_group.size() == all_cases.size()) { // only contains one group
|
|||
return groups; |
|||
} |
|||
|
|||
// TODO: do not insert the elements in first group
|
|||
std::set<CommonCode> cases(all_cases.begin(), all_cases.end()); |
|||
for (auto &&tmp : groups[0]) { |
|||
cases.erase(tmp); // remove elements in first group
|
|||
} |
|||
while (!cases.empty()) { |
|||
groups.emplace_back(); // create empty vector
|
|||
auto current_group = groups.end() - 1; // insert into latest
|
|||
for (auto &&tmp : Group::group_cases(cases.begin()->to_raw_code())) { |
|||
auto common_code = tmp.to_common_code(); |
|||
current_group->emplace_back(common_code); // insert into current group
|
|||
cases.erase(common_code); // remove from global union
|
|||
} |
|||
} |
|||
|
|||
auto compare_func = [](const std::vector<CommonCode> &v1, const std::vector<CommonCode> &v2) { |
|||
return v1.size() > v2.size(); // sort by vector size
|
|||
}; |
|||
std::stable_sort(groups.begin(), groups.end(), compare_func); // using stable sort for ordered index
|
|||
return groups; |
|||
} |
|||
|
|||
} // namespace klotski
|
@ -1,118 +1,5 @@ |
|||
#include <queue> |
|||
#include <vector> |
|||
#include "core.h" |
|||
#include "group.h" |
|||
#include "absl/container/flat_hash_map.h" |
|||
#include "common.h" |
|||
|
|||
#include "size.h" |
|||
|
|||
#include "group_seeds.h" |
|||
|
|||
namespace klotski { |
|||
|
|||
using klotski::AllCases; |
|||
using klotski::BasicRanges; |
|||
|
|||
using klotski::Common::check_range; |
|||
using klotski::Common::range_reverse; |
|||
|
|||
std::vector<CommonCode> Group::all_cases(uint32_t type_id) { |
|||
auto tmp = block_num(type_id); |
|||
std::vector<uint32_t> ranges; // basic ranges of type_id
|
|||
BasicRanges::generate(ranges, BasicRanges::generate_t { // generate target ranges
|
|||
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
|
|||
.n2 = tmp.n_1x2, /// 1x2 -> 01
|
|||
.n3 = tmp.n_2x1, /// 2x1 -> 10
|
|||
.n4 = tmp.n_1x1, /// 1x1 -> 11
|
|||
}); |
|||
for (auto &range : ranges) { |
|||
range = range_reverse(range); // basic ranges reversed
|
|||
} |
|||
|
|||
std::vector<CommonCode> all_cases; |
|||
all_cases.reserve(GROUP_ALL_CASES_SIZE[type_id]); |
|||
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
|
|||
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
|
|||
if ((head & 0b11) == 0b11) { |
|||
++head; // skip invalid address
|
|||
} |
|||
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
|
|||
for (auto &&range : ranges) { |
|||
if (!check_range(head, range)) { // case valid
|
|||
all_cases.emplace_back(CommonCode::unsafe_create( |
|||
head << 32 | range_reverse(range) // release valid cases
|
|||
)); |
|||
} |
|||
} |
|||
} |
|||
return all_cases; |
|||
} |
|||
|
|||
std::vector<RawCode> Group::group_cases(const RawCode &seed) { |
|||
std::queue<uint64_t> cache; |
|||
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|||
cases.reserve(max_group_size(seed)); |
|||
cases.emplace(seed.unwrap(), 0); // without mask
|
|||
cache.emplace(seed.unwrap()); |
|||
|
|||
auto core = Core( |
|||
[&cache, &cases](auto &&code, auto &&mask) { // callback function
|
|||
auto current = cases.find(code); |
|||
if (current != cases.end()) { |
|||
current->second |= mask; // update mask
|
|||
return; |
|||
} |
|||
cases.emplace(code, mask); |
|||
cache.emplace(code); |
|||
} |
|||
); |
|||
while (!cache.empty()) { // until BFS without elements
|
|||
core.next_cases(cache.front(), cases.find(cache.front())->second); |
|||
cache.pop(); // case dequeue
|
|||
} |
|||
|
|||
auto result = std::vector<RawCode>(); |
|||
result.reserve(cases.size()); |
|||
for (auto &&raw_code : cases) { // export group cases
|
|||
result.emplace_back(RawCode::unsafe_create(raw_code.first)); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) { |
|||
auto all_cases = Group::all_cases(type_id); |
|||
if (all_cases.empty()) { |
|||
return {}; // type 203 -> no element
|
|||
} |
|||
|
|||
std::vector<std::vector<CommonCode>> groups; |
|||
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
|
|||
auto first_group = Group::group_cases(min->to_raw_code()); // expand the first group
|
|||
groups.emplace_back(first_group.begin(), first_group.end()); |
|||
if (first_group.size() == all_cases.size()) { // only contains one group
|
|||
return groups; |
|||
} |
|||
|
|||
std::set<CommonCode> cases(all_cases.begin(), all_cases.end()); |
|||
for (auto &&tmp : groups[0]) { |
|||
cases.erase(tmp); // remove elements in first group
|
|||
} |
|||
while (!cases.empty()) { |
|||
groups.emplace_back(); // create empty vector
|
|||
auto current_group = groups.end() - 1; // insert into latest
|
|||
for (auto &&tmp : Group::group_cases(cases.begin()->to_raw_code())) { |
|||
auto common_code = tmp.to_common_code(); |
|||
current_group->emplace_back(common_code); // insert into current group
|
|||
cases.erase(common_code); // remove from global union
|
|||
} |
|||
} |
|||
|
|||
auto compare_func = [](const std::vector<CommonCode> &v1, const std::vector<CommonCode> &v2) { |
|||
return v1.size() > v2.size(); // sort by vector size
|
|||
}; |
|||
std::stable_sort(groups.begin(), groups.end(), compare_func); // using stable sort for ordered index
|
|||
return groups; |
|||
} |
|||
|
|||
} // namespace klotski
|
|||
|
@ -1,34 +0,0 @@ |
|||
#pragma once |
|||
|
|||
namespace klotski { |
|||
|
|||
const uint32_t GROUP_ALL_CASES_SIZE[204] = { |
|||
12, 192, 1440, 6720, 21840, 52416, 96096, 137280, |
|||
154440, 137280, 96096, 52416, 21840, 6720, 1440, 124, |
|||
1736, 11284, 45136, 124124, 248248, 372372, 425568, 372372, |
|||
248248, 124124, 45136, 11284, 132, 1848, 12012, 48048, |
|||
132132, 264264, 396396, 453024, 396396, 264264, 132132, 48048, |
|||
12012, 512, 6144, 33792, 112640, 253440, 405504, 473088, |
|||
405504, 253440, 112640, 33792, 1044, 12528, 68904, 229680, |
|||
516780, 826848, 964656, 826848, 516780, 229680, 68904, 582, |
|||
6984, 38412, 128040, 288090, 460944, 537768, 460944, 288090, |
|||
128040, 38412, 1092, 10920, 49140, 131040, 229320, 275184, |
|||
229320, 131040, 49140, 3180, 31800, 143100, 381600, 667800, |
|||
801360, 667800, 381600, 143100, 3382, 33820, 152190, 405840, |
|||
710220, 852264, 710220, 405840, 152190, 1320, 13200, 59400, |
|||
158400, 277200, 332640, 277200, 158400, 59400, 1320, 10560, |
|||
36960, 73920, 92400, 73920, 36960, 4680, 37440, 131040, |
|||
262080, 327600, 262080, 131040, 7248, 57984, 202944, 405888, |
|||
507360, 405888, 202944, 5344, 42752, 149632, 299264, 374080, |
|||
299264, 149632, 1632, 13056, 45696, 91392, 114240, 91392, |
|||
45696, 948, 5688, 14220, 18960, 14220, 3444, 20664, |
|||
51660, 68880, 51660, 7120, 42720, 106800, 142400, 106800, |
|||
7284, 43704, 109260, 145680, 109260, 4392, 26352, 65880, |
|||
87840, 65880, 1044, 6264, 15660, 20880, 15660, 396, |
|||
1584, 2376, 1260, 5040, 7560, 3084, 12336, 18504, |
|||
4288, 17152, 25728, 3196, 12784, 19176, 1836, 7344, |
|||
11016, 270, 1080, 1620, 88, 180, 626, 772, |
|||
1036, 464, 342, 0, |
|||
}; |
|||
|
|||
} // namespace klotski
|
Loading…
Reference in new issue