diff --git a/src/klotski_core/group/basic_id.cc b/src/klotski_core/group/basic_id.cc index 7fc3f71..01872ff 100644 --- a/src/klotski_core/group/basic_id.cc +++ b/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 diff --git a/src/klotski_core/group/build_cases.cc b/src/klotski_core/group/build_cases.cc index 365a649..21ef7e4 100644 --- a/src/klotski_core/group/build_cases.cc +++ b/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 Group::cases(const CommonCode &common_code) noexcept { - return cases(common_code.to_raw_code()); -} - -std::vector Group::build_group(const GroupId &group_id) { - auto cases = Group::cases(group_id.seed()); - return {cases.begin(), cases.end()}; -} - -std::vector TypeId::all_cases() const noexcept { +std::vector TypeId::cases() const noexcept { std::vector ranges; // basic ranges of type_id ranges.reserve(TYPE_ID_SIZE[type_id_]); // over-allocation @@ -63,10 +48,56 @@ std::vector TypeId::all_cases() const noexcept { return all_cases; } +std::vector> TypeId::groups() const noexcept { + auto all_cases = cases(); + std::vector> 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 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 &v1, const std::vector &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 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 cache({raw_code.unwrap()}); absl::flat_hash_map cases; // - 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 Group::cases(const CommonCode &common_code) noexcept { + return cases(common_code.to_raw_code()); +} + std::vector Group::cases(const RawCode &raw_code) noexcept { std::queue cache({raw_code.unwrap()}); absl::flat_hash_map cases; // - 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 Group::cases(const RawCode &raw_code) noexcept { return result; } -std::vector> Group::build_groups(const TypeId &type_id) { - auto all_cases = type_id.all_cases(); - std::vector> 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 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 &v1, const std::vector &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 diff --git a/src/klotski_core/group/group.h b/src/klotski_core/group/group.h index 77bbf0d..f74282b 100644 --- a/src/klotski_core/group/group.h +++ b/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 seeds() const noexcept; - - /// Search for all cases of the specified type_id. - std::vector 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 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 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> 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 cases() const noexcept; +}; /// ------------------------------------------ Group ------------------------------------------ class Group { public: - /// Search for all derivatives that a case can produce. - static std::vector cases(const RawCode &raw_code) noexcept; - static std::vector cases(const CommonCode &common_code) noexcept; - - /// Calculate the specified group in the specified group_id. - static std::vector build_group(const GroupId &group_id); - - /// Calculate all groups in the specified type_id. - static std::vector> 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 cases(const RawCode &raw_code) noexcept; + static std::vector 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 diff --git a/src/klotski_core/group/group_info.cc b/src/klotski_core/group/group_info.cc index 07807d4..33a08a9 100644 --- a/src/klotski_core/group/group_info.cc +++ b/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 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 diff --git a/src/klotski_core/group/seeds.cc b/src/klotski_core/group/seeds.cc index 8a1d783..162982c 100644 --- a/src/klotski_core/group/seeds.cc +++ b/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 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 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 diff --git a/test/group/basic_id.cc b/test/group/basic_id.cc index 2f8e943..a287584 100644 --- a/test/group/basic_id.cc +++ b/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) { diff --git a/test/group/build_cases.cc b/test/group/build_cases.cc index 7b8628d..8be861d 100644 --- a/test/group/build_cases.cc +++ b/test/group/build_cases.cc @@ -29,7 +29,7 @@ const char GROUP_INFO_MD5[] = "976bf22530085210e68a6a4e67053506"; TEST(Group, all_cases) { std::array, 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