Browse Source

feat: group all cases

master
Dnomd343 2 years ago
parent
commit
4efb519a7b
  1. 11
      src/klotski_core/all_cases/all_cases.h
  2. 10
      src/klotski_core/all_cases/basic_ranges.cc
  3. 25
      src/klotski_core/all_cases/basic_ranges.h
  4. 47
      src/klotski_core/ffi/tmain.cc
  5. 2
      src/klotski_core/group/CMakeLists.txt
  6. 73
      src/klotski_core/group/block_num.cc
  7. 97
      src/klotski_core/group/group.cc
  8. 5
      src/klotski_core/group/group.h
  9. 61
      test/group/group.cc

11
src/klotski_core/all_cases/all_cases.h

@ -37,7 +37,7 @@ const uint32_t ALL_CASES_SIZE[16] = {
const uint32_t ALL_CASES_SIZE_SUM = 29334498;
class AllCases : public BasicRanges {
class AllCases : private BasicRanges {
public:
/// Trigger the build process.
static void build();
@ -46,7 +46,7 @@ public:
static Status status() noexcept;
/// Blocking access to constructed data.
static const std::vector<uint32_t> (&fetch())[16];
static const basic_ranges_t (&fetch())[16];
/// Export all possible common codes.
static std::vector<CommonCode> release();
@ -54,9 +54,14 @@ public:
private:
static bool available_;
static std::mutex building_;
static std::vector<uint32_t> data_[16];
static basic_ranges_t data_[16];
static void build_data();
public:
using BasicRanges::NOT_INIT;
using BasicRanges::BUILDING;
using BasicRanges::AVAILABLE;
};
} // namespace klotski

10
src/klotski_core/all_cases/basic_ranges.cc

@ -10,9 +10,9 @@ using Common::range_reverse;
/// static variable initialize
std::mutex BasicRanges::building_;
bool BasicRanges::available_ = false;
std::vector<uint32_t> BasicRanges::data_;
BasicRanges::basic_ranges_t BasicRanges::data_;
const std::vector<uint32_t>& BasicRanges::fetch() {
const BasicRanges::basic_ranges_t& BasicRanges::fetch() {
if (status() != AVAILABLE) {
build();
}
@ -50,7 +50,7 @@ void BasicRanges::build_data() {
for (int n = 0; n <= 7; ++n) // number of 1x2 and 2x1 block -> 0 ~ 7
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) // number of 2x1 block -> 0 ~ n
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) // number of 1x1 block -> 0 ~ (14 - 2n)
generate(generate_t { // generate target ranges
generate(data_, generate_t { // generate target ranges
.n1 = 16 - n * 2 - n_1x1, /// space -> 00
.n2 = n - n_2x1, /// 1x2 -> 01
.n3 = n_2x1, /// 2x1 -> 10
@ -65,7 +65,7 @@ void BasicRanges::build_data() {
}
/// Generate basic-ranges of specific type.
void BasicRanges::generate(generate_t info) {
void BasicRanges::generate(basic_ranges_t &release, generate_t info) {
constexpr auto MASK_01 = (uint32_t)0b01 << 30;
constexpr auto MASK_10 = (uint32_t)0b10 << 30;
constexpr auto MASK_11 = (uint32_t)0b11 << 30;
@ -88,7 +88,7 @@ void BasicRanges::generate(generate_t info) {
while (!cache.empty()) { // queue without element -> work complete
auto current = cache.front();
if (!current.nx) { // both n1, n2, n3, n4 -> 0
data_.emplace_back(current.prefix); // release prefix as basic range
release.emplace_back(current.prefix); // release prefix as basic range
cache.pop();
continue; // skip current search
}

25
src/klotski_core/all_cases/basic_ranges.h

@ -44,6 +44,7 @@ public:
BUILDING,
AVAILABLE,
};
typedef std::vector<uint32_t> basic_ranges_t;
/// Trigger the build process, from `NOT_INIT` to `BUILDING`.
static void build();
@ -52,22 +53,26 @@ public:
static Status status() noexcept;
/// Blocking access to constructed data.
static const std::vector<uint32_t>& fetch();
static const basic_ranges_t& fetch();
private:
struct generate_t {
int n1; // number of `00`
int n2; // number of `01`
int n3; // number of `10`
int n4; // number of `11`
};
static bool available_;
static std::mutex building_;
static std::vector<uint32_t> data_;
static basic_ranges_t data_;
static void build_data();
static void generate(generate_t info);
public:
/// The number of types of blocks.
struct generate_t {
int n1; // number of `00` -> space
int n2; // number of `01` -> 1x2 block
int n3; // number of `10` -> 2x1 block
int n4; // number of `11` -> 1x1 block
};
/// Generate all basic-ranges of the specified type.
static void generate(basic_ranges_t &release, generate_t info);
};
} // namespace klotski

47
src/klotski_core/ffi/tmain.cc

@ -21,8 +21,55 @@ using klotski::CommonCode;
using klotski::Benchmark;
using klotski::BasicRanges;
void tmain() {
// std::vector<CommonCode> ok;
// for (auto &&c : AllCases::release()) {
// if (Group::type_id(c) == 123) {
// ok.emplace_back(c);
// }
// }
// std::cout << ok.size() << std::endl;
// std::cout << Group::all_cases(123).size() << std::endl;
// std::vector<CommonCode> err;
// auto ret = Group::all_cases(123);
// std::cout << ret.size() << std::endl;
// err.reserve(ret.size());
// for (auto &&r : ret) {
// if (Group::type_id(r) != 123) {
// std::cout << r << std::endl;
// }
// err.emplace_back(r);
// }
// uint32_t sum = 0;
// for (uint32_t type_id = 0; type_id < 204; ++type_id) {
// sum += Group::all_cases(type_id).size();
// auto tmp = Group::block_num(type_id);
//
// std::vector<uint32_t> ranges;
//
// BasicRanges::generate(ranges, BasicRanges::generate_t { // generate target ranges
// .n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
// .n2 = tmp.n_1x2, /// 1x2 -> 01
// .n3 = tmp.n_2x1, /// 2x1 -> 10
// .n4 = tmp.n_1x1, /// 1x1 -> 11
// });
// sum += ranges.size();
// }
// std::cout << "sum = " << sum << std::endl;
uint32_t sum = 0;
for (uint32_t type_id = 0; type_id < 204; ++type_id) {
sum += Group::all_cases(type_id).size();
}
std::cout << "sum = " << sum << std::endl;
// auto r = Group::block_num(123);
// std::cout << (int)r.n_1x1 << " " << (int)r.n_1x2 << " " << (int)r.n_2x1 << std::endl;

2
src/klotski_core/group/CMakeLists.txt

@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 3.0)
add_library(group OBJECT group.cc)
add_library(group OBJECT group.cc block_num.cc)

73
src/klotski_core/group/block_num.cc

@ -0,0 +1,73 @@
#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) {
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 + 204, 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

97
src/klotski_core/group/group.cc

@ -2,76 +2,59 @@
#include <vector>
#include "core.h"
#include "group.h"
#include "common.h"
#include "absl/container/flat_hash_map.h"
#include "type_id.h"
#include "common.h"
namespace klotski {
using Common::range_reverse;
using klotski::AllCases;
using klotski::BasicRanges;
uint32_t Group::type_id(const RawCode &raw_code) {
return type_id(block_num(raw_code));
}
using klotski::Common::check_range;
using klotski::Common::range_reverse;
uint32_t Group::type_id(const CommonCode &common_code) {
return type_id(block_num(common_code));
}
std::vector<CommonCode> Group::all_cases(uint32_t type_id) {
uint32_t Group::type_id(const block_num_t &block_num) {
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 + 204, flag) - TYPE_ID_INDEX;
}
auto tmp = block_num(type_id);
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,
};
}
std::vector<uint32_t> ranges;
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;
}
BasicRanges::generate(ranges, BasicRanges::generate_t { // generate target ranges
.n1 = 16 - tmp.n_1x1 - (tmp.n_1x2 + tmp.n_2x1) * 2, /// space -> 00
.n2 = tmp.n_1x2, /// 1x2 -> 01
.n3 = tmp.n_2x1, /// 2x1 -> 10
.n4 = tmp.n_1x1, /// 1x1 -> 11
});
for (auto &range : ranges) {
range = range_reverse(range); // basic ranges reversed
}
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;
// std::cout << ranges.size() << std::endl;
std::vector<CommonCode> all_cases;
for (uint64_t head = 0; head < 15; ++head) { // address of 2x2 block
/// head -> 0/1/2 / 4/5/6 / 8/9/10 / 12/13/14
if ((head & 0b11) == 0b11) {
++head; // skip invalid address
}
/// head(4-bit) + basic-range(32-bit) --check--> valid cases
for (auto &&range : ranges) {
if (!check_range(head, range)) { // case valid
all_cases.emplace_back(CommonCode::create(
head << 32 | range_reverse(range)
));
// range_reverse(range); // release valid cases
}
}
}
return result;
return all_cases;
}
std::vector<RawCode> Group::group_cases(const RawCode &seed) {

5
src/klotski_core/group/group.h

@ -9,8 +9,8 @@ namespace klotski {
const uint32_t TYPE_ID_LIMIT = 204;
class Group {
/// ---------------------------- block statistics -----------------------------
public:
struct block_num_t {
uint8_t n_1x1 = 0;
uint8_t n_1x2 = 0;
@ -25,12 +25,15 @@ public:
static block_num_t block_num(const RawCode &raw_code);
static block_num_t block_num(const CommonCode &common_code);
/// ---------------------------- xxxxxxxxxxxxxxxxx ----------------------------
// static uint32_t max_group_size(uint32_t type_id);
static uint32_t max_group_size(const RawCode &raw_code) {
return 65535 * 8;
};
static std::vector<CommonCode> all_cases(uint32_t type_id);
static std::vector<RawCode> group_cases(const RawCode &seed);
};

61
test/group/group.cc

@ -12,18 +12,16 @@ using klotski::ALL_CASES_SIZE_SUM;
const char BLOCK_NUM_MD5[] = "46a7b3af6d039cbe2f7eaebdd196c6a2";
TEST(Group, block_num) {
TEST(Group, type_id) {
std::thread threads[16];
std::string block_num_datas[16];
auto test = [&block_num_datas](uint64_t head) {
char buffer[13];
for (auto &&range: AllCases::fetch()[head]) {
auto test = [](uint64_t head) {
for (const auto &range : AllCases::fetch()[head]) {
auto common_code = CommonCode::unsafe_create(head << 32 | range);
auto tmp = Group::block_num(common_code);
EXPECT_EQ(tmp, Group::block_num(common_code.to_raw_code()));
sprintf(buffer, "%d,%d,%d\n", tmp.n_1x2 + tmp.n_2x1, tmp.n_1x1, tmp.n_2x1);
block_num_datas[head] += buffer;
auto type_id = Group::type_id(common_code); // found type id
EXPECT_LT(type_id, TYPE_ID_LIMIT);
EXPECT_EQ(type_id, Group::type_id(common_code.to_raw_code()));
EXPECT_EQ(type_id, Group::type_id(Group::block_num(common_code)));
EXPECT_EQ(Group::block_num(type_id), Group::block_num(common_code));
}
};
for (uint64_t head = 0; head < 16; ++head) { // split into 16 threads
@ -32,42 +30,33 @@ TEST(Group, block_num) {
for (auto &t : threads) {
t.join();
}
std::string block_num_data;
for (auto &&tmp : block_num_datas) {
block_num_data += tmp;
}
auto block_num_md5 = md5(block_num_data.c_str(), block_num_data.size());
EXPECT_STREQ(block_num_md5.c_str(), BLOCK_NUM_MD5);
// auto *block_num_data = new char[ALL_CASES_SIZE_SUM * 7 + 1]; // 'x,?x,x' + '\n'
// auto *current = block_num_data;
// for (auto &&common_code : AllCases::release()) {
// auto tmp = Group::block_num(common_code);
// EXPECT_EQ(tmp, Group::block_num(common_code.to_raw_code()));
// sprintf(current, "%d,%d,%d\n", tmp.n_1x2 + tmp.n_2x1, tmp.n_1x1, tmp.n_2x1);
// current += strlen(current);
// }
// auto block_num_md5 = md5(block_num_data, current - block_num_data);
// EXPECT_STREQ(block_num_md5.c_str(), BLOCK_NUM_MD5);
}
TEST(Group, type_id) {
TEST(Group, block_num) {
std::thread threads[16];
auto test = [](uint64_t head) {
for (const auto &range : AllCases::fetch()[head]) {
std::string block_num_data;
std::string block_num_str[16];
auto test = [&block_num_str](uint64_t head) {
char buffer[13];
for (auto &&range: AllCases::fetch()[head]) {
auto common_code = CommonCode::unsafe_create(head << 32 | range);
auto type_id = Group::type_id(common_code); // found type id
EXPECT_LT(type_id, TYPE_ID_LIMIT);
EXPECT_EQ(type_id, Group::type_id(common_code.to_raw_code()));
EXPECT_EQ(type_id, Group::type_id(Group::block_num(common_code)));
EXPECT_EQ(Group::block_num(type_id), Group::block_num(common_code));
auto tmp = Group::block_num(common_code);
EXPECT_EQ(tmp, Group::block_num(common_code.to_raw_code()));
sprintf(buffer, "%d,%d,%d\n", tmp.n_1x2 + tmp.n_2x1, tmp.n_1x1, tmp.n_2x1);
block_num_str[head] += buffer;
}
};
for (uint64_t head = 0; head < 16; ++head) { // split into 16 threads
threads[head] = std::thread(test, head);
}
for (auto &t : threads) {
t.join();
}
for (auto &&tmp : block_num_str) { // combine string
block_num_data += tmp;
}
auto block_num_md5 = md5(block_num_data.c_str(), block_num_data.size());
EXPECT_STREQ(block_num_md5.c_str(), BLOCK_NUM_MD5);
}

Loading…
Cancel
Save