Browse Source

feat: GroupId module

master
Dnomd343 2 years ago
parent
commit
4ecccce96c
  1. 2
      src/klotski_core/group/CMakeLists.txt
  2. 20
      src/klotski_core/group/basic_id.cc
  3. 74
      src/klotski_core/group/block_num_.cc
  4. 2
      src/klotski_core/group/build_cases.cc
  5. 5
      src/klotski_core/group/group.cc
  6. 55
      src/klotski_core/group/group.h
  7. 2
      src/klotski_core/group/group_info.cc
  8. 21
      src/klotski_core/group/seeds.cc
  9. 2
      test/CMakeLists.txt
  10. 25
      test/group/basic_id.cc
  11. 9
      test/group/build_cases.cc

2
src/klotski_core/group/CMakeLists.txt

@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 3.0)
add_library(group OBJECT seeds.cc group.cc block_num.cc block_num_.cc build_cases.cc group_info.cc)
add_library(group OBJECT seeds.cc basic_id.cc build_cases.cc group_info.cc)

20
src/klotski_core/group/block_num.cc → src/klotski_core/group/basic_id.cc

@ -8,6 +8,8 @@ namespace klotski {
using Common::range_reverse;
/// ----------------------------------------- Type ID -----------------------------------------
TypeId::TypeId(uint32_t type_id) {
if (type_id >= TYPE_ID_LIMIT) { // invalid type id
throw std::invalid_argument("type id overflow");
@ -31,6 +33,8 @@ uint32_t TypeId::to_type_id(block_num_t &&block_num) noexcept {
return std::lower_bound(TYPE_ID_INDEX, TYPE_ID_INDEX + TYPE_ID_LIMIT, flag) - TYPE_ID_INDEX;
}
/// -------------------------------------- Block Number ---------------------------------------
TypeId::block_num_t TypeId::block_num() const noexcept {
auto flag = TYPE_ID_INDEX[type_id_];
auto n_2x1 = (flag >> 4) & 0b111;
@ -79,4 +83,20 @@ TypeId::block_num_t TypeId::block_num(const CommonCode &common_code) noexcept {
return result;
}
/// ---------------------------------------- Group ID -----------------------------------------
GroupId::GroupId(uint32_t type_id, uint32_t group_id) : type_id_(type_id) {
if (group_id >= TYPE_ID_GROUP_NUM[type_id]) {
throw std::invalid_argument("group id overflow");
}
group_id_ = group_id;
}
GroupId::GroupId(const TypeId &type_id, uint32_t group_id) : type_id_(type_id) {
if (group_id >= TYPE_ID_GROUP_NUM[type_id.unwrap()]) {
throw std::invalid_argument("group id overflow");
}
group_id_ = group_id;
}
} // namespace klotski

74
src/klotski_core/group/block_num_.cc

@ -1,74 +0,0 @@
#include <group.h>
#include "common.h"
#include "type_id.h"
namespace klotski {
using Common::range_reverse;
uint32_t Group::type_id(const RawCode &raw_code) {
return type_id(block_num(raw_code));
}
uint32_t Group::type_id(const CommonCode &common_code) {
return type_id(block_num(common_code));
}
uint32_t Group::type_id(const block_num_t &block_num) {
/// flag -> ... 0000 0xxx 0xxx xxxx
/// n_x2x n_2x1 n_1x1
auto n_x2x = block_num.n_1x2 + block_num.n_2x1;
auto flag = (n_x2x << 8) | (block_num.n_2x1 << 4) | block_num.n_1x1;
return std::lower_bound(TYPE_ID_INDEX, TYPE_ID_INDEX + TYPE_ID_LIMIT, flag) - TYPE_ID_INDEX;
}
Group::block_num_t Group::block_num(uint32_t type_id) {
auto flag = TYPE_ID_INDEX[type_id];
uint8_t n_x2x = flag >> 8;
uint8_t n_2x1 = (flag >> 4) & 0b1111;
return block_num_t {
.n_1x1 = static_cast<uint8_t>(flag & 0b1111),
.n_1x2 = static_cast<uint8_t>(n_x2x - n_2x1),
.n_2x1 = n_2x1,
};
}
Group::block_num_t Group::block_num(const RawCode &raw_code) {
block_num_t result;
auto tmp = raw_code.unwrap();
for (int addr = 0; addr < 20; ++addr, tmp >>= 3) {
switch (tmp & 0b111) {
case B_1x1:
++result.n_1x1;
continue;
case B_1x2:
++result.n_1x2;
continue;
case B_2x1:
++result.n_2x1;
continue;
}
}
return result;
}
Group::block_num_t Group::block_num(const CommonCode &common_code) {
block_num_t result;
auto range = range_reverse((uint32_t)common_code.unwrap());
for (; range; range >>= 2) {
switch (range & 0b11) {
case 0b01: /// 1x2 block
++result.n_1x2;
continue;
case 0b10: /// 2x1 block
++result.n_2x1;
continue;
case 0b11: /// 1x1 block
++result.n_1x1;
continue;
}
}
return result;
}
} // namespace klotski

2
src/klotski_core/group/build_cases.cc

@ -15,7 +15,7 @@ using Common::check_range;
using Common::range_reverse;
std::vector<CommonCode> Group::all_cases(uint32_t type_id) {
auto tmp = block_num(type_id);
auto tmp = TypeId(type_id).block_num();
std::vector<uint32_t> ranges; // basic ranges of type_id
BasicRanges::generate(ranges, { // generate target ranges
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00

5
src/klotski_core/group/group.cc

@ -1,5 +0,0 @@
#include "group.h"
namespace klotski {
} // namespace klotski

55
src/klotski_core/group/group.h

@ -8,6 +8,8 @@ namespace klotski {
const uint32_t TYPE_ID_LIMIT = 203;
/// ----------------------------------------- Type ID -----------------------------------------
class TypeId {
public:
/// 1. n_1x1 + (n_1x2 + n_2x1) * 2 <= 14
@ -48,34 +50,41 @@ inline bool operator!=(const TypeId::block_num_t &b1, const TypeId::block_num_t
return (b1.n_1x1 != b2.n_1x1) || (b1.n_1x2 != b2.n_1x2) || (b1.n_2x1 != b2.n_2x1);
}
class Group {
/// -------------------------------- block statistics ---------------------------------
/// ---------------------------------------- Group ID -----------------------------------------
class GroupId {
TypeId type_id_;
uint32_t group_id_;
public:
/// 1. n_1x1 + (n_1x2 + n_2x1) * 2 <= 14
/// 2. (n_1x1 != 0) && (n_2x1 != 7)
struct block_num_t {
uint8_t n_1x1 = 0; /// [0, 14]
uint8_t n_1x2 = 0; /// [0, 7]
uint8_t n_2x1 = 0; /// [0, 7]
};
GroupId(uint32_t type_id, uint32_t group_id);
GroupId(const TypeId &type_id, uint32_t group_id);
/// Get type_id value (0 ~ 202).
static uint32_t type_id(const RawCode &raw_code);
static uint32_t type_id(const block_num_t &block_num);
static uint32_t type_id(const CommonCode &common_code);
/// 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 number of klotski blocks.
static block_num_t block_num(uint32_t type_id);
static block_num_t block_num(const RawCode &raw_code);
static block_num_t block_num(const CommonCode &common_code);
inline bool operator==(const GroupId &g1, const GroupId &g2) {
return g1.type_id() == g2.type_id() && g1.unwrap() == g2.unwrap();
}
/// --------------------------------- cases expansion ---------------------------------
inline bool operator!=(const GroupId &g1, const GroupId &g2) {
return g1.type_id() != g2.type_id() || g1.unwrap() != g2.unwrap();
}
/// ------------------------------------------ Group ------------------------------------------
class Group {
public:
/// ----------------------------------- group seeds -----------------------------------
static CommonCode group_seed(const RawCode &raw_code);
static CommonCode group_seed(const CommonCode &common_code);
static CommonCode group_seed(uint32_t type_id, uint32_t group_id);
static std::vector<CommonCode> group_seeds(uint32_t type_id);
/// Get all seeds in the specified type id.
static std::vector<CommonCode> group_seeds(const TypeId &type_id);
/// --------------------------------- cases expansion ---------------------------------
@ -127,12 +136,4 @@ public:
};
inline bool operator==(const Group::block_num_t &b1, const Group::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 Group::block_num_t &b1, const Group::block_num_t &b2) {
return (b1.n_1x1 != b2.n_1x1) || (b1.n_1x2 != b2.n_1x2) || (b1.n_2x1 != b2.n_2x1);
}
}

2
src/klotski_core/group/group_info.cc

@ -16,7 +16,7 @@ Group::group_info_t Group::group_info(const RawCode &raw_code) {
Group::group_info_t Group::group_info(const CommonCode &common_code) {
auto type_id = Group::type_id(common_code);
auto type_id = TypeId(common_code).unwrap();
std::cout << type_id << std::endl;
std::cout << "group num: " << TYPE_ID_GROUP_NUM[type_id] << std::endl;

21
src/klotski_core/group/seeds.cc

@ -6,6 +6,8 @@
namespace klotski {
CommonCode Group::group_seed(uint32_t type_id, uint32_t group_id) {
// TODO: check value
@ -31,4 +33,23 @@ CommonCode Group::group_seed(uint32_t type_id, uint32_t group_id) {
return seed;
}
std::vector<CommonCode> Group::group_seeds(const TypeId &type_id) {
auto offset = GROUP_SEEDS + TYPE_ID_OFFSET[type_id.unwrap()]; // group id offset
return {offset, offset + TYPE_ID_GROUP_NUM[type_id.unwrap()]};
}
CommonCode Group::group_seed(const RawCode &raw_code) {
return CommonCode(0);
}
CommonCode Group::group_seed(const CommonCode &common_code) {
return CommonCode(0);
}
} // namespace klotski

2
test/CMakeLists.txt

@ -61,7 +61,7 @@ add_test(NAME core COMMAND test_core)
#######################################################################################
set(TEST_GROUP_SRC
group/block_num.cc
group/basic_id.cc
group/build_cases.cc
)
add_executable(test_group ${TEST_GROUP_SRC})

25
test/group/block_num.cc → test/group/basic_id.cc

@ -1,16 +1,19 @@
#include <thread>
#include "md5.h"
#include "group.h"
#include "type_id.h"
#include "all_cases.h"
#include "gtest/gtest.h"
using klotski::TypeId;
using klotski::GroupId;
using klotski::RawCode;
using klotski::AllCases;
using klotski::CommonCode;
using klotski::TYPE_ID_LIMIT;
using klotski::ALL_CASES_SIZE;
using klotski::TYPE_ID_GROUP_NUM;
const char BLOCK_NUM_MD5[] = "46a7b3af6d039cbe2f7eaebdd196c6a2";
@ -19,7 +22,7 @@ TEST(Group, type_id) {
EXPECT_EQ(TypeId(type_id).unwrap(), type_id);
}
try {
EXPECT_EQ(TypeId(TYPE_ID_LIMIT).unwrap(), TYPE_ID_LIMIT + 1);
EXPECT_EQ(TypeId(TYPE_ID_LIMIT).unwrap(), -1);
} catch (...) {} // should panic
auto test = [](uint64_t head) {
@ -69,3 +72,23 @@ TEST(Group, block_num) {
auto block_num_md5 = md5(block_num_str.c_str(), block_num_str.size());
EXPECT_STREQ(block_num_md5.c_str(), BLOCK_NUM_MD5); // verify md5
}
TEST(Group, group_id) {
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
for (uint32_t group_id = 0; group_id < TYPE_ID_GROUP_NUM[type_id]; ++group_id) {
auto gid = GroupId(type_id, group_id);
EXPECT_EQ(gid, GroupId(TypeId(type_id), group_id));
EXPECT_EQ(gid.type_id(), type_id);
EXPECT_EQ(gid.unwrap(), group_id);
}
try {
EXPECT_EQ(GroupId(type_id, TYPE_ID_GROUP_NUM[type_id]).unwrap(), -1);
} catch (...) {} // should panic
}
}
TEST(Group, operators) {
// TODO: TypeId
// TODO: block_num_t
// TODO: GroupId
}

9
test/group/build_cases.cc

@ -10,6 +10,7 @@
#include "group/group_seeds.h"
using klotski::Group;
using klotski::TypeId;
using klotski::AllCases;
using klotski::RawCode;
@ -35,7 +36,7 @@ TEST(Group, all_cases) {
for (uint32_t id = 0; id < TYPE_ID_LIMIT; ++id) {
EXPECT_EQ(all_cases[id].size(), TYPE_ID_SIZE[id]); // verify cases number
for (auto &&common_code : all_cases[id]) {
EXPECT_EQ(Group::type_id(common_code), id); // verify type id
EXPECT_EQ(TypeId(common_code).unwrap(), id); // verify type id
combine.emplace_back(common_code.unwrap());
}
std::is_sorted(all_cases[id].begin(), all_cases[id].end()); // verify data order
@ -55,9 +56,9 @@ TEST(Group, group_cases) {
std::vector<CommonCode> group(group_raw.begin(), group_raw.end()); // convert as CommonCodes
EXPECT_EQ(seed, std::min_element(group.begin(), group.end())->unwrap()); // confirm min seed
uint32_t type_id = Group::type_id(CommonCode(seed)); // current type id
uint32_t type_id = TypeId(CommonCode(seed)).unwrap(); // current type id
for (auto &&elem : group) {
EXPECT_EQ(Group::type_id(elem), type_id); // verify type id of group cases
EXPECT_EQ(TypeId(elem).unwrap(), type_id); // verify type id of group cases
}
return group;
};
@ -110,7 +111,7 @@ TEST(Group, build_groups) {
.group_id = static_cast<uint16_t>(id),
.group_index = index,
};
EXPECT_EQ(Group::type_id(groups[id][index]), type_id); // verify type id
EXPECT_EQ(TypeId(groups[id][index]).unwrap(), type_id); // verify type id
}
group_seeds.emplace_back(groups[id][0]); // record seed
}

Loading…
Cancel
Save