Browse Source

refactor: interface of group module

master
Dnomd343 1 year ago
parent
commit
055c5c5ecf
  1. 16
      src/klotski_core/group/basic_id.cc
  2. 105
      src/klotski_core/group/build_cases.cc
  3. 119
      src/klotski_core/group/group.h
  4. 52
      src/klotski_core/group/group_info.cc
  5. 25
      src/klotski_core/group/seeds.cc
  6. 3
      test/group/basic_id.cc
  7. 2
      test/group/build_cases.cc

16
src/klotski_core/group/basic_id.cc

@ -18,14 +18,14 @@ TypeId::TypeId(uint32_t type_id) {
}
TypeId::TypeId(const RawCode &raw_code) noexcept {
type_id_ = to_type_id(block_num(raw_code));
type_id_ = type_id(block_num(raw_code));
}
TypeId::TypeId(const CommonCode &common_code) noexcept {
type_id_ = to_type_id(block_num(common_code));
type_id_ = type_id(block_num(common_code));
}
uint32_t TypeId::to_type_id(block_num_t &&block_num) noexcept {
uint32_t TypeId::type_id(block_num_t &&block_num) noexcept { // block_num_t -> type_id
/// flag -> ... 0000 0xxx 0xxx xxxx
/// n_x2x n_2x1 n_1x1
auto n_x2x = block_num.n_1x2 + block_num.n_2x1;
@ -35,7 +35,7 @@ uint32_t TypeId::to_type_id(block_num_t &&block_num) noexcept {
/// -------------------------------------- Block Number ---------------------------------------
TypeId::block_num_t TypeId::block_num() const noexcept {
TypeId::block_num_t TypeId::block_num() const noexcept { // type_id -> block_num_t
auto flag = TYPE_ID_INDEX[type_id_];
auto n_2x1 = (flag >> 4) & 0b111;
return block_num_t {
@ -99,4 +99,12 @@ GroupId::GroupId(const TypeId &type_id, uint32_t group_id) : type_id_(type_id) {
group_id_ = group_id;
}
GroupId::GroupId(const RawCode &raw_code) noexcept : type_id_(TypeId(raw_code)) {
group_id_ = group_id(type_id_.unwrap(), GroupId::seed(raw_code));
}
GroupId::GroupId(const CommonCode &common_code) noexcept : type_id_(TypeId(common_code)) {
group_id_ = group_id(type_id_.unwrap(), GroupId::seed(common_code));
}
} // namespace klotski

105
src/klotski_core/group/build_cases.cc

@ -12,24 +12,9 @@ namespace klotski {
using Common::check_range;
using Common::range_reverse;
uint32_t GroupId::size() const noexcept {
return size(seed());
}
uint32_t GroupId::size(const CommonCode &common_code) noexcept {
return GroupId::size(common_code.to_raw_code());
}
/// ----------------------------------------- Type ID -----------------------------------------
std::vector<RawCode> Group::cases(const CommonCode &common_code) noexcept {
return cases(common_code.to_raw_code());
}
std::vector<CommonCode> Group::build_group(const GroupId &group_id) {
auto cases = Group::cases(group_id.seed());
return {cases.begin(), cases.end()};
}
std::vector<CommonCode> TypeId::all_cases() const noexcept {
std::vector<CommonCode> TypeId::cases() const noexcept {
std::vector<uint32_t> ranges; // basic ranges of type_id
ranges.reserve(TYPE_ID_SIZE[type_id_]); // over-allocation
@ -63,10 +48,56 @@ std::vector<CommonCode> TypeId::all_cases() const noexcept {
return all_cases;
}
std::vector<std::vector<CommonCode>> TypeId::groups() const noexcept {
auto all_cases = cases();
std::vector<std::vector<CommonCode>> groups;
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
groups.emplace_back(first_group.begin(), first_group.end());
if (first_group.size() == all_cases.size()) {
return groups; // only contains one group
}
absl::btree_set<CommonCode> cases(all_cases.begin(), all_cases.end());
for (auto &&tmp : *groups.begin()) {
cases.erase(tmp); // remove elements from first group
}
while (!cases.empty()) {
auto group = Group::cases(cases.begin()->to_raw_code());
groups.emplace_back(group.begin(), group.end()); // release new group
for (auto &&tmp : *(groups.end() - 1)) {
cases.erase(tmp); // remove selected cases
}
}
auto cmp_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(), cmp_func); // using stable sort for ordered index
return groups;
}
/// ---------------------------------------- Group ID -----------------------------------------
uint32_t GroupId::size() const noexcept {
return size(seed());
}
uint32_t GroupId::size(const CommonCode &common_code) noexcept {
return size(common_code.to_raw_code());
}
std::vector<RawCode> GroupId::cases() const noexcept {
// auto cases = Group::cases(seed());
// return {cases.begin(), cases.end()};
return Group::cases(seed());
}
uint32_t GroupId::size(const RawCode &raw_code) noexcept {
std::queue<uint64_t> cache({raw_code.unwrap()});
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
cases.reserve(Group::group_max_size(raw_code));
cases.reserve(TypeId::group_max_size(raw_code));
cases.emplace(raw_code.unwrap(), 0b0); // without mask
auto core = Core(
@ -87,10 +118,16 @@ uint32_t GroupId::size(const RawCode &raw_code) noexcept {
return cases.size();
}
/// ------------------------------------------ Group ------------------------------------------
std::vector<RawCode> Group::cases(const CommonCode &common_code) noexcept {
return cases(common_code.to_raw_code());
}
std::vector<RawCode> Group::cases(const RawCode &raw_code) noexcept {
std::queue<uint64_t> cache({raw_code.unwrap()});
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
cases.reserve(Group::group_max_size(raw_code));
cases.reserve(TypeId::group_max_size(raw_code));
cases.emplace(raw_code.unwrap(), 0b0); // without mask
auto core = Core(
@ -117,34 +154,4 @@ std::vector<RawCode> Group::cases(const RawCode &raw_code) noexcept {
return result;
}
std::vector<std::vector<CommonCode>> Group::build_groups(const TypeId &type_id) {
auto all_cases = type_id.all_cases();
std::vector<std::vector<CommonCode>> groups;
auto min = std::min_element(all_cases.begin(), all_cases.end()); // search min CommonCode
auto first_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()) {
return groups; // only contains one group
}
absl::btree_set<CommonCode> cases(all_cases.begin(), all_cases.end());
for (auto &&tmp : *groups.begin()) {
cases.erase(tmp); // remove elements from first group
}
while (!cases.empty()) {
auto group = Group::cases(cases.begin()->to_raw_code());
groups.emplace_back(group.begin(), group.end()); // release new group
for (auto &&tmp : *(groups.end() - 1)) {
cases.erase(tmp); // remove selected cases
}
}
auto cmp_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(), cmp_func); // using stable sort for ordered index
return groups;
}
} // namespace klotski

119
src/klotski_core/group/group.h

@ -24,14 +24,14 @@ public:
private:
uint32_t type_id_;
static inline uint32_t to_type_id(block_num_t &&block_num) noexcept;
static inline uint32_t type_id(block_num_t &&block_num) noexcept;
public:
explicit TypeId(uint32_t type_id);
explicit TypeId(const RawCode &raw_code) noexcept;
explicit TypeId(const CommonCode &common_code) noexcept;
/// Release raw type id value.
/// Release raw type_id value.
constexpr uint32_t unwrap() const noexcept { return type_id_; }
/// Get the number of klotski blocks.
@ -39,28 +39,25 @@ public:
static block_num_t block_num(const RawCode &raw_code) noexcept;
static block_num_t block_num(const CommonCode &common_code) noexcept;
/// Get all seeds in the specified type id.
std::vector<CommonCode> seeds() const noexcept;
/// Search for all cases of the specified type_id.
std::vector<CommonCode> all_cases() const noexcept;
};
/// Get the number of groups.
uint32_t group_num() const noexcept;
static uint32_t group_num(const RawCode &raw_code) noexcept;
static uint32_t group_num(const CommonCode &common_code) noexcept;
inline bool operator==(const TypeId &t1, const TypeId &t2) {
return t1.unwrap() == t2.unwrap();
}
/// Get the max group size.
uint32_t group_max_size() const noexcept;
static uint32_t group_max_size(const RawCode &raw_code) noexcept;
static uint32_t group_max_size(const CommonCode &common_code) noexcept;
inline bool operator!=(const TypeId &t1, const TypeId &t2) {
return t1.unwrap() != t2.unwrap();
}
/// Get all seeds of the current type_id.
std::vector<CommonCode> seeds() const noexcept;
inline bool operator==(const TypeId::block_num_t &b1, const TypeId::block_num_t &b2) {
return (b1.n_1x1 == b2.n_1x1) && (b1.n_1x2 == b2.n_1x2) && (b1.n_2x1 == b2.n_2x1);
}
/// Search for all cases of the current type_id.
std::vector<CommonCode> cases() const noexcept;
inline bool operator!=(const TypeId::block_num_t &b1, const TypeId::block_num_t &b2) {
return (b1.n_1x1 != b2.n_1x1) || (b1.n_1x2 != b2.n_1x2) || (b1.n_2x1 != b2.n_2x1);
}
/// Calculate all groups of the current type_id.
std::vector<std::vector<CommonCode>> groups() const noexcept;
};
/// ---------------------------------------- Group ID -----------------------------------------
@ -68,82 +65,78 @@ class GroupId {
TypeId type_id_;
uint32_t group_id_;
static uint32_t group_id(uint32_t type_id, const CommonCode &seed) noexcept;
public:
GroupId(uint32_t type_id, uint32_t group_id);
GroupId(const TypeId &type_id, uint32_t group_id);
explicit GroupId(const RawCode &raw_code) noexcept;
explicit GroupId(const CommonCode &common_code) noexcept;
/// Release raw type id / group id value.
/// Release raw type_id / group_id value.
constexpr uint32_t unwrap() const noexcept { return group_id_; }
constexpr uint32_t type_id() const noexcept { return type_id_.unwrap(); }
/// Get the size of the specified group.
/// Get the size of the current group.
uint32_t size() const noexcept;
static uint32_t size(const RawCode &raw_code) noexcept;
static uint32_t size(const CommonCode &common_code) noexcept;
/// Get the minimum CommonCode of the specified group.
/// Get the minimum CommonCode of the current group.
CommonCode seed() const noexcept;
static CommonCode seed(const RawCode &raw_code) noexcept;
static CommonCode seed(const CommonCode &common_code) noexcept;
};
inline bool operator==(const GroupId &g1, const GroupId &g2) {
return g1.type_id() == g2.type_id() && g1.unwrap() == g2.unwrap();
}
inline bool operator!=(const GroupId &g1, const GroupId &g2) {
return g1.type_id() != g2.type_id() || g1.unwrap() != g2.unwrap();
}
/// Calculate the specified group.
std::vector<RawCode> cases() const noexcept;
};
/// ------------------------------------------ Group ------------------------------------------
class Group {
public:
/// Search for all derivatives that a case can produce.
static std::vector<RawCode> cases(const RawCode &raw_code) noexcept;
static std::vector<RawCode> cases(const CommonCode &common_code) noexcept;
/// Calculate the specified group in the specified group_id.
static std::vector<CommonCode> build_group(const GroupId &group_id);
/// Calculate all groups in the specified type_id.
static std::vector<std::vector<CommonCode>> build_groups(const TypeId &type_id);
/// ----------------------------------- group info ------------------------------------
struct group_info_t {
struct info_t {
uint16_t type_id;
uint16_t group_id;
uint32_t group_index;
};
/// Search for all derivatives that a case can produce.
static std::vector<RawCode> cases(const RawCode &raw_code) noexcept;
static std::vector<RawCode> cases(const CommonCode &common_code) noexcept;
/// Get group info according to specified case.
static group_info_t group_info(const RawCode &raw_code);
static group_info_t group_info(const CommonCode &common_code);
static info_t info(const RawCode &raw_code);
static info_t info(const CommonCode &common_code);
/// Get the CommonCode according to the group info.
static CommonCode group_case(const group_info_t &group_info);
// TODO: group_size
/// -------------------------------- xxxxxxxxxxxxxxxxx --------------------------------
static CommonCode resolve(const GroupId &group_id, uint32_t group_index);
};
// TODO: update max_group_size in TYPE_ID_MAX_GROUP
/// ---------------------------------------- Operators ----------------------------------------
static uint32_t group_max_size(const TypeId &type_id) {
return 65535 * 8;
}
inline bool operator==(const TypeId &t1, const TypeId &t2) {
return t1.unwrap() == t2.unwrap();
}
static uint32_t group_max_size(const RawCode &raw_code) {
return group_max_size(TypeId(raw_code));
}
inline bool operator!=(const TypeId &t1, const TypeId &t2) {
return t1.unwrap() != t2.unwrap();
}
static uint32_t group_max_size(const CommonCode &common_code) {
return group_max_size(TypeId(common_code));
}
inline bool operator==(const GroupId &g1, const GroupId &g2) {
return g1.type_id() == g2.type_id() && g1.unwrap() == g2.unwrap();
}
// TODO: group_num
inline bool operator!=(const GroupId &g1, const GroupId &g2) {
return g1.type_id() != g2.type_id() || g1.unwrap() != g2.unwrap();
}
};
inline bool operator==(const TypeId::block_num_t &b1, const TypeId::block_num_t &b2) {
return (b1.n_1x1 == b2.n_1x1) && (b1.n_1x2 == b2.n_1x2) && (b1.n_2x1 == b2.n_2x1);
}
inline bool operator!=(const TypeId::block_num_t &b1, const TypeId::block_num_t &b2) {
return (b1.n_1x1 != b2.n_1x1) || (b1.n_1x2 != b2.n_1x2) || (b1.n_2x1 != b2.n_2x1);
}
} // namespace klotski

52
src/klotski_core/group/group_info.cc

@ -7,46 +7,50 @@
namespace klotski {
Group::group_info_t Group::group_info(const RawCode &raw_code) {
/// ----------------------------------------- Type ID -----------------------------------------
// TODO: function body
uint32_t TypeId::group_num() const noexcept {
return TYPE_ID_GROUP_NUM[type_id_];
}
return Group::group_info_t();
uint32_t TypeId::group_num(const RawCode &raw_code) noexcept {
return TypeId(raw_code).group_num();
}
Group::group_info_t Group::group_info(const CommonCode &common_code) {
uint32_t TypeId::group_num(const CommonCode &common_code) noexcept {
return TypeId(common_code).group_num();
}
auto type_id = TypeId(common_code).unwrap();
uint32_t TypeId::group_max_size() const noexcept {
return TYPE_ID_GROUP_MAX_SIZE[type_id_];
}
std::cout << type_id << std::endl;
std::cout << "group num: " << TYPE_ID_GROUP_NUM[type_id] << std::endl;
std::cout << "offset: " << TYPE_ID_OFFSET[type_id] << std::endl;
uint32_t TypeId::group_max_size(const RawCode &raw_code) noexcept {
return TypeId(raw_code).group_max_size();
}
uint32_t start = TYPE_ID_OFFSET[type_id];
uint32_t end = start + TYPE_ID_GROUP_NUM[type_id];
std::cout << "range: [" << start << ", " << end << ")" << std::endl;
uint32_t TypeId::group_max_size(const CommonCode &common_code) noexcept {
return TypeId(common_code).group_max_size();
}
/// ------------------------------------------ Group ------------------------------------------
auto group = Group::cases(common_code);
std::vector<CommonCode> g(group.begin(), group.end());
auto seed = std::min_element(g.begin(), g.end());
std::cout << "seed: " << *seed << std::endl;
Group::info_t Group::info(const RawCode &raw_code) {
auto t = std::lower_bound(GROUP_SEEDS + start, GROUP_SEEDS + end, seed->unwrap());
auto tmp_index = t - GROUP_SEEDS;
std::cout << "tmp index: " << tmp_index;
std::cout << " (" << CommonCode(GROUP_SEEDS[tmp_index]) << ")" << std::endl;
// TODO: function body
return {};
}
auto group_id = GROUP_SEEDS_INDEX_REV[tmp_index];
std::cout << "group id: " << group_id << std::endl;
Group::info_t Group::info(const CommonCode &common_code) {
// TODO: function body
return Group::group_info_t();
return {};
}
CommonCode Group::group_case(const Group::group_info_t &group_info) {
CommonCode Group::resolve(const GroupId &group_id, uint32_t group_index) {
// TODO: check group info
// TODO: check group index
// TODO: function body

25
src/klotski_core/group/seeds.cc

@ -7,8 +7,15 @@
namespace klotski {
CommonCode GroupId::seed(const CommonCode &common_code) noexcept {
return seed(common_code.to_raw_code());
std::vector<CommonCode> TypeId::seeds() const noexcept {
auto offset = GROUP_SEEDS + TYPE_ID_OFFSET[type_id_]; // type id offset
return {offset, offset + TYPE_ID_GROUP_NUM[type_id_]};
}
CommonCode GroupId::seed() const noexcept { // group_id -> seed
auto offset = TYPE_ID_OFFSET[type_id_.unwrap()]; // type id offset
auto index = offset + GROUP_SEEDS_INDEX[offset + group_id_];
return CommonCode::unsafe_create(GROUP_SEEDS[index]);
}
CommonCode GroupId::seed(const RawCode &raw_code) noexcept {
@ -17,15 +24,15 @@ CommonCode GroupId::seed(const RawCode &raw_code) noexcept {
return *std::min_element(group.begin(), group.end());
}
CommonCode GroupId::seed() const noexcept {
auto offset = TYPE_ID_OFFSET[type_id_.unwrap()]; // type id offset
auto index = offset + GROUP_SEEDS_INDEX[offset + group_id_];
return CommonCode::unsafe_create(GROUP_SEEDS[index]);
CommonCode GroupId::seed(const CommonCode &common_code) noexcept {
return seed(common_code.to_raw_code());
}
std::vector<CommonCode> TypeId::seeds() const noexcept {
auto offset = GROUP_SEEDS + TYPE_ID_OFFSET[type_id_]; // type id offset
return {offset, offset + TYPE_ID_GROUP_NUM[type_id_]};
uint32_t GroupId::group_id(uint32_t type_id, const CommonCode &seed) noexcept { // seed -> group_id
auto start = GROUP_SEEDS + TYPE_ID_OFFSET[type_id];
auto end = start + TYPE_ID_GROUP_NUM[type_id];
auto index = std::lower_bound(start, end, seed.unwrap()) - GROUP_SEEDS;
return GROUP_SEEDS_INDEX_REV[index];
}
} // namespace klotski

3
test/group/basic_id.cc

@ -85,6 +85,9 @@ TEST(Group, group_id) {
EXPECT_EQ(GroupId(type_id, TYPE_ID_GROUP_NUM[type_id]).unwrap(), -1);
} catch (...) {} // should panic
}
// TODO: test GroupId(...)
}
TEST(Group, operators) {

2
test/group/build_cases.cc

@ -29,7 +29,7 @@ const char GROUP_INFO_MD5[] = "976bf22530085210e68a6a4e67053506";
TEST(Group, all_cases) {
std::array<std::vector<CommonCode>, TYPE_ID_LIMIT> all_cases;
auto build = [&all_cases](TypeId type_id) {
auto cases = type_id.all_cases(); // build test data
auto cases = type_id.cases(); // build test data
EXPECT_EQ(cases.size(), TYPE_ID_SIZE[type_id.unwrap()]); // verify cases number
for (auto &&common_code : cases) {
EXPECT_EQ(TypeId(common_code), type_id); // verify type id

Loading…
Cancel
Save