Browse Source

fix: type id flag calculation error

master
Dnomd343 5 months ago
parent
commit
030c1a0bb4
  1. 8
      src/core/group/group.h
  2. 2
      src/core_test/CMakeLists.txt
  3. 149
      src/core_test/cases/group_union.cc
  4. 90
      src/core_test/cases/helper/block_nums.cc
  5. 29
      src/core_test/cases/helper/cases.h
  6. 23
      src/core_test/cases/helper/impl.cc
  7. 2
      src/core_test/cases/ranges.cc

8
src/core/group/group.h

@ -27,7 +27,7 @@
/// (10-bit) | (n_1x2 + n_2x1) | (n_2x1) | (n_1x1) |
/// | (0 ~ 7) | (0 ~ 7) | (0 ~ 14) |
///
/// flag => ((n_1x2 + n_2x1) << 7) | (n_2x1 << 3) | (n_1x1)
/// flag => ((n_1x2 + n_2x1) << 7) | (n_2x1 << 4) | (n_1x1)
///
/// Using the table lookup method, the `type_id` of any case can be obtained
/// within O(1), which is encapsulated in `GroupUnion`.
@ -75,6 +75,9 @@ namespace klotski::cases {
constexpr uint32_t TYPE_ID_LIMIT = 203;
constexpr uint32_t ALL_GROUP_NUM = 25422;
typedef std::vector<codec::RawCode> RawCodes;
typedef std::vector<codec::CommonCode> CommonCodes;
class Group;
// TODO: add constexpr
@ -142,9 +145,6 @@ private:
// ------------------------------------------------------------------------------------- //
};
typedef std::vector<codec::RawCode> RawCodes;
typedef std::vector<codec::CommonCode> CommonCodes;
class Group {
public:
Group() = delete;

2
src/core_test/CMakeLists.txt

@ -24,7 +24,7 @@ set(KLSK_TEST_CASES_SRC
cases/basic_ranges.cc
cases/all_cases.cc
cases/group_union.cc
cases/helper/impl.cc
cases/helper/block_nums.cc
)
add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC})

149
src/core_test/cases/group_union.cc

@ -1,151 +1,31 @@
#include <algorithm>
#include <common_code.h>
#include <cstdint>
#include <iostream>
#include <format>
#include <utility.h>
#include <group/group.h>
#include <gtest/gtest.h>
struct block_num_t {
int n_1x1;
int n_1x2;
int n_2x1;
};
template <>
struct std::hash<block_num_t> {
size_t operator()(const block_num_t val) const noexcept {
return std::hash<int>()(val.n_1x1) ^ std::hash<int>()(val.n_1x2) ^ std::hash<int>()(val.n_2x1);
}
};
bool operator==(const block_num_t &lhs, const block_num_t &rhs) {
return lhs.n_1x1 == rhs.n_1x1 && lhs.n_1x2 == rhs.n_1x2 && lhs.n_2x1 == rhs.n_2x1;
}
uint32_t cal_flag(const block_num_t &block_num) {
return ((block_num.n_1x2 + block_num.n_2x1) << 7) | (block_num.n_2x1 << 3) | block_num.n_1x1;
}
std::vector<block_num_t> block_nums() {
std::vector<std::pair<uint32_t, block_num_t>> tmp;
for (int n = 0; n <= 7; ++n) {
for (int n_1x2 = 0; n_1x2 <= n; ++n_1x2) {
if (n == 7 && n_1x2 == 0) {
continue;
}
for (int n_1x1 = 0; n_1x1 <= (20 - 4 - 2 - n * 2); ++n_1x1) {
auto num = block_num_t {
.n_1x1 = n_1x1,
.n_1x2 = n_1x2,
.n_2x1 = n - n_1x2,
};
auto flag = cal_flag(num);
tmp.emplace_back(flag, num);
// std::cout << flag << std::endl;
}
}
}
std::sort(tmp.begin(), tmp.end(), [](const auto val1, const auto val2) {
return val1.first < val2.first;
});
// for (auto [x, _] : tmp) {
// std::cout << x << std::endl;
// }
std::vector<block_num_t> results;
std::ranges::transform(tmp, std::back_inserter(results), [](const auto val) {
return val.second;
});
// for (auto x : results) {
// std::cout << std::format("n_1x1 = {} / n_1x2 = {} / n_2x1 = {}", x.n_1x1, x.n_1x2, x.n_2x1) << std::endl;
// }
return results;
}
block_num_t cal_block_num(const uint64_t common_code) noexcept {
block_num_t result {};
auto range = klotski::range_reverse(static_cast<uint32_t>(common_code));
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;
}
uint32_t to_type_id(block_num_t block_num) {
auto f = []() {
auto ret = block_nums();
std::unordered_map<block_num_t, uint32_t> kk;
for (auto i = 0; i < ret.size(); ++i) {
kk.emplace(ret[i], i);
}
return kk;
};
static auto data = f();
#include <format>
#include <cstdint>
#include <algorithm>
return data[block_num];
// TODO: only for debug
#include <iostream>
}
#include "group/group.h"
#include "helper/cases.h"
#include "common_code/common_code.h"
TEST(GroupUnion, demo) {
// kk();
auto kk = cal_block_num(0x1A9BF0C00);
std::cout << to_type_id(kk) << std::endl;
// for (auto i = 0; i < block_nums().size(); ++i) {
// // std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << std::endl;
//
// // std::cout << block_nums()[i].n_2x1 << std::endl;
//
// std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << ", ";
// std::cout << block_nums()[i].n_2x1 << ", ";
// std::cout << block_nums()[i].n_1x1 << std::endl;
// }
//
// return;
std::vector<std::vector<uint64_t>> pp;
pp.resize(block_nums().size());
// std::cout << pp.size() << std::endl;
for (uint64_t head = 0; head < 16; ++head) {
for (auto range : klotski::cases::AllCases::instance().fetch()[head]) {
for (auto range : AllCases::instance().fetch()[head]) {
uint64_t common_code = head << 32 | range;
auto type_id = to_type_id(cal_block_num(common_code));
@ -156,15 +36,9 @@ TEST(GroupUnion, demo) {
}
// std::cout << pp[0].size() << std::endl;
// std::cout << pp[169].size() << std::endl;
for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
// std::cout << "start cases cal" << std::endl;
auto cases = klotski::cases::GroupUnion::unsafe_create(type_id).cases();
// std::cout << "end cases cal" << std::endl;
std::vector<uint64_t> extend {};
for (uint64_t head = 0; head < 16; ++head) {
@ -174,7 +48,6 @@ TEST(GroupUnion, demo) {
}
std::cout << "type_id " << type_id << " -> " << extend.size() << std::endl;
// std::cout << std::endl;
EXPECT_EQ(extend, pp[type_id]);
}

90
src/core_test/cases/helper/block_nums.cc

@ -0,0 +1,90 @@
#include <iostream>
#include "cases.h"
#include <ranges>
block_num_t cal_block_num(uint32_t range) {
block_num_t result {};
range = range_reverse(range);
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;
}
static std::vector<block_num_t> build_block_nums() {
auto cal_type_flag = [](const block_num_t &block_num) {
const auto n_x2x = block_num.n_1x2 + block_num.n_2x1;
return (n_x2x << 7) | (block_num.n_2x1 << 4) | block_num.n_1x1;
};
std::vector<std::pair<uint32_t, block_num_t>> nums;
for (int n = 0; n <= 7; ++n) {
for (int n_1x2 = 0; n_1x2 <= n; ++n_1x2) {
if (n == 7 && n_1x2 == 0) {
continue;
}
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) {
auto num = block_num_t {
.n_1x1 = n_1x1,
.n_1x2 = n_1x2,
.n_2x1 = n - n_1x2,
};
nums.emplace_back(cal_type_flag(num), num);
}
}
}
std::ranges::sort(nums.begin(), nums.end(), [](const auto val1, const auto val2) {
return val1.first < val2.first;
});
return std::views::all(nums) | std::views::transform([](const auto val) {
return val.second;
}) | std::ranges::to<std::vector>();
}
uint32_t to_type_id(block_num_t block_num) {
auto f = []() {
auto ret = build_block_nums();
std::unordered_map<block_num_t, uint32_t> kk;
for (auto i = 0; i < ret.size(); ++i) {
kk.emplace(ret[i], i);
}
return kk;
};
static auto data = f();
return data[block_num];
// TODO: handle invalid params
}
block_num_t to_block_num(uint32_t type_id) {
static auto data = build_block_nums();
// TODO: handle invalid params
return data[type_id];
}
std::vector<block_num_t> block_nums() {
static auto data = build_block_nums();
return data;
}

29
src/core_test/cases/helper/cases.h

@ -26,6 +26,8 @@ constexpr auto Heads = std::to_array({
0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14
});
// ------------------------------------------------------------------------------------- //
/// Assert that Ranges are sorted and unique.
#define EXPECT_SORTED_AND_UNIQUE(R) \
EXPECT_TRUE(std::ranges::is_sorted(R.begin(), R.end())); \
@ -40,10 +42,35 @@ constexpr auto Heads = std::to_array({
for (const auto range : ranges) \
EXPECT_TRUE(CommonCode::check(static_cast<uint64_t>(head) << 32 | range))
// ------------------------------------------------------------------------------------- //
/// The number of blocks in one klotski layout.
struct block_num_t {
int n_1x1;
int n_1x2;
int n_2x1;
};
block_num_t get_block_num(uint32_t range);
template <>
struct std::hash<block_num_t> {
size_t operator()(const block_num_t val) const noexcept {
return (val.n_1x1 << 6) ^ (val.n_1x2 << 3) ^ val.n_2x1;
}
};
constexpr bool operator==(const block_num_t &lhs, const block_num_t &rhs) {
return lhs.n_1x1 == rhs.n_1x1 && lhs.n_1x2 == rhs.n_1x2 && lhs.n_2x1 == rhs.n_2x1;
}
// ------------------------------------------------------------------------------------- //
/// Calculate the block number from Range.
block_num_t cal_block_num(uint32_t range);
/// Calculate type id value from the block number.
uint32_t to_type_id(block_num_t block_num);
/// Calculate the block number value from type id.
block_num_t to_block_num(uint32_t type_id);
std::vector<block_num_t> block_nums();

23
src/core_test/cases/helper/impl.cc

@ -1,23 +0,0 @@
#include <cstdint>
#include "cases.h"
#include "utils/utility.h"
block_num_t get_block_num(uint32_t range) {
block_num_t result {};
range = klotski::range_reverse(range);
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;
}

2
src/core_test/cases/ranges.cc

@ -28,7 +28,7 @@ TEST(Ranges, spawn) {
EXPECT_SORTED_AND_UNIQUE(ranges);
for (const auto range : ranges) {
const auto [val_1x1, val_1x2, val_2x1] = get_block_num(range);
const auto [val_1x1, val_1x2, val_2x1] = cal_block_num(range);
EXPECT_EQ(val_1x1, n_1x1);
EXPECT_EQ(val_2x1, n_2x1);
EXPECT_EQ(val_1x2 + val_2x1, n);

Loading…
Cancel
Save