|
@ -5,6 +5,7 @@ |
|
|
#include "type_id.h" |
|
|
#include "type_id.h" |
|
|
#include "common_code.h" |
|
|
#include "common_code.h" |
|
|
#include "absl/container/flat_hash_map.h" |
|
|
#include "absl/container/flat_hash_map.h" |
|
|
|
|
|
#include "absl/container/btree_set.h" |
|
|
|
|
|
|
|
|
#include "type_id.h" |
|
|
#include "type_id.h" |
|
|
#include "group_seeds.h" |
|
|
#include "group_seeds.h" |
|
@ -14,8 +15,8 @@ namespace klotski { |
|
|
using Common::check_range; |
|
|
using Common::check_range; |
|
|
using Common::range_reverse; |
|
|
using Common::range_reverse; |
|
|
|
|
|
|
|
|
std::vector<CommonCode> Group::all_cases(uint32_t type_id) { |
|
|
std::vector<CommonCode> Group::all_cases(const TypeId &type_id) { |
|
|
auto tmp = TypeId(type_id).block_num(); |
|
|
auto tmp = type_id.block_num(); |
|
|
std::vector<uint32_t> ranges; // basic ranges of type_id
|
|
|
std::vector<uint32_t> ranges; // basic ranges of type_id
|
|
|
BasicRanges::generate(ranges, { // generate target ranges
|
|
|
BasicRanges::generate(ranges, { // generate target ranges
|
|
|
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
|
|
|
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
|
|
@ -28,7 +29,7 @@ std::vector<CommonCode> Group::all_cases(uint32_t type_id) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<CommonCode> all_cases; |
|
|
std::vector<CommonCode> all_cases; |
|
|
all_cases.reserve(TYPE_ID_SIZE[type_id]); |
|
|
all_cases.reserve(TYPE_ID_SIZE[type_id.unwrap()]); |
|
|
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
|
|
|
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
|
|
|
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
|
|
|
if ((head & 0b11) == 0b11) { |
|
|
if ((head & 0b11) == 0b11) { |
|
@ -46,12 +47,12 @@ std::vector<CommonCode> Group::all_cases(uint32_t type_id) { |
|
|
return all_cases; |
|
|
return all_cases; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<RawCode> Group::group_cases(const RawCode &raw_code) { |
|
|
absl::flat_hash_map<uint64_t, uint64_t> expansion(const RawCode &entry) { |
|
|
std::queue<uint64_t> cache; |
|
|
std::queue<uint64_t> cache; |
|
|
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|
|
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|
|
cases.reserve(max_group_size(raw_code)); |
|
|
cases.reserve(Group::group_max_size(entry)); |
|
|
cases.emplace(raw_code.unwrap(), 0); // without mask
|
|
|
cases.emplace(entry.unwrap(), 0); // without mask
|
|
|
cache.emplace(raw_code.unwrap()); |
|
|
cache.emplace(entry.unwrap()); |
|
|
|
|
|
|
|
|
auto core = Core( |
|
|
auto core = Core( |
|
|
[&cache, &cases](auto &&code, auto &&mask) { // callback function
|
|
|
[&cache, &cases](auto &&code, auto &&mask) { // callback function
|
|
@ -68,7 +69,11 @@ std::vector<RawCode> Group::group_cases(const RawCode &raw_code) { |
|
|
core.next_cases(cache.front(), cases.find(cache.front())->second); |
|
|
core.next_cases(cache.front(), cases.find(cache.front())->second); |
|
|
cache.pop(); // case dequeue
|
|
|
cache.pop(); // case dequeue
|
|
|
} |
|
|
} |
|
|
|
|
|
return cases; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<RawCode> Group::group_cases(const RawCode &raw_code) { |
|
|
|
|
|
auto cases = expansion(raw_code); |
|
|
auto result = std::vector<RawCode>(); |
|
|
auto result = std::vector<RawCode>(); |
|
|
result.reserve(cases.size()); |
|
|
result.reserve(cases.size()); |
|
|
for (auto &&tmp : cases) { // export group cases
|
|
|
for (auto &&tmp : cases) { // export group cases
|
|
@ -77,7 +82,6 @@ std::vector<RawCode> Group::group_cases(const RawCode &raw_code) { |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// TODO: test this function
|
|
|
|
|
|
std::vector<RawCode> Group::group_cases(const CommonCode &common_code) { |
|
|
std::vector<RawCode> Group::group_cases(const CommonCode &common_code) { |
|
|
return group_cases(RawCode::from_common_code(common_code)); |
|
|
return group_cases(RawCode::from_common_code(common_code)); |
|
|
} |
|
|
} |
|
@ -121,9 +125,10 @@ std::vector<CommonCode> Group::build_group(uint32_t type_id, uint32_t group_id) |
|
|
return {}; // group_id out of range
|
|
|
return {}; // group_id out of range
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) { |
|
|
std::vector<std::vector<CommonCode>> Group::build_groups(const TypeId &type_id) { |
|
|
auto all_cases = Group::all_cases(type_id); |
|
|
auto all_cases = Group::all_cases(type_id); |
|
|
std::vector<std::vector<CommonCode>> groups; |
|
|
std::vector<std::vector<CommonCode>> groups; |
|
|
|
|
|
|
|
|
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
|
|
|
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
|
|
|
auto first_group = group_cases(min->to_raw_code()); // expand the first group
|
|
|
auto first_group = group_cases(min->to_raw_code()); // expand the first group
|
|
|
groups.emplace_back(first_group.begin(), first_group.end()); |
|
|
groups.emplace_back(first_group.begin(), first_group.end()); |
|
@ -131,17 +136,15 @@ std::vector<std::vector<CommonCode>> Group::build_groups(uint32_t type_id) { |
|
|
return groups; |
|
|
return groups; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::set<CommonCode> cases(all_cases.begin(), all_cases.end()); |
|
|
absl::btree_set<CommonCode> cases(all_cases.begin(), all_cases.end()); |
|
|
for (auto &&tmp : groups[0]) { |
|
|
for (auto &&tmp : *groups.begin()) { |
|
|
cases.erase(tmp); // remove elements in first group
|
|
|
cases.erase(tmp); // remove elements in first group
|
|
|
} |
|
|
} |
|
|
while (!cases.empty()) { |
|
|
while (!cases.empty()) { |
|
|
groups.emplace_back(); // create empty vector
|
|
|
auto group = group_cases(cases.begin()->to_raw_code()); |
|
|
auto current_group = groups.end() - 1; // insert into latest
|
|
|
groups.emplace_back(group.begin(), group.end()); // release new group
|
|
|
for (auto &&tmp : group_cases(cases.begin()->to_raw_code())) { |
|
|
for (auto &&tmp : *(groups.end() - 1)) { |
|
|
auto common_code = tmp.to_common_code(); |
|
|
cases.erase(tmp); // remove selected cases
|
|
|
current_group->emplace_back(common_code); // insert into current group
|
|
|
|
|
|
cases.erase(common_code); // remove from global union
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|