mirror of https://github.com/dnomd343/klotski.git
Dnomd343
2 months ago
18 changed files with 312 additions and 3639 deletions
@ -1,23 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <array> |
|||
|
|||
namespace klotski::cases { |
|||
|
|||
// GROUP_PRO_SIZE: 1~964656 (20-bits)
|
|||
// GROUP_PRO_TYPE: 0~4 (3-bits)
|
|||
// GROUP_PRO_SEED: ... (36-bits)
|
|||
|
|||
// seed(36) + size(20) + type(3)
|
|||
|
|||
constexpr auto PATTERN_DATA = std::to_array<uint64_t>({ |
|||
#include "pattern.inc" |
|||
}); |
|||
|
|||
// seed(36) + type_id(8) + pattern_id(10) + toward(2)
|
|||
|
|||
constexpr auto GROUP_DATA = std::to_array<uint64_t>({ |
|||
#include "group.inc" |
|||
}); |
|||
|
|||
} // namespace klotski::cases
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,88 @@ |
|||
#include <absl/container/flat_hash_map.h> |
|||
|
|||
#include "mover/mover.h" |
|||
#include "group/group.h" |
|||
|
|||
//using klotski::cases::Group;
|
|||
using klotski::codec::RawCode; |
|||
using klotski::codec::CommonCode; |
|||
using klotski::cases::RangesUnion; |
|||
|
|||
using klotski::mover::MaskMover; |
|||
using klotski::cases::GroupUnion; |
|||
|
|||
std::vector<RawCode> klotski::cases::Group_extend(RawCode raw_code, uint32_t reserve) { |
|||
std::vector<RawCode> codes; |
|||
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|||
reserve = reserve ? reserve : GroupUnion::from_raw_code(raw_code).max_group_size(); |
|||
codes.reserve(reserve); |
|||
cases.reserve(reserve); |
|||
|
|||
auto core = MaskMover([&codes, &cases](uint64_t code, uint64_t mask) { |
|||
if (const auto match = cases.find(code); match != cases.end()) { |
|||
match->second |= mask; // update mask
|
|||
return; |
|||
} |
|||
cases.emplace(code, mask); |
|||
codes.emplace_back(RawCode::unsafe_create(code)); // new case
|
|||
}); |
|||
|
|||
uint64_t offset = 0; |
|||
codes.emplace_back(raw_code); |
|||
cases.emplace(raw_code, 0); // without mask
|
|||
while (offset != codes.size()) { |
|||
auto curr = codes[offset++].unwrap(); |
|||
core.next_cases(curr, cases.find(curr)->second); |
|||
} |
|||
return codes; |
|||
} |
|||
|
|||
//RangesUnion Group::cases() const {
|
|||
//
|
|||
// // TODO: add white list for single-group unions
|
|||
// // return GroupUnion::cases directly
|
|||
//
|
|||
// auto seed = CommonCode::unsafe_create(GROUP_SEED[flat_id()]);
|
|||
//
|
|||
// // std::cout << seed << std::endl;
|
|||
//
|
|||
// auto codes = Group_extend(seed.to_raw_code(), size());
|
|||
//
|
|||
// // std::cout << codes.size() << std::endl;
|
|||
//
|
|||
// // TODO: how to reserve
|
|||
//
|
|||
// RangesUnion data;
|
|||
//
|
|||
// for (auto raw_code : codes) {
|
|||
// auto common_code = raw_code.to_common_code().unwrap();
|
|||
// data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code));
|
|||
// }
|
|||
//
|
|||
// // TODO: do sort process
|
|||
//
|
|||
// for (int head = 0; head < 16; ++head) {
|
|||
// std::stable_sort(data[head].begin(), data[head].end());
|
|||
// }
|
|||
//
|
|||
// return data;
|
|||
//}
|
|||
|
|||
//Group Group::from_raw_code(codec::RawCode raw_code) {
|
|||
//
|
|||
// auto raw_codes = Group_extend(raw_code);
|
|||
//
|
|||
// auto common_codes = raw_codes | std::views::transform([](const RawCode r) {
|
|||
// return r.to_common_code();
|
|||
// }) | std::ranges::to<std::vector>(); // TODO: search min_element directly
|
|||
//
|
|||
// auto seed = std::min_element(common_codes.begin(), common_codes.end());
|
|||
//
|
|||
// std::cout << *seed << std::endl;
|
|||
//
|
|||
// // TODO: search type_id / group_id from map
|
|||
// auto flat_id = std::find(GROUP_SEED.begin(), GROUP_SEED.end(), *seed) - GROUP_SEED.begin();
|
|||
// std::cout << flat_id << std::endl;
|
|||
//
|
|||
// return Group::unsafe_create(0, 0); // TODO: only for compile
|
|||
//}
|
@ -1,88 +1,66 @@ |
|||
#include <absl/container/flat_hash_map.h> |
|||
#include <algorithm> |
|||
|
|||
#include "mover/mover.h" |
|||
#include "group/group.h" |
|||
|
|||
//using klotski::cases::Group;
|
|||
using klotski::codec::RawCode; |
|||
using klotski::codec::CommonCode; |
|||
|
|||
using klotski::cases::Group; |
|||
using klotski::cases::RangesUnion; |
|||
|
|||
using klotski::mover::MaskMover; |
|||
using klotski::cases::GroupUnion; |
|||
using klotski::cases::GROUP_DATA; |
|||
using klotski::cases::PATTERN_DATA; |
|||
|
|||
RangesUnion Group::cases() const { |
|||
auto seed = CommonCode::unsafe_create(PATTERN_DATA[flat_id()] >> 23); |
|||
|
|||
// NOTE: convert as RawCode directly
|
|||
if (toward_ == Toward::B) { |
|||
seed = seed.to_horizontal_mirror(); |
|||
} else if (toward_ == Toward::C) { |
|||
seed = seed.to_vertical_mirror(); |
|||
} else if (toward_ == Toward::D) { |
|||
// NOTE: avoid multi convert
|
|||
seed = seed.to_vertical_mirror().to_horizontal_mirror(); |
|||
} |
|||
|
|||
auto codes = Group_extend(seed.to_raw_code(), size()); |
|||
|
|||
std::vector<RawCode> klotski::cases::Group_extend(RawCode raw_code, uint32_t reserve) { |
|||
std::vector<RawCode> codes; |
|||
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
|
|||
reserve = reserve ? reserve : GroupUnion::from_raw_code(raw_code).max_group_size(); |
|||
codes.reserve(reserve); |
|||
cases.reserve(reserve); |
|||
RangesUnion data; |
|||
for (auto raw_code : codes) { |
|||
auto common_code = raw_code.to_common_code().unwrap(); |
|||
data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code)); |
|||
} |
|||
|
|||
auto core = MaskMover([&codes, &cases](uint64_t code, uint64_t mask) { |
|||
if (const auto match = cases.find(code); match != cases.end()) { |
|||
match->second |= mask; // update mask
|
|||
return; |
|||
} |
|||
cases.emplace(code, mask); |
|||
codes.emplace_back(RawCode::unsafe_create(code)); // new case
|
|||
}); |
|||
for (int head = 0; head < 16; ++head) { |
|||
std::stable_sort(data[head].begin(), data[head].end()); |
|||
} |
|||
return data; |
|||
} |
|||
|
|||
uint64_t offset = 0; |
|||
codes.emplace_back(raw_code); |
|||
cases.emplace(raw_code, 0); // without mask
|
|||
while (offset != codes.size()) { |
|||
auto curr = codes[offset++].unwrap(); |
|||
core.next_cases(curr, cases.find(curr)->second); |
|||
static std::unordered_map<uint64_t, Group> build_map_data() { |
|||
// NOTE: using CommonCode as map key
|
|||
std::unordered_map<uint64_t, Group> data; |
|||
data.reserve(GROUP_DATA.size()); |
|||
for (auto raw : GROUP_DATA) { |
|||
uint32_t type_id = (raw >> 12) & 0b11111111; |
|||
uint32_t pattern_id = (raw >> 2) & 0b1111111111; |
|||
uint32_t toward = raw & 0b11; |
|||
auto seed = CommonCode::unsafe_create(raw >> 20).unwrap(); |
|||
auto group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward); |
|||
data.emplace(seed, group); |
|||
} |
|||
return codes; |
|||
return data; |
|||
} |
|||
|
|||
//RangesUnion Group::cases() const {
|
|||
//
|
|||
// // TODO: add white list for single-group unions
|
|||
// // return GroupUnion::cases directly
|
|||
//
|
|||
// auto seed = CommonCode::unsafe_create(GROUP_SEED[flat_id()]);
|
|||
//
|
|||
// // std::cout << seed << std::endl;
|
|||
//
|
|||
// auto codes = Group_extend(seed.to_raw_code(), size());
|
|||
//
|
|||
// // std::cout << codes.size() << std::endl;
|
|||
//
|
|||
// // TODO: how to reserve
|
|||
//
|
|||
// RangesUnion data;
|
|||
//
|
|||
// for (auto raw_code : codes) {
|
|||
// auto common_code = raw_code.to_common_code().unwrap();
|
|||
// data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code));
|
|||
// }
|
|||
//
|
|||
// // TODO: do sort process
|
|||
//
|
|||
// for (int head = 0; head < 16; ++head) {
|
|||
// std::stable_sort(data[head].begin(), data[head].end());
|
|||
// }
|
|||
//
|
|||
// return data;
|
|||
//}
|
|||
Group Group::from_raw_code(codec::RawCode raw_code) { |
|||
static auto map_data = build_map_data(); |
|||
|
|||
//Group Group::from_raw_code(codec::RawCode raw_code) {
|
|||
//
|
|||
// auto raw_codes = Group_extend(raw_code);
|
|||
//
|
|||
// auto common_codes = raw_codes | std::views::transform([](const RawCode r) {
|
|||
// return r.to_common_code();
|
|||
// }) | std::ranges::to<std::vector>(); // TODO: search min_element directly
|
|||
//
|
|||
// auto seed = std::min_element(common_codes.begin(), common_codes.end());
|
|||
//
|
|||
// std::cout << *seed << std::endl;
|
|||
//
|
|||
// // TODO: search type_id / group_id from map
|
|||
// auto flat_id = std::find(GROUP_SEED.begin(), GROUP_SEED.end(), *seed) - GROUP_SEED.begin();
|
|||
// std::cout << flat_id << std::endl;
|
|||
//
|
|||
// return Group::unsafe_create(0, 0); // TODO: only for compile
|
|||
//}
|
|||
auto raw_codes = Group_extend(raw_code); |
|||
auto common_codes = raw_codes | std::views::transform([](const RawCode r) { |
|||
return r.to_common_code(); |
|||
}) | std::ranges::to<std::vector>(); // TODO: search min_element directly
|
|||
auto seed = std::min_element(common_codes.begin(), common_codes.end()); |
|||
|
|||
return map_data.at(seed->unwrap()); |
|||
} |
|||
|
@ -1,66 +0,0 @@ |
|||
#include <algorithm> |
|||
|
|||
#include "group/group.h" |
|||
|
|||
using klotski::codec::RawCode; |
|||
using klotski::codec::CommonCode; |
|||
|
|||
using klotski::cases::GroupPro; |
|||
using klotski::cases::RangesUnion; |
|||
|
|||
using klotski::cases::GROUP_DATA; |
|||
using klotski::cases::PATTERN_DATA; |
|||
|
|||
RangesUnion GroupPro::cases() const { |
|||
auto seed = CommonCode::unsafe_create(PATTERN_DATA[flat_id()] >> 23); |
|||
|
|||
// NOTE: convert as RawCode directly
|
|||
if (toward_ == Toward::B) { |
|||
seed = seed.to_horizontal_mirror(); |
|||
} else if (toward_ == Toward::C) { |
|||
seed = seed.to_vertical_mirror(); |
|||
} else if (toward_ == Toward::D) { |
|||
// NOTE: avoid multi convert
|
|||
seed = seed.to_vertical_mirror().to_horizontal_mirror(); |
|||
} |
|||
|
|||
auto codes = Group_extend(seed.to_raw_code(), size()); |
|||
|
|||
RangesUnion data; |
|||
for (auto raw_code : codes) { |
|||
auto common_code = raw_code.to_common_code().unwrap(); |
|||
data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code)); |
|||
} |
|||
|
|||
for (int head = 0; head < 16; ++head) { |
|||
std::stable_sort(data[head].begin(), data[head].end()); |
|||
} |
|||
return data; |
|||
} |
|||
|
|||
static std::unordered_map<uint64_t, GroupPro> build_map_data() { |
|||
// NOTE: using CommonCode as map key
|
|||
std::unordered_map<uint64_t, GroupPro> data; |
|||
data.reserve(GROUP_DATA.size()); |
|||
for (auto raw : GROUP_DATA) { |
|||
uint32_t type_id = (raw >> 12) & 0b11111111; |
|||
uint32_t pattern_id = (raw >> 2) & 0b1111111111; |
|||
uint32_t toward = raw & 0b11; |
|||
auto seed = CommonCode::unsafe_create(raw >> 20).unwrap(); |
|||
auto group = GroupPro::unsafe_create(type_id, pattern_id, (GroupPro::Toward)toward); |
|||
data.emplace(seed, group); |
|||
} |
|||
return data; |
|||
} |
|||
|
|||
GroupPro GroupPro::from_raw_code(codec::RawCode raw_code) { |
|||
static auto map_data = build_map_data(); |
|||
|
|||
auto raw_codes = Group_extend(raw_code); |
|||
auto common_codes = raw_codes | std::views::transform([](const RawCode r) { |
|||
return r.to_common_code(); |
|||
}) | std::ranges::to<std::vector>(); // TODO: search min_element directly
|
|||
auto seed = std::min_element(common_codes.begin(), common_codes.end()); |
|||
|
|||
return map_data.at(seed->unwrap()); |
|||
} |
@ -1,135 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include "constant/group_pro.h" |
|||
|
|||
namespace klotski::cases { |
|||
|
|||
[[nodiscard]] constexpr uint32_t GroupPro::type_id() const { |
|||
return type_id_; |
|||
} |
|||
|
|||
[[nodiscard]] constexpr uint32_t GroupPro::pattern_id() const { |
|||
return pattern_id_; |
|||
} |
|||
|
|||
[[nodiscard]] constexpr GroupPro::Toward GroupPro::toward() const { |
|||
return toward_; |
|||
} |
|||
|
|||
constexpr GroupPro GroupPro::unsafe_create(uint32_t type_id, uint32_t pattern_id, Toward toward) { |
|||
return {type_id, pattern_id, toward}; |
|||
} |
|||
|
|||
constexpr std::optional<GroupPro> GroupPro::create(uint32_t type_id, uint32_t pattern_id, Toward toward) { |
|||
if (type_id >= TYPE_ID_LIMIT) { |
|||
return std::nullopt; |
|||
} |
|||
if (pattern_id >= GroupUnion::unsafe_create(type_id).pattern_num()) { |
|||
return std::nullopt; |
|||
} |
|||
// TODO: toward check |
|||
return unsafe_create(type_id, pattern_id, toward); |
|||
} |
|||
|
|||
constexpr uint32_t GroupPro::flat_id() const { |
|||
return PATTERN_OFFSET[type_id_] + pattern_id_; |
|||
} |
|||
|
|||
constexpr uint32_t GroupPro::size() const { |
|||
return (PATTERN_DATA[flat_id()] >> 3) & 0xFFFFF; |
|||
} |
|||
|
|||
inline GroupPro GroupPro::from_short_code(codec::ShortCode short_code) { |
|||
return from_common_code(short_code.to_common_code()); |
|||
} |
|||
|
|||
inline GroupPro GroupPro::from_common_code(codec::CommonCode common_code) { |
|||
return from_raw_code(common_code.to_raw_code()); |
|||
} |
|||
|
|||
constexpr auto GroupPro::mirror_type() const -> MirrorType { |
|||
return static_cast<MirrorType>(PATTERN_DATA[flat_id()] & 0b111); |
|||
} |
|||
|
|||
constexpr bool GroupPro::is_vertical_mirror() const { |
|||
switch (mirror_type()) { |
|||
case MirrorType::Full: |
|||
return true; |
|||
case MirrorType::Horizontal: |
|||
return false; |
|||
case MirrorType::Centro: |
|||
return false; |
|||
case MirrorType::Vertical: |
|||
return true; |
|||
case MirrorType::Ordinary: |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
constexpr bool GroupPro::is_horizontal_mirror() const { |
|||
switch (mirror_type()) { |
|||
case MirrorType::Full: |
|||
return true; |
|||
case MirrorType::Horizontal: |
|||
return true; |
|||
case MirrorType::Centro: |
|||
return false; |
|||
case MirrorType::Vertical: |
|||
return false; |
|||
case MirrorType::Ordinary: |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
constexpr GroupPro GroupPro::to_vertical_mirror() const { |
|||
switch (mirror_type()) { |
|||
case MirrorType::Full: |
|||
return *this; |
|||
case MirrorType::Horizontal: |
|||
if (toward_ == Toward::A) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::C); |
|||
} |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::A); |
|||
case MirrorType::Centro: |
|||
if (toward_ == Toward::A) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::B); |
|||
} |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::A); |
|||
case MirrorType::Vertical: |
|||
return *this; |
|||
case MirrorType::Ordinary: |
|||
if (toward_ == Toward::A) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::C); |
|||
} else if (toward_ == Toward::B) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::D); |
|||
} else if (toward_ == Toward::C) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::A); |
|||
} |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::B); |
|||
} |
|||
} |
|||
|
|||
constexpr GroupPro GroupPro::to_horizontal_mirror() const { |
|||
switch (mirror_type()) { |
|||
case MirrorType::Full: |
|||
case MirrorType::Horizontal: |
|||
return *this; |
|||
case MirrorType::Centro: |
|||
case MirrorType::Vertical: |
|||
if (toward_ == Toward::A) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::B); |
|||
} |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::A); |
|||
case MirrorType::Ordinary: |
|||
if (toward_ == Toward::A) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::B); |
|||
} else if (toward_ == Toward::B) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::A); |
|||
} else if (toward_ == Toward::C) { |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::D); |
|||
} |
|||
return GroupPro::unsafe_create(type_id_, pattern_id_, Toward::C); |
|||
} |
|||
} |
|||
|
|||
} // namespace klotski::cases |
Loading…
Reference in new issue