Browse Source

refactor: clean legacy group code

master
Dnomd343 4 weeks ago
parent
commit
8ccb1bed0f
  1. 2
      src/core/CMakeLists.txt
  2. 86
      src/core/group/group.h
  3. 17
      src/core/group/internal/constant/group.h
  4. 23
      src/core/group/internal/constant/group_pro.h
  5. 1
      src/core/group/internal/constant/mirror_h.inc
  6. 1
      src/core/group/internal/constant/mirror_v.inc
  7. 3178
      src/core/group/internal/constant/seeds.inc
  8. 1
      src/core/group/internal/constant/sizes.inc
  9. 88
      src/core/group/internal/extend.cc
  10. 126
      src/core/group/internal/group.cc
  11. 179
      src/core/group/internal/group.inl
  12. 6
      src/core/group/internal/group_cases_pro.cc
  13. 66
      src/core/group/internal/group_pro.cc
  14. 135
      src/core/group/internal/group_pro.inl
  15. 26
      src/core/group/internal/group_union.inl
  16. 5
      src/core/main.cc
  17. 8
      src/core_test/cases/group_pro.cc
  18. 3
      src/core_test/cases/group_union.cc

2
src/core/CMakeLists.txt

@ -24,8 +24,8 @@ set(KLOTSKI_CORE_SRC
fast_cal/internal/fast_cal.cc fast_cal/internal/fast_cal.cc
group/internal/group_union.cc group/internal/group_union.cc
group/internal/extend.cc
group/internal/group.cc group/internal/group.cc
group/internal/group_pro.cc
group/internal/group_cases.cc group/internal/group_cases.cc
group/internal/group_cases_pro.cc group/internal/group_cases_pro.cc

86
src/core/group/group.h

@ -79,8 +79,7 @@ constexpr uint32_t ALL_PATTERN_NUM = 6577;
typedef std::vector<codec::RawCode> RawCodes; typedef std::vector<codec::RawCode> RawCodes;
typedef std::vector<codec::CommonCode> CommonCodes; typedef std::vector<codec::CommonCode> CommonCodes;
//class Group; class Group;
class GroupPro;
// TODO: add constexpr // TODO: add constexpr
class GroupUnion { class GroupUnion {
@ -114,7 +113,7 @@ public:
[[nodiscard]] constexpr uint32_t pattern_num() const; [[nodiscard]] constexpr uint32_t pattern_num() const;
[[nodiscard]] std::vector<GroupPro> groups_pro() const; [[nodiscard]] std::vector<Group> groups_pro() const;
// TODO: get target pattern_id // TODO: get target pattern_id
@ -160,9 +159,9 @@ private:
// TODO: add debug output // TODO: add debug output
class GroupPro { class Group {
public: public:
GroupPro() = delete; Group() = delete;
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -195,12 +194,12 @@ public:
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
/// Create Group without any check. /// Create Group without any check.
static constexpr GroupPro unsafe_create(uint32_t type_id, static constexpr Group unsafe_create(uint32_t type_id,
uint32_t pattern_id, Toward toward); uint32_t pattern_id, Toward toward);
/// Create Group with validity check. /// Create Group with validity check.
static constexpr std::optional<GroupPro> create(uint32_t type_id, static constexpr std::optional<Group> create(uint32_t type_id,
uint32_t pattern_id, Toward toward); uint32_t pattern_id, Toward toward);
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -213,13 +212,13 @@ public:
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
/// Create Group from RawCode. /// Create Group from RawCode.
static GroupPro from_raw_code(codec::RawCode raw_code); static Group from_raw_code(codec::RawCode raw_code);
/// Create Group from ShortCode. /// Create Group from ShortCode.
static GroupPro from_short_code(codec::ShortCode short_code); static Group from_short_code(codec::ShortCode short_code);
/// Create Group from CommonCode. /// Create Group from CommonCode.
static GroupPro from_common_code(codec::CommonCode common_code); static Group from_common_code(codec::CommonCode common_code);
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -233,10 +232,10 @@ public:
[[nodiscard]] constexpr bool is_horizontal_mirror() const; [[nodiscard]] constexpr bool is_horizontal_mirror() const;
/// Obtain the vertically symmetrical klotski group. /// Obtain the vertically symmetrical klotski group.
[[nodiscard]] constexpr GroupPro to_vertical_mirror() const; [[nodiscard]] constexpr Group to_vertical_mirror() const;
/// Obtain the horizontally symmetrical klotski group. /// Obtain the horizontally symmetrical klotski group.
[[nodiscard]] constexpr GroupPro to_horizontal_mirror() const; [[nodiscard]] constexpr Group to_horizontal_mirror() const;
// ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------- //
@ -245,7 +244,7 @@ private:
Toward toward_; Toward toward_;
uint32_t pattern_id_; uint32_t pattern_id_;
GroupPro(uint32_t type_id, uint32_t pattern_id, Toward toward) { Group(uint32_t type_id, uint32_t pattern_id, Toward toward) {
type_id_ = type_id; type_id_ = type_id;
pattern_id_ = pattern_id; pattern_id_ = pattern_id;
toward_ = toward; toward_ = toward;
@ -255,66 +254,13 @@ private:
[[nodiscard]] constexpr uint32_t flat_id() const; [[nodiscard]] constexpr uint32_t flat_id() const;
}; };
//class Group {
//public:
// Group() = delete;
// ------------------------------------------------------------------------------------- //
/// Get the original type id.
// [[nodiscard]] constexpr uint32_t type_id() const;
/// Get the original group id.
// [[nodiscard]] constexpr uint32_t group_id() const;
/// Create Group without any check.
// static constexpr Group unsafe_create(uint32_t type_id, uint32_t group_id);
/// Create Group with validity check.
// static constexpr std::optional<Group> create(uint32_t type_id, uint32_t group_id);
// ------------------------------------------------------------------------------------- //
/// Get all cases under current group.
// [[nodiscard]] RangesUnion cases() const;
/// Get the number of klotski cases contained.
// [[nodiscard]] constexpr uint32_t size() const;
// ------------------------------------------------------------------------------------- //
/// Create Group from RawCode.
// static Group from_raw_code(codec::RawCode raw_code);
/// Create Group from ShortCode.
// static Group from_short_code(codec::ShortCode short_code);
/// Create Group from CommonCode.
// static Group from_common_code(codec::CommonCode common_code);
// ------------------------------------------------------------------------------------- //
// TODO: add `is_xxx_mirror` interface
// [[nodiscard]] constexpr Group to_vertical_mirror() const;
// [[nodiscard]] constexpr Group to_horizontal_mirror() const;
//private:
// uint32_t type_id_;
// uint32_t group_id_;
/// Tiled merge of type_id and group_id.
// [[nodiscard]] constexpr uint32_t flat_id() const;
//};
/// Spawn all the unsorted codes of the current group. /// Spawn all the unsorted codes of the current group.
std::vector<codec::RawCode> Group_extend(codec::RawCode raw_code, uint32_t reserve = 0); std::vector<codec::RawCode> Group_extend(codec::RawCode raw_code, uint32_t reserve = 0);
class GroupCasesPro { class GroupCasesPro {
public: public:
struct CaseInfo { struct CaseInfo {
GroupPro group; Group group;
uint32_t case_id; uint32_t case_id;
}; };
@ -405,5 +351,3 @@ public:
#include "internal/group_union.inl" #include "internal/group_union.inl"
#include "internal/group_cases.inl" #include "internal/group_cases.inl"
#include "internal/group.inl" #include "internal/group.inl"
#include "internal/group_pro.inl"

17
src/core/group/internal/constant/group.h

@ -4,21 +4,16 @@
namespace klotski::cases { namespace klotski::cases {
// TODO: should we try to compress it? // seed(36) + size(20) + type(3)
constexpr auto GROUP_SIZE = std::to_array<uint32_t>({
#include "sizes.inc"
});
constexpr auto GROUP_SEED = std::to_array<uint64_t>({ constexpr auto PATTERN_DATA = std::to_array<uint64_t>({
#include "seeds.inc" #include "pattern.inc"
}); });
constexpr auto GROUP_MIRROR_H = std::to_array<uint16_t>({ // seed(36) + type_id(8) + pattern_id(10) + toward(2)
#include "mirror_h.inc"
});
constexpr auto GROUP_MIRROR_V = std::to_array<uint16_t>({ constexpr auto GROUP_DATA = std::to_array<uint64_t>({
#include "mirror_v.inc" #include "group.inc"
}); });
} // namespace klotski::cases } // namespace klotski::cases

23
src/core/group/internal/constant/group_pro.h

@ -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

1
src/core/group/internal/constant/mirror_h.inc

File diff suppressed because one or more lines are too long

1
src/core/group/internal/constant/mirror_v.inc

File diff suppressed because one or more lines are too long

3178
src/core/group/internal/constant/seeds.inc

File diff suppressed because it is too large

1
src/core/group/internal/constant/sizes.inc

File diff suppressed because one or more lines are too long

88
src/core/group/internal/extend.cc

@ -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
//}

126
src/core/group/internal/group.cc

@ -1,88 +1,66 @@
#include <absl/container/flat_hash_map.h> #include <algorithm>
#include "mover/mover.h"
#include "group/group.h" #include "group/group.h"
//using klotski::cases::Group;
using klotski::codec::RawCode; using klotski::codec::RawCode;
using klotski::codec::CommonCode; using klotski::codec::CommonCode;
using klotski::cases::Group;
using klotski::cases::RangesUnion; using klotski::cases::RangesUnion;
using klotski::mover::MaskMover; using klotski::cases::GROUP_DATA;
using klotski::cases::GroupUnion; 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) { RangesUnion data;
std::vector<RawCode> codes; for (auto raw_code : codes) {
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask> auto common_code = raw_code.to_common_code().unwrap();
reserve = reserve ? reserve : GroupUnion::from_raw_code(raw_code).max_group_size(); data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code));
codes.reserve(reserve); }
cases.reserve(reserve);
auto core = MaskMover([&codes, &cases](uint64_t code, uint64_t mask) { for (int head = 0; head < 16; ++head) {
if (const auto match = cases.find(code); match != cases.end()) { std::stable_sort(data[head].begin(), data[head].end());
match->second |= mask; // update mask }
return; return data;
} }
cases.emplace(code, mask);
codes.emplace_back(RawCode::unsafe_create(code)); // new case
});
uint64_t offset = 0; static std::unordered_map<uint64_t, Group> build_map_data() {
codes.emplace_back(raw_code); // NOTE: using CommonCode as map key
cases.emplace(raw_code, 0); // without mask std::unordered_map<uint64_t, Group> data;
while (offset != codes.size()) { data.reserve(GROUP_DATA.size());
auto curr = codes[offset++].unwrap(); for (auto raw : GROUP_DATA) {
core.next_cases(curr, cases.find(curr)->second); 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 { Group Group::from_raw_code(codec::RawCode raw_code) {
// static auto map_data = build_map_data();
// // 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) {
// auto raw_codes = Group_extend(raw_code); return r.to_common_code();
// }) | std::ranges::to<std::vector>(); // TODO: search min_element directly
// auto common_codes = raw_codes | std::views::transform([](const RawCode r) { auto seed = std::min_element(common_codes.begin(), common_codes.end());
// return r.to_common_code();
// }) | std::ranges::to<std::vector>(); // TODO: search min_element directly return map_data.at(seed->unwrap());
// }
// 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
//}

179
src/core/group/internal/group.inl

@ -4,57 +4,132 @@
namespace klotski::cases { namespace klotski::cases {
// ----------------------------------------------------------------------------------------- // [[nodiscard]] constexpr uint32_t Group::type_id() const {
return type_id_;
//constexpr uint32_t Group::size() const { }
// return GROUP_SIZE[flat_id()];
//} [[nodiscard]] constexpr uint32_t Group::pattern_id() const {
// return pattern_id_;
//constexpr uint32_t Group::type_id() const { }
// return type_id_;
//} [[nodiscard]] constexpr auto Group::toward() const -> Toward {
// return toward_;
//constexpr uint32_t Group::group_id() const { }
// return group_id_;
//} constexpr Group Group::unsafe_create(uint32_t type_id, uint32_t pattern_id, Toward toward) {
// return {type_id, pattern_id, toward};
//constexpr uint32_t Group::flat_id() const { }
// return GROUP_OFFSET[type_id_] + group_id_;
//} constexpr std::optional<Group> Group::create(uint32_t type_id, uint32_t pattern_id, Toward toward) {
if (type_id >= TYPE_ID_LIMIT) {
// ----------------------------------------------------------------------------------------- // return std::nullopt;
}
//constexpr Group Group::to_vertical_mirror() const { if (pattern_id >= GroupUnion::unsafe_create(type_id).pattern_num()) {
// return Group::unsafe_create(type_id_, GROUP_MIRROR_V[flat_id()]); return std::nullopt;
//} }
// // TODO: toward check
//constexpr Group Group::to_horizontal_mirror() const { return unsafe_create(type_id, pattern_id, toward);
// return Group::unsafe_create(type_id_, GROUP_MIRROR_H[flat_id()]); }
//}
constexpr uint32_t Group::flat_id() const {
// ----------------------------------------------------------------------------------------- // return PATTERN_OFFSET[type_id_] + pattern_id_;
}
//inline Group Group::from_common_code(codec::CommonCode common_code) {
// return from_raw_code(common_code.to_raw_code()); constexpr uint32_t Group::size() const {
//} return (PATTERN_DATA[flat_id()] >> 3) & 0xFFFFF;
// }
//inline Group Group::from_short_code(codec::ShortCode short_code) {
// return from_common_code(short_code.to_common_code()); inline Group Group::from_short_code(codec::ShortCode short_code) {
//} return from_common_code(short_code.to_common_code());
}
// ----------------------------------------------------------------------------------------- //
inline Group Group::from_common_code(codec::CommonCode common_code) {
//constexpr Group Group::unsafe_create(const uint32_t type_id, const uint32_t group_id) { return from_raw_code(common_code.to_raw_code());
// return std::bit_cast<Group>(static_cast<uint64_t>(group_id) << 32 | type_id); }
//}
// constexpr auto Group::mirror_type() const -> MirrorType {
//constexpr std::optional<Group> Group::create(const uint32_t type_id, const uint32_t group_id) { return static_cast<MirrorType>(PATTERN_DATA[flat_id()] & 0b111);
// if (type_id < TYPE_ID_LIMIT && group_id < GROUP_NUM[type_id]) { }
// return unsafe_create(type_id, group_id);
// } constexpr bool Group::is_vertical_mirror() const {
// return std::nullopt; 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 Group::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 Group Group::to_vertical_mirror() const {
switch (mirror_type()) {
case MirrorType::Full:
return *this;
case MirrorType::Horizontal:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Centro:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Vertical:
return *this;
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
}
constexpr Group Group::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 Group::unsafe_create(type_id_, pattern_id_, Toward::B);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
case MirrorType::Ordinary:
if (toward_ == Toward::A) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::B);
} else if (toward_ == Toward::B) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::A);
} else if (toward_ == Toward::C) {
return Group::unsafe_create(type_id_, pattern_id_, Toward::D);
}
return Group::unsafe_create(type_id_, pattern_id_, Toward::C);
}
}
} // namespace klotski::cases } // namespace klotski::cases

6
src/core/group/internal/group_cases_pro.cc

@ -5,7 +5,7 @@
using klotski::codec::ShortCode; using klotski::codec::ShortCode;
using klotski::codec::CommonCode; using klotski::codec::CommonCode;
using klotski::cases::GroupPro; using klotski::cases::Group;
using klotski::cases::GroupUnion; using klotski::cases::GroupUnion;
using klotski::cases::RangesUnion; using klotski::cases::RangesUnion;
using klotski::cases::GroupCasesPro; using klotski::cases::GroupCasesPro;
@ -36,7 +36,7 @@ std::vector<std::vector<RangesUnion>> build_ranges_unions() {
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
auto group_union = GroupUnion::unsafe_create(type_id); auto group_union = GroupUnion::unsafe_create(type_id);
for (uint32_t pattern_id = 0; pattern_id < group_union.pattern_num(); ++pattern_id) { for (uint32_t pattern_id = 0; pattern_id < group_union.pattern_num(); ++pattern_id) {
std::vector<GroupPro> groups; std::vector<Group> groups;
for (auto group : group_union.groups_pro()) { for (auto group : group_union.groups_pro()) {
if (group.pattern_id() == pattern_id) { if (group.pattern_id() == pattern_id) {
groups.emplace_back(group); groups.emplace_back(group);
@ -115,7 +115,7 @@ GroupCasesPro::CaseInfo GroupCasesPro::fast_obtain(codec::ShortCode short_code)
auto case_id = (*rev_data)[short_code.unwrap()].case_id; auto case_id = (*rev_data)[short_code.unwrap()].case_id;
return CaseInfo { return CaseInfo {
.group = GroupPro::unsafe_create(type_id, pattern_id, (GroupPro::Toward)toward_id), .group = Group::unsafe_create(type_id, pattern_id, (Group::Toward)toward_id),
.case_id = case_id, .case_id = case_id,
}; };
} }

66
src/core/group/internal/group_pro.cc

@ -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());
}

135
src/core/group/internal/group_pro.inl

@ -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

26
src/core/group/internal/group_union.inl

@ -60,26 +60,26 @@ constexpr uint32_t GroupUnion::pattern_num() const {
return PATTERN_NUM[type_id_]; return PATTERN_NUM[type_id_];
} }
inline std::vector<GroupPro> GroupUnion::groups_pro() const { inline std::vector<Group> GroupUnion::groups_pro() const {
std::vector<GroupPro> groups; std::vector<Group> groups;
groups.reserve(group_num()); groups.reserve(group_num());
for (uint32_t pattern_id = 0; pattern_id < pattern_num(); ++pattern_id) { for (uint32_t pattern_id = 0; pattern_id < pattern_num(); ++pattern_id) {
auto group = GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::A); auto group = Group::unsafe_create(type_id_, pattern_id, Group::Toward::A);
groups.emplace_back(group); groups.emplace_back(group);
switch (group.mirror_type()) { switch (group.mirror_type()) {
case GroupPro::MirrorType::Full: case Group::MirrorType::Full:
continue; continue;
case GroupPro::MirrorType::Horizontal: case Group::MirrorType::Horizontal:
groups.emplace_back(GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::C)); groups.emplace_back(Group::unsafe_create(type_id_, pattern_id, Group::Toward::C));
break; break;
case GroupPro::MirrorType::Centro: case Group::MirrorType::Centro:
case GroupPro::MirrorType::Vertical: case Group::MirrorType::Vertical:
groups.emplace_back(GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::B)); groups.emplace_back(Group::unsafe_create(type_id_, pattern_id, Group::Toward::B));
break; break;
case GroupPro::MirrorType::Ordinary: case Group::MirrorType::Ordinary:
groups.emplace_back(GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::B)); groups.emplace_back(Group::unsafe_create(type_id_, pattern_id, Group::Toward::B));
groups.emplace_back(GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::C)); groups.emplace_back(Group::unsafe_create(type_id_, pattern_id, Group::Toward::C));
groups.emplace_back(GroupPro::unsafe_create(type_id_, pattern_id, GroupPro::Toward::D)); groups.emplace_back(Group::unsafe_create(type_id_, pattern_id, Group::Toward::D));
break; break;
} }
} }

5
src/core/main.cc

@ -26,8 +26,7 @@ using klotski::codec::ShortCode;
using klotski::codec::CommonCode; using klotski::codec::CommonCode;
using klotski::cases::GroupUnion; using klotski::cases::GroupUnion;
//using klotski::cases::Group; using klotski::cases::Group;
using klotski::cases::GroupPro;
using klotski::cases::GroupCases; using klotski::cases::GroupCases;
using klotski::cases::GroupUnion; using klotski::cases::GroupUnion;
using klotski::cases::GroupCasesPro; using klotski::cases::GroupCasesPro;
@ -61,7 +60,7 @@ int main() {
// std::cout << data_s.size() << std::endl; // std::cout << data_s.size() << std::endl;
// std::cout << data_c.size() << std::endl; // std::cout << data_c.size() << std::endl;
auto group = GroupPro::from_common_code(CommonCode::unsafe_create(0x1A9BF0C00)); auto group = Group::from_common_code(CommonCode::unsafe_create(0x1A9BF0C00));
std::cout << group.type_id() << std::endl; std::cout << group.type_id() << std::endl;
std::cout << group.pattern_id() << std::endl; std::cout << group.pattern_id() << std::endl;
std::cout << (int)group.toward() << std::endl; std::cout << (int)group.toward() << std::endl;

8
src/core_test/cases/group_pro.cc

@ -7,7 +7,7 @@
#include "helper/parallel.h" #include "helper/parallel.h"
using klotski::cases::GroupPro; using klotski::cases::Group;
using klotski::cases::GroupUnion; using klotski::cases::GroupUnion;
TEST(GroupPro, demo) { TEST(GroupPro, demo) {
@ -21,7 +21,7 @@ TEST(GroupPro, demo) {
std::cout << GroupUnion::unsafe_create(169).group_num() << std::endl; std::cout << GroupUnion::unsafe_create(169).group_num() << std::endl;
std::cout << (int)helper::pattern_mirror_type(169, 0) << std::endl; std::cout << (int)helper::pattern_mirror_type(169, 0) << std::endl;
std::cout << (int)GroupPro::unsafe_create(169, 0, GroupPro::Toward::A).mirror_type() << std::endl; std::cout << (int)Group::unsafe_create(169, 0, Group::Toward::A).mirror_type() << std::endl;
std::cout << std::format("{}", helper::pattern_toward_list(169, 0)) << std::endl; std::cout << std::format("{}", helper::pattern_toward_list(169, 0)) << std::endl;
std::cout << (int)GroupUnion::unsafe_create(169).groups_pro()[0].toward() << std::endl; std::cout << (int)GroupUnion::unsafe_create(169).groups_pro()[0].toward() << std::endl;
@ -43,12 +43,12 @@ TEST(GroupPro, cases) {
EXPECT_EQ((int)group.mirror_type(), helper::pattern_mirror_type(group.type_id(), group.pattern_id())); EXPECT_EQ((int)group.mirror_type(), helper::pattern_mirror_type(group.type_id(), group.pattern_id()));
auto g1 = GroupPro::from_common_code(cases.front()); auto g1 = Group::from_common_code(cases.front());
EXPECT_EQ(g1.type_id(), group.type_id()); EXPECT_EQ(g1.type_id(), group.type_id());
EXPECT_EQ(g1.pattern_id(), group.pattern_id()); EXPECT_EQ(g1.pattern_id(), group.pattern_id());
EXPECT_EQ(g1.toward(), group.toward()); EXPECT_EQ(g1.toward(), group.toward());
auto g2 = GroupPro::from_common_code(cases.back()); auto g2 = Group::from_common_code(cases.back());
EXPECT_EQ(g2.type_id(), group.type_id()); EXPECT_EQ(g2.type_id(), group.type_id());
EXPECT_EQ(g2.pattern_id(), group.pattern_id()); EXPECT_EQ(g2.pattern_id(), group.pattern_id());
EXPECT_EQ(g2.toward(), group.toward()); EXPECT_EQ(g2.toward(), group.toward());

3
src/core_test/cases/group_union.cc

@ -15,8 +15,7 @@
using klotski::codec::ShortCode; using klotski::codec::ShortCode;
//using klotski::cases::Group; using klotski::cases::Group;
using klotski::cases::GroupPro;
using klotski::cases::GroupUnion; using klotski::cases::GroupUnion;
using klotski::cases::TYPE_ID_LIMIT; using klotski::cases::TYPE_ID_LIMIT;

Loading…
Cancel
Save