mirror of https://github.com/dnomd343/klotski.git
				
				
			Compare commits
	
		
			13 Commits 
		
	
	
		
			98ec2f3a1b
			...
			e28d717c3c
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | e28d717c3c | 1 year ago | 
|  | bc2c123e12 | 1 year ago | 
|  | fece208b2f | 1 year ago | 
|  | bce32d45a5 | 1 year ago | 
|  | 030c1a0bb4 | 1 year ago | 
|  | ccae5abce2 | 1 year ago | 
|  | 9ba27b70ae | 1 year ago | 
|  | 4d4523d072 | 1 year ago | 
|  | aa6d61432b | 1 year ago | 
|  | 5da4ce8295 | 1 year ago | 
|  | f5c91b8084 | 1 year ago | 
|  | 396a7fe4bc | 1 year ago | 
|  | 1607813851 | 1 year ago | 
				 27 changed files with 840 additions and 1055 deletions
			
			
		| @ -0,0 +1,38 @@ | |||||
|  | #include <benchmark/benchmark.h> | ||||
|  | 
 | ||||
|  | #include "group/group.h" | ||||
|  | #include "ranges/ranges.h" | ||||
|  | #include "all_cases/all_cases.h" | ||||
|  | 
 | ||||
|  | using klotski::cases::AllCases; | ||||
|  | 
 | ||||
|  | static void SpawnRanges(benchmark::State &state) { | ||||
|  |     // constexpr auto nums = target_nums();
 | ||||
|  | 
 | ||||
|  |     for (auto _ : state) { | ||||
|  | 
 | ||||
|  |         klotski::cases::Ranges kk {}; | ||||
|  |         kk.reserve(7311921); | ||||
|  | 
 | ||||
|  |         // for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
 | ||||
|  |             for (auto [n, n_2x1, n_1x1] : klotski::cases::BLOCK_NUM) { | ||||
|  |                 kk.spawn(n, n_2x1, n_1x1); | ||||
|  |             } | ||||
|  |         // }
 | ||||
|  |     } | ||||
|  | 
 | ||||
|  | } | ||||
|  | 
 | ||||
|  | static void RangesUnionExport(benchmark::State &state) { | ||||
|  |     auto &all_cases = AllCases::instance().fetch(); | ||||
|  |     for (auto _ : state) { | ||||
|  |         auto codes = all_cases.codes(); | ||||
|  |         benchmark::DoNotOptimize(codes.size()); | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | BENCHMARK(SpawnRanges)->Unit(benchmark::kMillisecond); | ||||
|  | 
 | ||||
|  | // BENCHMARK(RangesUnionExport)->Unit(benchmark::kMillisecond);
 | ||||
|  | 
 | ||||
|  | BENCHMARK_MAIN(); | ||||
| @ -0,0 +1,16 @@ | |||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <array> | ||||
|  | 
 | ||||
|  | namespace klotski::cases { | ||||
|  | 
 | ||||
|  | // TODO: should we try to compress it?
 | ||||
|  | constexpr auto GROUP_SIZE = std::to_array<uint32_t>({ | ||||
|  | #include "sizes.inc" | ||||
|  | }); | ||||
|  | 
 | ||||
|  | constexpr auto GROUP_SEED = std::to_array<uint64_t>({ | ||||
|  | #include "seeds.inc" | ||||
|  | }); | ||||
|  | 
 | ||||
|  | } // namespace klotski::cases
 | ||||
								
									
										File diff suppressed because one or more lines are too long
									
								
							
						
					| @ -1,45 +1,59 @@ | |||||
|  | #include <absl/container/flat_hash_map.h> | ||||
|  | 
 | ||||
|  | #include "core/core.h" | ||||
| #include "group/group.h" | #include "group/group.h" | ||||
| 
 | 
 | ||||
| #include <queue> | using klotski::core::Core; | ||||
|  | using klotski::cases::Group; | ||||
|  | using klotski::codec::RawCode; | ||||
|  | using klotski::codec::CommonCode; | ||||
|  | using klotski::cases::RangesUnion; | ||||
| 
 | 
 | ||||
| #include <absl/container/btree_set.h> | std::vector<RawCode> Group::extend(RawCode raw_code, uint32_t reserve) { | ||||
| #include <absl/container/flat_hash_map.h> |     std::vector<RawCode> codes; | ||||
| #include <absl/container/node_hash_map.h> |     absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
 | ||||
|  |     reserve = reserve ? reserve : GroupUnion::from_raw_code(raw_code).max_group_size(); | ||||
|  |     codes.reserve(reserve); | ||||
|  |     cases.reserve(reserve); | ||||
|  | 
 | ||||
|  |     auto core = Core([&codes, &cases](uint64_t code, uint64_t mask) { | ||||
|  |         if (const auto match = cases.find(code); match != cases.end()) { | ||||
|  |             match->second |= mask; // update mask
 | ||||
|  |             return; | ||||
|  |         } | ||||
|  |         cases.emplace(code, mask); | ||||
|  |         codes.emplace_back(RawCode::unsafe_create(code)); // new case
 | ||||
|  |     }); | ||||
|  | 
 | ||||
|  |     uint64_t offset = 0; | ||||
|  |     codes.emplace_back(raw_code); | ||||
|  |     cases.emplace(raw_code, 0); // without mask
 | ||||
|  |     while (offset != codes.size()) { | ||||
|  |         auto curr = codes[offset++].unwrap(); | ||||
|  |         core.next_cases(curr, cases.find(curr)->second); | ||||
|  |     } | ||||
|  |     return codes; | ||||
|  | } | ||||
| 
 | 
 | ||||
| #include <core/core.h> | RangesUnion Group::cases() const { | ||||
|  |     auto seed = CommonCode::unsafe_create(GROUP_SEED[flat_id()]); | ||||
| 
 | 
 | ||||
| std::vector<uint64_t> klotski::cases::Group::extend(codec::RawCode raw_code) { |     // std::cout << seed << std::endl;
 | ||||
| 
 | 
 | ||||
|     auto max_size = GroupUnion::from_raw_code(raw_code).max_group_size(); |     auto codes = extend(seed.to_raw_code(), size()); | ||||
|     // auto max_size = GroupUnion::create(raw_code_to_type_id(raw_code))->max_group_size();
 |  | ||||
| 
 | 
 | ||||
|     uint64_t offset = 0; |     // std::cout << codes.size() << std::endl;
 | ||||
|     std::vector<uint64_t> results; |  | ||||
|     results.reserve(max_size); |  | ||||
|     results.emplace_back(raw_code); |  | ||||
| 
 | 
 | ||||
|     absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
 |     // TODO: how to reserve
 | ||||
|     cases.reserve(max_size); |  | ||||
|     cases.emplace(raw_code, 0); // without mask
 |  | ||||
| 
 | 
 | ||||
|     auto core = klotski::core::Core( |     RangesUnion data; | ||||
|         [&results, &cases](auto code, auto mask) { // callback function
 |  | ||||
|             auto current = cases.find(code); |  | ||||
|             if (current != cases.end()) { |  | ||||
|                 current->second |= mask; // update mask
 |  | ||||
|                 return; |  | ||||
|             } |  | ||||
|             cases.emplace(code, mask); |  | ||||
|             results.emplace_back(code); |  | ||||
|         } |  | ||||
|     ); |  | ||||
| 
 | 
 | ||||
|     while (offset != results.size()) { |     for (auto raw_code : codes) { | ||||
|         auto tmp = results[offset]; |         auto common_code = raw_code.to_common_code().unwrap(); | ||||
|         core.next_cases(tmp, cases.find(tmp)->second); |         data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code)); | ||||
|         ++offset; |  | ||||
|     } |     } | ||||
| 
 | 
 | ||||
|     return results; |     // TODO: do sort process
 | ||||
| 
 | 
 | ||||
|  |     return data; | ||||
| } | } | ||||
|  | |||||
| @ -0,0 +1,34 @@ | |||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include "constant/group.h" | ||||
|  | 
 | ||||
|  | namespace klotski::cases { | ||||
|  | 
 | ||||
|  | inline uint32_t Group::size() const { | ||||
|  |     return GROUP_SIZE[flat_id()]; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline uint32_t Group::flat_id() const { | ||||
|  |     return GROUP_OFFSET[type_id_] + group_id_; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline uint32_t Group::type_id() const { | ||||
|  |     return type_id_; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline uint32_t Group::group_id() const { | ||||
|  |     return group_id_; | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline Group Group::unsafe_create(const uint32_t type_id, const uint32_t group_id) { | ||||
|  |     return std::bit_cast<Group>(static_cast<uint64_t>(group_id) << 32 | type_id); | ||||
|  | } | ||||
|  | 
 | ||||
|  | inline std::optional<Group> Group::create(const uint32_t type_id, const uint32_t group_id) { | ||||
|  |     if (type_id < TYPE_ID_LIMIT && group_id < GROUP_NUM[type_id]) { | ||||
|  |         return unsafe_create(type_id, group_id); | ||||
|  |     } | ||||
|  |     return std::nullopt; | ||||
|  | } | ||||
|  | 
 | ||||
|  | } // namespace klotski::cases | ||||
| @ -1,154 +1,51 @@ | |||||
|  | #include "core/core.h" | ||||
| #include "group/group.h" | #include "group/group.h" | ||||
|  | #include "constant/group_union.h" | ||||
| 
 | 
 | ||||
| // #include <queue>
 | using klotski::codec::RawCode; | ||||
| 
 | using klotski::codec::CommonCode; | ||||
| // #include <absl/container/btree_set.h>
 | using klotski::cases::GroupUnion; | ||||
| // #include <absl/container/flat_hash_map.h>
 |  | ||||
| // #include <absl/container/node_hash_map.h>
 |  | ||||
| 
 |  | ||||
| #include <iostream> |  | ||||
| #include <core/core.h> |  | ||||
| 
 | 
 | ||||
| #include "constant/group_union.h" | #define RANGE_DERIVE(HEAD) ranges.derive(HEAD, cases[HEAD]) | ||||
| 
 | 
 | ||||
| static KLSK_INLINE uint32_t type_id(const int n, const int n_2x1, const int n_1x1) { | static KLSK_INLINE uint32_t to_type_id(const int n, const int n_2x1, const int n_1x1) { | ||||
|     constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196}; |     constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196}; | ||||
|     return offset[n] + (15 - n * 2) * n_2x1 + n_1x1; |     return offset[n] + (15 - n * 2) * n_2x1 + n_1x1; | ||||
| } | } | ||||
| 
 | 
 | ||||
| static uint32_t common_code_to_type_id(const uint64_t common_code) { | uint32_t GroupUnion::type_id(const CommonCode common_code) { | ||||
|     const auto range = static_cast<uint32_t>(common_code); |     const auto range = static_cast<uint32_t>(common_code.unwrap()); | ||||
|     const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555); |     const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555); | ||||
|     const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555); |     const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555); | ||||
|     return type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1); |     return to_type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1); | ||||
| } |  | ||||
| 
 |  | ||||
| static uint32_t raw_code_to_type_id(const uint64_t raw_code) { |  | ||||
|     const auto n = std::popcount(((raw_code >> 1) ^ raw_code) & 0x0249249249249249); |  | ||||
|     const auto n_2x1 = std::popcount((raw_code >> 1) & ~raw_code & 0x0249249249249249); |  | ||||
|     const auto n_1x1 = std::popcount((raw_code >> 1) & raw_code & 0x0249249249249249) - n - 3; |  | ||||
|     return type_id(n, n_2x1, n_1x1); |  | ||||
| } |  | ||||
| 
 |  | ||||
| uint32_t klotski::cases::GroupUnion::type_id(codec::CommonCode common_code) { |  | ||||
|     return common_code_to_type_id(common_code.unwrap()); |  | ||||
| } | } | ||||
| 
 | 
 | ||||
| uint32_t klotski::cases::GroupUnion::type_id(codec::RawCode raw_code) { | uint32_t GroupUnion::type_id(const RawCode raw_code) { | ||||
|     return raw_code_to_type_id(raw_code.unwrap()); |     const auto code = raw_code.unwrap(); | ||||
|  |     const auto n = std::popcount(((code >> 1) ^ code) & 0x0249249249249249); | ||||
|  |     const auto n_2x1 = std::popcount((code >> 1) & ~code & 0x0249249249249249); | ||||
|  |     const auto n_1x1 = std::popcount((code >> 1) & code & 0x0249249249249249) - n - 3; | ||||
|  |     return to_type_id(n, n_2x1, n_1x1); | ||||
| } | } | ||||
| 
 | 
 | ||||
| klotski::cases::RangesUnion klotski::cases::GroupUnion::cases() const { | klotski::cases::RangesUnion GroupUnion::cases() const { | ||||
|     Ranges ranges {}; |  | ||||
| 
 |  | ||||
|     auto [n, n_2x1, n_1x1] = BLOCK_NUM[type_id_]; |     auto [n, n_2x1, n_1x1] = BLOCK_NUM[type_id_]; | ||||
|  |     auto [s_a, s_b, s_c, s_d] = GROUP_UNION_CASES_NUM[type_id_]; | ||||
| 
 | 
 | ||||
|     // int n = TYPE_ID_N_NUM[type_id_];
 |     Ranges ranges {}; | ||||
|     // int n_2x1 = TYPE_ID_N_2x1_NUM[type_id_];
 |     ranges.reserve(BASIC_RANGES_NUM[type_id_]); | ||||
|     // int n_1x1 = TYPE_ID_N_1x1_NUM[type_id_]; // TODO: cal from type_id
 |  | ||||
|     ranges.spawn(n, n_2x1, n_1x1); |     ranges.spawn(n, n_2x1, n_1x1); | ||||
| 
 |  | ||||
|     // for (int i = 0; i < TYPE_ID_LIMIT; ++i) {
 |  | ||||
|     //     ranges.spawn(TYPE_ID_N_NUM[i], TYPE_ID_N_2x1_NUM[i], TYPE_ID_N_1x1_NUM[i]);
 |  | ||||
|     // }
 |  | ||||
|     // std::stable_sort(ranges.begin(), ranges.end());
 |  | ||||
| 
 |  | ||||
|     // for (auto &x : ranges) {
 |  | ||||
|     //     x = klotski::range_reverse(x);
 |  | ||||
|     // }
 |  | ||||
| 
 |  | ||||
|     ranges.reverse(); |     ranges.reverse(); | ||||
| 
 | 
 | ||||
|     // auto do_assert = [](uint32_t lhs, uint32_t rhs) {
 |  | ||||
|     //     if (lhs != rhs) {
 |  | ||||
|     //         std::cout << "error" << std::endl;
 |  | ||||
|     //     }
 |  | ||||
|     // };
 |  | ||||
| 
 |  | ||||
|     RangesUnion cases; |     RangesUnion cases; | ||||
| 
 |     cases[0x0].reserve(s_a); cases[0x1].reserve(s_b); cases[0x2].reserve(s_a); | ||||
|     // cases[0x0].reserve(7815);
 |     cases[0x4].reserve(s_c); cases[0x5].reserve(s_d); cases[0x6].reserve(s_c); | ||||
|     // cases[0x1].reserve(6795);
 |     cases[0x8].reserve(s_c); cases[0x9].reserve(s_d); cases[0xA].reserve(s_c); | ||||
|     // cases[0x2].reserve(7815);
 |     cases[0xC].reserve(s_a); cases[0xD].reserve(s_b); cases[0xE].reserve(s_a); | ||||
|     //
 | 
 | ||||
|     // cases[0x4].reserve(3525);
 |     RANGE_DERIVE(0x0); RANGE_DERIVE(0x1); RANGE_DERIVE(0x2); | ||||
|     // cases[0x5].reserve(3465);
 |     RANGE_DERIVE(0x4); RANGE_DERIVE(0x5); RANGE_DERIVE(0x6); | ||||
|     // cases[0x6].reserve(3525);
 |     RANGE_DERIVE(0x8); RANGE_DERIVE(0x9); RANGE_DERIVE(0xA); | ||||
|     //
 |     RANGE_DERIVE(0xC); RANGE_DERIVE(0xD); RANGE_DERIVE(0xE); | ||||
|     // cases[0x8].reserve(3525);
 |  | ||||
|     // cases[0x9].reserve(3465);
 |  | ||||
|     // cases[0xA].reserve(3525);
 |  | ||||
|     //
 |  | ||||
|     // cases[0xC].reserve(7815);
 |  | ||||
|     // cases[0xD].reserve(6795);
 |  | ||||
|     // cases[0xE].reserve(7815);
 |  | ||||
| 
 |  | ||||
|     auto [A, B, C, D] = GROUP_UNION_CASES_NUM[type_id_]; |  | ||||
| 
 |  | ||||
|     cases[0x0].reserve(A); |  | ||||
|     cases[0x1].reserve(B); |  | ||||
|     cases[0x2].reserve(A); |  | ||||
| 
 |  | ||||
|     cases[0x4].reserve(C); |  | ||||
|     cases[0x5].reserve(D); |  | ||||
|     cases[0x6].reserve(C); |  | ||||
| 
 |  | ||||
|     cases[0x8].reserve(C); |  | ||||
|     cases[0x9].reserve(D); |  | ||||
|     cases[0xA].reserve(C); |  | ||||
| 
 |  | ||||
|     cases[0xC].reserve(A); |  | ||||
|     cases[0xD].reserve(B); |  | ||||
|     cases[0xE].reserve(A); |  | ||||
| 
 |  | ||||
|     ranges.derive(0x0, cases[0x0]); |  | ||||
|     ranges.derive(0x1, cases[0x1]); |  | ||||
|     ranges.derive(0x2, cases[0x2]); |  | ||||
| 
 |  | ||||
|     ranges.derive(0x4, cases[0x4]); |  | ||||
|     ranges.derive(0x5, cases[0x5]); |  | ||||
|     ranges.derive(0x6, cases[0x6]); |  | ||||
| 
 |  | ||||
|     ranges.derive(0x8, cases[0x8]); |  | ||||
|     ranges.derive(0x9, cases[0x9]); |  | ||||
|     ranges.derive(0xA, cases[0xA]); |  | ||||
| 
 |  | ||||
|     ranges.derive(0xC, cases[0xC]); |  | ||||
|     ranges.derive(0xD, cases[0xD]); |  | ||||
|     ranges.derive(0xE, cases[0xE]); |  | ||||
| 
 |  | ||||
|     // uint32_t A = cases[0x0].size();
 |  | ||||
|     // uint32_t B = cases[0x1].size();
 |  | ||||
|     // uint32_t C = cases[0x4].size();
 |  | ||||
|     // uint32_t D = cases[0x5].size();
 |  | ||||
|     //
 |  | ||||
|     // do_assert(cases[0x2].size(), A);
 |  | ||||
|     // do_assert(cases[0x6].size(), C);
 |  | ||||
|     // do_assert(cases[0x8].size(), C);
 |  | ||||
|     // do_assert(cases[0x9].size(), D);
 |  | ||||
|     // do_assert(cases[0xA].size(), C);
 |  | ||||
|     // do_assert(cases[0xC].size(), A);
 |  | ||||
|     // do_assert(cases[0xD].size(), B);
 |  | ||||
|     // do_assert(cases[0xE].size(), A);
 |  | ||||
|     //
 |  | ||||
|     // std::cout << A << ", " << B << ", " << C << ", " << D << std::endl;
 |  | ||||
| 
 |  | ||||
|     // auto [A, B, C, D] = kk[type_id_];
 |  | ||||
|     // do_assert(cases[0x0].size(), A);
 |  | ||||
|     // do_assert(cases[0x1].size(), B);
 |  | ||||
|     // do_assert(cases[0x2].size(), A);
 |  | ||||
|     //
 |  | ||||
|     // do_assert(cases[0x4].size(), C);
 |  | ||||
|     // do_assert(cases[0x5].size(), D);
 |  | ||||
|     // do_assert(cases[0x6].size(), C);
 |  | ||||
|     //
 |  | ||||
|     // do_assert(cases[0x8].size(), C);
 |  | ||||
|     // do_assert(cases[0x9].size(), D);
 |  | ||||
|     // do_assert(cases[0xA].size(), C);
 |  | ||||
|     //
 |  | ||||
|     // do_assert(cases[0xC].size(), A);
 |  | ||||
|     // do_assert(cases[0xD].size(), B);
 |  | ||||
|     // do_assert(cases[0xE].size(), A);
 |  | ||||
| 
 |  | ||||
|     return cases; |     return cases; | ||||
| } | } | ||||
|  | |||||
| @ -1,40 +1,45 @@ | |||||
| #include <algorithm> |  | ||||
| 
 |  | ||||
| #include "utils/utility.h" |  | ||||
| #include "ranges/ranges.h" | #include "ranges/ranges.h" | ||||
|  | #include "common_code/common_code.h" | ||||
| 
 | 
 | ||||
| using klotski::cases::Ranges; | using klotski::cases::Ranges; | ||||
|  | using klotski::codec::CommonCode; | ||||
|  | using klotski::cases::RangesUnion; | ||||
| 
 | 
 | ||||
| template<int N> | static constexpr auto heads = std::to_array<uint64_t>({ | ||||
| static void build_ranges(std::vector<uint32_t> &ranges, int n_10, int n_11) { |     0x0, 0x1, 0x2, 0x4, 0x5, 0x6, | ||||
|     int n_01 = N - n_10; |     0x8, 0x9, 0xA, 0xC, 0xD, 0xE, | ||||
|     int n_00 = 16 - N * 2 - n_11; | }); | ||||
| 
 | 
 | ||||
|     std::array<int, 16 - N> series {}; | void Ranges::reverse() { | ||||
|     std::fill_n(series.begin() + n_00, n_01, 0b01); |     for (auto &x : *this) { | ||||
|     std::fill_n(series.begin() + n_00 + n_01, n_10, 0b10); |         x = range_reverse(x); | ||||
|     std::fill_n(series.begin() + n_00 + n_01 + n_10, n_11, 0b11); |     } | ||||
|  | } | ||||
| 
 | 
 | ||||
|     do { | Ranges& Ranges::operator+=(const Ranges &ranges) { | ||||
|         uint32_t range = 0; |     this->insert(this->end(), ranges.begin(), ranges.end()); | ||||
|         for (const auto x : series) { // store every 2-bit
 |     return *this; | ||||
|             (range <<= 2) |= x; | } | ||||
|         } | 
 | ||||
|         ranges.emplace_back(range << (N * 2)); | RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) { | ||||
|     } while (std::ranges::next_permutation(series).found); |     for (const auto head : heads) { | ||||
|  |         (*this)[head] += ranges_union[head]; | ||||
|  |     } | ||||
|  |     return *this; | ||||
| } | } | ||||
| 
 | 
 | ||||
| void Ranges::spawn(const int n, const int n_2x1, const int n_1x1) { | std::vector<CommonCode> RangesUnion::codes() const { | ||||
|     KLSK_ASSUME(n >= 0 && n_2x1 >= 0 && n_1x1 >= 0); |     size_type size = 0; | ||||
|     KLSK_ASSUME(n <= 7 && n_2x1 <= n && n_1x1 + n * 2 <= 14); |     for (const auto head : heads) { | ||||
|     switch (n) { |         size += (*this)[head].size(); | ||||
|         case 0: return build_ranges<0>(*this, n_2x1, n_1x1); |     } | ||||
|         case 1: return build_ranges<1>(*this, n_2x1, n_1x1); | 
 | ||||
|         case 2: return build_ranges<2>(*this, n_2x1, n_1x1); |     std::vector<CommonCode> codes; | ||||
|         case 3: return build_ranges<3>(*this, n_2x1, n_1x1); |     codes.reserve(size); | ||||
|         case 4: return build_ranges<4>(*this, n_2x1, n_1x1); |     for (const auto head : heads) { | ||||
|         case 5: return build_ranges<5>(*this, n_2x1, n_1x1); |         for (const auto range : (*this)[head]) { | ||||
|         case 6: return build_ranges<6>(*this, n_2x1, n_1x1); |             codes.emplace_back(CommonCode::unsafe_create(head << 32 | range)); | ||||
|         case 7: return build_ranges<7>(*this, n_2x1, n_1x1); |         } | ||||
|     } |     } | ||||
|  |     return codes; | ||||
| } | } | ||||
|  | |||||
| @ -0,0 +1,40 @@ | |||||
|  | #include <algorithm> | ||||
|  | 
 | ||||
|  | #include "utils/utility.h" | ||||
|  | #include "ranges/ranges.h" | ||||
|  | 
 | ||||
|  | using klotski::cases::Ranges; | ||||
|  | 
 | ||||
|  | template<int N> | ||||
|  | static void spawn_ranges(std::vector<uint32_t> &ranges, int n_10, int n_11) { | ||||
|  |     int n_01 = N - n_10; | ||||
|  |     int n_00 = 16 - N * 2 - n_11; | ||||
|  | 
 | ||||
|  |     std::array<int, 16 - N> series {}; | ||||
|  |     std::fill_n(series.begin() + n_00, n_01, 0b01); | ||||
|  |     std::fill_n(series.begin() + n_00 + n_01, n_10, 0b10); | ||||
|  |     std::fill_n(series.begin() + n_00 + n_01 + n_10, n_11, 0b11); | ||||
|  | 
 | ||||
|  |     do { | ||||
|  |         uint32_t range = 0; | ||||
|  |         for (const auto x : series) { // store every 2-bit
 | ||||
|  |             (range <<= 2) |= x; | ||||
|  |         } | ||||
|  |         ranges.emplace_back(range << (N * 2)); | ||||
|  |     } while (std::ranges::next_permutation(series).found); | ||||
|  | } | ||||
|  | 
 | ||||
|  | void Ranges::spawn(const int n, const int n_2x1, const int n_1x1) { | ||||
|  |     KLSK_ASSUME(n >= 0 && n_2x1 >= 0 && n_1x1 >= 0); | ||||
|  |     KLSK_ASSUME(n <= 7 && n_2x1 <= n && n_1x1 + n * 2 <= 14); | ||||
|  |     switch (n) { | ||||
|  |         case 0: return spawn_ranges<0>(*this, n_2x1, n_1x1); | ||||
|  |         case 1: return spawn_ranges<1>(*this, n_2x1, n_1x1); | ||||
|  |         case 2: return spawn_ranges<2>(*this, n_2x1, n_1x1); | ||||
|  |         case 3: return spawn_ranges<3>(*this, n_2x1, n_1x1); | ||||
|  |         case 4: return spawn_ranges<4>(*this, n_2x1, n_1x1); | ||||
|  |         case 5: return spawn_ranges<5>(*this, n_2x1, n_1x1); | ||||
|  |         case 6: return spawn_ranges<6>(*this, n_2x1, n_1x1); | ||||
|  |         case 7: return spawn_ranges<7>(*this, n_2x1, n_1x1); | ||||
|  |     } | ||||
|  | } | ||||
| @ -1,36 +1,42 @@ | |||||
| #pragma once | #pragma once | ||||
| 
 | 
 | ||||
|  | #include <array> | ||||
| #include <vector> | #include <vector> | ||||
| #include <cstdint> | #include <cstdint> | ||||
| 
 | 
 | ||||
| #include "utils/utility.h" | #include "utils/utility.h" | ||||
| 
 | 
 | ||||
|  | namespace klotski::codec { | ||||
|  | class CommonCode; | ||||
|  | } // namespace klotski::codec
 | ||||
|  | 
 | ||||
| namespace klotski::cases { | namespace klotski::cases { | ||||
| 
 | 
 | ||||
| class Ranges : public std::vector<uint32_t> { | class Ranges final : public std::vector<uint32_t> { | ||||
| public: | public: | ||||
|  |     /// Append the ranges from another instance.
 | ||||
|  |     Ranges& operator+=(const Ranges &ranges); | ||||
|  | 
 | ||||
|     /// Spawn klotski-ranges that match the specified block numbers.
 |     /// Spawn klotski-ranges that match the specified block numbers.
 | ||||
|     void spawn(int n, int n_2x1, int n_1x1); |     void spawn(int n, int n_2x1, int n_1x1); | ||||
| 
 | 
 | ||||
|  |     /// Flip the klotski-ranges every two bits in low-high symmetry.
 | ||||
|     void reverse(); |     void reverse(); | ||||
| 
 | 
 | ||||
|     /// Derive the legal klotski-ranges with specified head.
 |     /// Derive the legal klotski-ranges from reversed ranges with specified head.
 | ||||
|     void derive(int head, Ranges &output) const; |     void derive(int head, Ranges &output) const; | ||||
| 
 | 
 | ||||
|     /// Check whether the combination of head and range is valid.
 |     /// Check whether the combination of head and reversed range is valid.
 | ||||
|     static KLSK_INLINE int check(int head, uint32_t range); |     static KLSK_INLINE int check(int head, uint32_t range); | ||||
| }; | }; | ||||
| 
 | 
 | ||||
| // typedef std::array<Ranges, 16> RangesUnion;
 |  | ||||
| 
 |  | ||||
| class RangesUnion final : public std::array<Ranges, 16> { | class RangesUnion final : public std::array<Ranges, 16> { | ||||
|     std::vector<uint64_t> codes(); | public: | ||||
| }; |     /// Append the ranges from another instance.
 | ||||
|  |     RangesUnion& operator+=(const RangesUnion &ranges_union); | ||||
| 
 | 
 | ||||
| inline void Ranges::reverse() { |     /// Export the RangesUnion as CommonCode list.
 | ||||
|     for (auto &x : *this) { |     [[nodiscard]] std::vector<codec::CommonCode> codes() const; | ||||
|         x = range_reverse(x); | }; | ||||
|     } |  | ||||
| } |  | ||||
| 
 | 
 | ||||
| } // namespace klotski::cases
 | } // namespace klotski::cases
 | ||||
|  | |||||
| @ -1,524 +0,0 @@ | |||||
| #!/usr/bin/env python3 |  | ||||
| 
 |  | ||||
| def load(): |  | ||||
|     lines = open('tmp.txt').read().splitlines() |  | ||||
|     tmp = [x.split(' ') for x in lines] |  | ||||
|     data = [(int(x[0]), int(x[1]), int(x[2])) for x in tmp] |  | ||||
|     return data |  | ||||
| 
 |  | ||||
| 
 |  | ||||
| def statis(data: list[tuple[int, int]]): |  | ||||
|     # data -> (distance, offset) |  | ||||
| 
 |  | ||||
|     distances = sorted({x[0] for x in data}) |  | ||||
| 
 |  | ||||
|     for distance in distances: |  | ||||
|         all_offsets = [x[1] for x in data if x[0] == distance] |  | ||||
|         offsets = sorted(set(all_offsets)) |  | ||||
| 
 |  | ||||
|         # print(distance, offsets) |  | ||||
| 
 |  | ||||
|         # for offset in offsets: |  | ||||
|         #     print(offset, all_offsets.count(offset)) |  | ||||
| 
 |  | ||||
|         offset_num = {x: all_offsets.count(x) for x in offsets} |  | ||||
| 
 |  | ||||
|         print(f'{distance} -> {offset_num}') |  | ||||
| 
 |  | ||||
| 
 |  | ||||
| if __name__ == '__main__': |  | ||||
|     raw_data = load() |  | ||||
| 
 |  | ||||
|     for head in range(16): |  | ||||
|         if head % 4 == 3: |  | ||||
|             continue |  | ||||
|         print(f'head = {head}') |  | ||||
|         statis([(x[1], x[2]) for x in raw_data]) |  | ||||
|         # statis([(x[1], x[2]) for x in raw_data if x[0] == head]) |  | ||||
|         print() |  | ||||
| 
 |  | ||||
| """ |  | ||||
| 0 -> {7: 177, 8: 2619, 9: 21087, 10: 156415, 11: 756356, 12: 1755849, 13: 1981898, 14: 1057653, 15: 212797} |  | ||||
| 1 -> {9: 18544, 10: 192582, 11: 596880, 12: 785128, 13: 460136, 14: 98136} |  | ||||
| 2 -> {8: 3578, 9: 15480, 10: 18792, 11: 8920, 12: 1760, 13: 120} |  | ||||
| 3 -> {7: 498, 8: 1963, 9: 2215, 10: 1000, 11: 192, 12: 13} |  | ||||
| 4 -> {8: 67} |  | ||||
| 5 -> {8: 1722, 9: 42570, 10: 178524, 11: 275405, 12: 178288, 13: 40830} |  | ||||
| 8 -> {7: 8} |  | ||||
| 10 -> {7: 490, 8: 5889, 9: 11075, 10: 7000, 11: 1728, 12: 143} |  | ||||
| 13 -> {6: 1} |  | ||||
| 15 -> {8: 7852, 9: 57590, 10: 120000, 11: 96384, 12: 26468} |  | ||||
| 16 -> {6: 50, 7: 433, 8: 625, 9: 297, 10: 53, 11: 3} |  | ||||
| 32 -> {7: 866, 8: 2500, 9: 1782, 10: 424, 11: 30} |  | ||||
| 42 -> {7: 23} |  | ||||
| 43 -> {7: 410, 8: 6875, 9: 16929, 10: 13091, 11: 3039} |  | ||||
| 57 -> {6: 189, 7: 457, 8: 295, 9: 68, 10: 5} |  | ||||
| 95 -> {6: 7} |  | ||||
| 98 -> {6: 182, 7: 1371, 8: 1475, 9: 476, 10: 45} |  | ||||
| 119 -> {7: 1828, 8: 7670, 9: 8160, 10: 2510} |  | ||||
| 184 -> {5: 1} |  | ||||
| 190 -> {5: 52, 6: 276, 7: 221, 8: 47, 9: 2} |  | ||||
| 284 -> {6: 552, 7: 884, 8: 282, 9: 16} |  | ||||
| 326 -> {6: 10} |  | ||||
| 327 -> {6: 266, 7: 2431, 8: 2679, 9: 494} |  | ||||
| 591 -> {5: 162, 6: 269, 7: 112, 8: 13} |  | ||||
| 806 -> {5: 6} |  | ||||
| 810 -> {5: 156, 6: 807, 7: 560, 8: 91} |  | ||||
| 895 -> {6: 1076, 7: 2912, 8: 1560} |  | ||||
| 1784 -> {4: 18, 5: 73, 6: 32, 7: 3} |  | ||||
| 2276 -> {5: 146, 6: 128, 7: 18} |  | ||||
| 2446 -> {5: 9} |  | ||||
| 2447 -> {5: 64, 6: 352, 7: 171} |  | ||||
| 5245 -> {4: 51, 5: 33, 6: 5} |  | ||||
| 6341 -> {4: 1} |  | ||||
| 6346 -> {4: 50, 5: 99, 6: 25} |  | ||||
| 6687 -> {5: 132, 6: 130} |  | ||||
| 15147 -> {3: 1} |  | ||||
| 15162 -> {3: 20, 4: 33, 5: 2} |  | ||||
| 17588 -> {4: 66, 5: 8} |  | ||||
| 18270 -> {4: 2} |  | ||||
| 18271 -> {4: 31, 5: 22} |  | ||||
| 43243 -> {3: 31, 4: 13} |  | ||||
| 48548 -> {3: 3} |  | ||||
| 48554 -> {3: 28, 4: 39} |  | ||||
| 49919 -> {4: 52} |  | ||||
| 122103 -> {2: 1} |  | ||||
| 122124 -> {2: 5, 3: 3} |  | ||||
| 133652 -> {3: 6} |  | ||||
| 136382 -> {3: 2} |  | ||||
| 136383 -> {3: 1} |  | ||||
| 342265 -> {2: 5} |  | ||||
| 367139 -> {2: 2} |  | ||||
| 367146 -> {2: 3} |  | ||||
| 953634 -> {1: 1} |  | ||||
| 953662 -> {1: 1} |  | ||||
| """ |  | ||||
| 
 |  | ||||
| """ |  | ||||
| head = 0 |  | ||||
| 0 -> {7: 24, 8: 357, 9: 2834, 10: 19468, 11: 85928, 12: 181284, 13: 185611, 14: 89839, 15: 16369} |  | ||||
| 1 -> {9: 2548, 10: 23998, 11: 67680, 12: 80822, 13: 42756, 14: 8178} |  | ||||
| 2 -> {8: 460, 9: 1932, 10: 2262, 11: 1024, 12: 190, 13: 12} |  | ||||
| 3 -> {7: 46, 8: 161, 9: 177, 10: 79, 11: 15, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 222, 9: 5313, 10: 21489, 11: 31616, 12: 19247, 13: 4083} |  | ||||
| 10 -> {7: 46, 8: 483, 9: 885, 10: 553, 11: 135, 12: 11} |  | ||||
| 15 -> {8: 644, 9: 4602, 10: 9480, 11: 7530, 12: 2036} |  | ||||
| 16 -> {6: 2, 7: 20, 8: 25, 9: 9, 10: 1} |  | ||||
| 32 -> {7: 40, 8: 100, 9: 54, 10: 8} |  | ||||
| 43 -> {7: 20, 8: 275, 9: 513, 10: 247} |  | ||||
| 57 -> {6: 13, 7: 25, 8: 10, 9: 1} |  | ||||
| 98 -> {6: 13, 7: 75, 8: 50, 9: 7} |  | ||||
| 119 -> {7: 100, 8: 260, 9: 120} |  | ||||
| 190 -> {5: 5, 6: 23, 7: 18, 8: 3} |  | ||||
| 284 -> {6: 46, 7: 72, 8: 18} |  | ||||
| 327 -> {6: 23, 7: 198, 8: 171} |  | ||||
| 591 -> {5: 11, 6: 18, 7: 8, 8: 1} |  | ||||
| 810 -> {5: 11, 6: 54, 7: 40, 8: 7} |  | ||||
| 895 -> {6: 72, 7: 208, 8: 120} |  | ||||
| 1784 -> {5: 2, 6: 1} |  | ||||
| 2276 -> {5: 4, 6: 4} |  | ||||
| 2447 -> {5: 2, 6: 11} |  | ||||
| 15162 -> {3: 1, 4: 1} |  | ||||
| 17588 -> {4: 2} |  | ||||
| 18271 -> {4: 1} |  | ||||
| 43243 -> {3: 3, 4: 1} |  | ||||
| 48554 -> {3: 3, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 122124 -> {2: 1} |  | ||||
| 342265 -> {2: 1} |  | ||||
| 367146 -> {2: 1} |  | ||||
| 
 |  | ||||
| head = 1 |  | ||||
| 0 -> {7: 9, 8: 165, 9: 1464, 10: 10920, 11: 54215, 12: 130359, 13: 151147, 14: 81673, 15: 16369} |  | ||||
| 1 -> {9: 1320, 10: 14456, 11: 47280, 12: 64758, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 226, 9: 1104, 10: 1518, 11: 800, 12: 170, 13: 12} |  | ||||
| 3 -> {7: 21, 8: 88, 9: 113, 10: 59, 11: 13, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 105, 9: 3036, 10: 14421, 11: 24700, 12: 17221, 13: 4083} |  | ||||
| 10 -> {7: 21, 8: 264, 9: 565, 10: 413, 11: 117, 12: 11} |  | ||||
| 15 -> {8: 352, 9: 2938, 10: 7080, 11: 6526, 12: 2036} |  | ||||
| 16 -> {6: 1, 7: 12, 8: 18, 9: 8, 10: 1} |  | ||||
| 32 -> {7: 24, 8: 72, 9: 48, 10: 8} |  | ||||
| 43 -> {7: 12, 8: 198, 9: 456, 10: 247} |  | ||||
| 57 -> {6: 7, 7: 15, 8: 8, 9: 1} |  | ||||
| 98 -> {6: 7, 7: 45, 8: 40, 9: 7} |  | ||||
| 119 -> {7: 60, 8: 208, 9: 120} |  | ||||
| 190 -> {5: 2, 6: 12, 7: 12, 8: 3} |  | ||||
| 284 -> {6: 24, 7: 48, 8: 18} |  | ||||
| 327 -> {6: 12, 7: 132, 8: 171} |  | ||||
| 591 -> {5: 4, 6: 10, 7: 6, 8: 1} |  | ||||
| 810 -> {5: 4, 6: 30, 7: 30, 8: 7} |  | ||||
| 895 -> {6: 40, 7: 156, 8: 120} |  | ||||
| 15162 -> {4: 1} |  | ||||
| 17588 -> {4: 2} |  | ||||
| 18271 -> {4: 1} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 122124 -> {2: 1, 3: 1} |  | ||||
| 133652 -> {3: 2} |  | ||||
| 136383 -> {3: 1} |  | ||||
| 342265 -> {2: 1} |  | ||||
| 367146 -> {2: 1} |  | ||||
| 953662 -> {1: 1} |  | ||||
| 
 |  | ||||
| head = 2 |  | ||||
| 0 -> {7: 24, 8: 359, 9: 2838, 10: 19461, 11: 85764, 12: 181037, 13: 185611, 14: 89839, 15: 16369} |  | ||||
| 1 -> {9: 2556, 10: 24076, 11: 67800, 12: 80822, 13: 42756, 14: 8178} |  | ||||
| 2 -> {8: 460, 9: 1932, 10: 2262, 11: 1024, 12: 190, 13: 12} |  | ||||
| 3 -> {7: 44, 8: 165, 9: 179, 10: 79, 11: 15, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 222, 9: 5313, 10: 21489, 11: 31616, 12: 19247, 13: 4083} |  | ||||
| 10 -> {7: 44, 8: 495, 9: 895, 10: 553, 11: 135, 12: 11} |  | ||||
| 15 -> {8: 660, 9: 4654, 10: 9480, 11: 7530, 12: 2036} |  | ||||
| 16 -> {6: 2, 7: 19, 8: 27, 9: 10, 10: 1} |  | ||||
| 32 -> {7: 38, 8: 108, 9: 60, 10: 8} |  | ||||
| 43 -> {7: 19, 8: 297, 9: 570, 10: 247} |  | ||||
| 57 -> {6: 14, 7: 23, 8: 9, 9: 1} |  | ||||
| 98 -> {6: 14, 7: 69, 8: 45, 9: 7} |  | ||||
| 119 -> {7: 92, 8: 234, 9: 120} |  | ||||
| 190 -> {5: 5, 6: 23, 7: 18, 8: 3} |  | ||||
| 284 -> {6: 46, 7: 72, 8: 18} |  | ||||
| 327 -> {6: 23, 7: 198, 8: 171} |  | ||||
| 591 -> {5: 7, 6: 16, 7: 8, 8: 1} |  | ||||
| 810 -> {5: 7, 6: 48, 7: 40, 8: 7} |  | ||||
| 895 -> {6: 64, 7: 208, 8: 120} |  | ||||
| 5245 -> {4: 2, 5: 1} |  | ||||
| 6346 -> {4: 2, 5: 3} |  | ||||
| 6687 -> {5: 4} |  | ||||
| 15162 -> {3: 1, 4: 1} |  | ||||
| 17588 -> {4: 2} |  | ||||
| 18271 -> {4: 1} |  | ||||
| 43243 -> {3: 3, 4: 1} |  | ||||
| 48554 -> {3: 3, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 122124 -> {2: 1} |  | ||||
| 342265 -> {2: 1} |  | ||||
| 367146 -> {2: 1} |  | ||||
| 
 |  | ||||
| head = 4 |  | ||||
| 0 -> {7: 13, 8: 186, 9: 1638, 10: 12049, 11: 58254, 12: 135573, 13: 153173, 14: 81673, 15: 16369} |  | ||||
| 1 -> {9: 1464, 10: 15808, 11: 50040, 12: 66264, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 244, 9: 1172, 10: 1584, 11: 816, 12: 170, 13: 12} |  | ||||
| 3 -> {7: 21, 8: 92, 9: 115, 10: 59, 11: 13, 12: 1} |  | ||||
| 5 -> {8: 122, 9: 3223, 10: 15048, 11: 25194, 12: 17221, 13: 4083} |  | ||||
| 10 -> {7: 21, 8: 276, 9: 575, 10: 413, 11: 117, 12: 11} |  | ||||
| 15 -> {8: 368, 9: 2990, 10: 7080, 11: 6526, 12: 2036} |  | ||||
| 16 -> {7: 4, 8: 12, 9: 7, 10: 1} |  | ||||
| 32 -> {7: 8, 8: 48, 9: 42, 10: 8} |  | ||||
| 43 -> {7: 4, 8: 132, 9: 399, 10: 247} |  | ||||
| 190 -> {5: 2, 6: 8, 7: 6, 8: 1} |  | ||||
| 284 -> {6: 16, 7: 24, 8: 6} |  | ||||
| 327 -> {6: 8, 7: 66, 8: 57} |  | ||||
| 591 -> {5: 7, 6: 16, 7: 8, 8: 1} |  | ||||
| 810 -> {5: 7, 6: 48, 7: 40, 8: 7} |  | ||||
| 895 -> {6: 64, 7: 208, 8: 120} |  | ||||
| 1784 -> {4: 1, 5: 3, 6: 1} |  | ||||
| 2276 -> {5: 6, 6: 4} |  | ||||
| 2447 -> {5: 3, 6: 11} |  | ||||
| 5245 -> {4: 4, 5: 5, 6: 1} |  | ||||
| 6346 -> {4: 4, 5: 15, 6: 5} |  | ||||
| 6687 -> {5: 20, 6: 26} |  | ||||
| 15162 -> {3: 1, 4: 1} |  | ||||
| 17588 -> {4: 2} |  | ||||
| 18271 -> {4: 1} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 342265 -> {2: 1} |  | ||||
| 367139 -> {2: 1} |  | ||||
| 953634 -> {1: 1} |  | ||||
| 
 |  | ||||
| head = 5 |  | ||||
| 0 -> {7: 5, 8: 124, 9: 1161, 10: 8742, 11: 43440, 12: 105459, 13: 126813, 14: 73507, 15: 16369} |  | ||||
| 1 -> {9: 1044, 10: 11492, 11: 37800, 12: 53714, 13: 34612, 14: 8178} |  | ||||
| 2 -> {8: 162, 9: 840, 10: 1176, 11: 648, 12: 150, 13: 12} |  | ||||
| 3 -> {7: 11, 8: 55, 9: 77, 10: 44, 11: 11, 12: 1} |  | ||||
| 5 -> {8: 81, 9: 2310, 10: 11172, 11: 20007, 12: 15195, 13: 4083} |  | ||||
| 10 -> {7: 11, 8: 165, 9: 385, 10: 308, 11: 99, 12: 11} |  | ||||
| 15 -> {8: 220, 9: 2002, 10: 5280, 11: 5522, 12: 2036} |  | ||||
| 190 -> {5: 1, 6: 6, 7: 5, 8: 1} |  | ||||
| 284 -> {6: 12, 7: 20, 8: 6} |  | ||||
| 327 -> {6: 6, 7: 55, 8: 57} |  | ||||
| 591 -> {5: 7, 6: 14, 7: 7, 8: 1} |  | ||||
| 810 -> {5: 7, 6: 42, 7: 35, 8: 7} |  | ||||
| 895 -> {6: 56, 7: 182, 8: 120} |  | ||||
| 1784 -> {4: 2, 5: 9, 6: 6, 7: 1} |  | ||||
| 2276 -> {5: 18, 6: 24, 7: 6} |  | ||||
| 2447 -> {5: 9, 6: 66, 7: 57} |  | ||||
| 5245 -> {4: 5, 5: 5, 6: 1} |  | ||||
| 6346 -> {4: 5, 5: 15, 6: 5} |  | ||||
| 6687 -> {5: 20, 6: 26} |  | ||||
| 15162 -> {3: 2, 4: 4, 5: 1} |  | ||||
| 17588 -> {4: 8, 5: 4} |  | ||||
| 18271 -> {4: 4, 5: 11} |  | ||||
| 43243 -> {3: 3, 4: 1} |  | ||||
| 48548 -> {3: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 122103 -> {2: 1} |  | ||||
| 122124 -> {2: 1, 3: 1} |  | ||||
| 133652 -> {3: 2} |  | ||||
| 136382 -> {3: 1} |  | ||||
| 342265 -> {2: 1} |  | ||||
| 367139 -> {2: 1} |  | ||||
| 
 |  | ||||
| head = 6 |  | ||||
| 0 -> {7: 13, 8: 189, 9: 1635, 10: 11994, 11: 58832, 12: 137293, 13: 154186, 14: 81673, 15: 16369} |  | ||||
| 1 -> {9: 1464, 10: 15522, 11: 49200, 12: 65762, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 244, 9: 1172, 10: 1584, 11: 816, 12: 170, 13: 12} |  | ||||
| 3 -> {7: 13, 8: 68, 9: 101, 10: 57, 11: 13, 12: 1} |  | ||||
| 5 -> {8: 122, 9: 3223, 10: 15048, 11: 25194, 12: 17221, 13: 4083} |  | ||||
| 10 -> {7: 13, 8: 204, 9: 505, 10: 399, 11: 117, 12: 11} |  | ||||
| 15 -> {8: 272, 9: 2626, 10: 6840, 11: 6526, 12: 2036} |  | ||||
| 57 -> {6: 4, 7: 12, 8: 7, 9: 1} |  | ||||
| 98 -> {6: 4, 7: 36, 8: 35, 9: 7} |  | ||||
| 119 -> {7: 48, 8: 182, 9: 120} |  | ||||
| 190 -> {5: 2, 6: 8, 7: 6, 8: 1} |  | ||||
| 284 -> {6: 16, 7: 24, 8: 6} |  | ||||
| 327 -> {6: 8, 7: 66, 8: 57} |  | ||||
| 591 -> {5: 7, 6: 16, 7: 8, 8: 1} |  | ||||
| 810 -> {5: 7, 6: 48, 7: 40, 8: 7} |  | ||||
| 895 -> {6: 64, 7: 208, 8: 120} |  | ||||
| 1784 -> {4: 1, 5: 3, 6: 1} |  | ||||
| 2276 -> {5: 6, 6: 4} |  | ||||
| 2447 -> {5: 3, 6: 11} |  | ||||
| 5245 -> {4: 6, 5: 5, 6: 1} |  | ||||
| 6341 -> {4: 1} |  | ||||
| 6346 -> {4: 5, 5: 15, 6: 5} |  | ||||
| 6687 -> {5: 20, 6: 26} |  | ||||
| 15147 -> {3: 1} |  | ||||
| 15162 -> {3: 2, 4: 4} |  | ||||
| 17588 -> {4: 8} |  | ||||
| 18270 -> {4: 2} |  | ||||
| 18271 -> {4: 2} |  | ||||
| 43243 -> {3: 6, 4: 2} |  | ||||
| 48548 -> {3: 2} |  | ||||
| 48554 -> {3: 4, 4: 6} |  | ||||
| 49919 -> {4: 8} |  | ||||
| 122124 -> {2: 1, 3: 1} |  | ||||
| 133652 -> {3: 2} |  | ||||
| 136382 -> {3: 1} |  | ||||
| 
 |  | ||||
| head = 8 |  | ||||
| 0 -> {7: 18, 8: 204, 9: 1439, 10: 10794, 11: 54722, 12: 131998, 13: 152149, 14: 81673, 15: 16369} |  | ||||
| 1 -> {9: 1172, 10: 13130, 11: 43200, 12: 59738, 13: 36648, 14: 8178} |  | ||||
| 2 -> {8: 320, 9: 1368, 10: 1698, 11: 832, 12: 170, 13: 12} |  | ||||
| 3 -> {7: 30, 8: 133, 9: 163, 10: 77, 11: 15, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 152, 9: 3762, 10: 16131, 11: 25688, 12: 17221, 13: 4083} |  | ||||
| 10 -> {7: 30, 8: 399, 9: 815, 10: 539, 11: 135, 12: 11} |  | ||||
| 15 -> {8: 532, 9: 4238, 10: 9240, 11: 7530, 12: 2036} |  | ||||
| 16 -> {6: 5, 7: 26, 8: 29, 9: 10, 10: 1} |  | ||||
| 32 -> {7: 52, 8: 116, 9: 60, 10: 8} |  | ||||
| 43 -> {7: 26, 8: 319, 9: 570, 10: 247} |  | ||||
| 57 -> {6: 18, 7: 55, 8: 44, 9: 12, 10: 1} |  | ||||
| 98 -> {6: 18, 7: 165, 8: 220, 9: 84, 10: 9} |  | ||||
| 119 -> {7: 220, 8: 1144, 9: 1440, 10: 502} |  | ||||
| 190 -> {5: 2, 6: 8, 7: 6, 8: 1} |  | ||||
| 284 -> {6: 16, 7: 24, 8: 6} |  | ||||
| 327 -> {6: 8, 7: 66, 8: 57} |  | ||||
| 591 -> {5: 17, 6: 23, 7: 9, 8: 1} |  | ||||
| 806 -> {5: 2} |  | ||||
| 810 -> {5: 15, 6: 69, 7: 45, 8: 7} |  | ||||
| 895 -> {6: 92, 7: 234, 8: 120} |  | ||||
| 1784 -> {4: 3, 5: 12, 6: 3} |  | ||||
| 2276 -> {5: 24, 6: 12} |  | ||||
| 2446 -> {5: 5} |  | ||||
| 2447 -> {5: 7, 6: 33} |  | ||||
| 5245 -> {4: 11, 5: 8, 6: 1} |  | ||||
| 6346 -> {4: 11, 5: 24, 6: 5} |  | ||||
| 6687 -> {5: 32, 6: 26} |  | ||||
| 15162 -> {3: 3, 4: 6, 5: 1} |  | ||||
| 17588 -> {4: 12, 5: 4} |  | ||||
| 18271 -> {4: 6, 5: 11} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 
 |  | ||||
| head = 9 |  | ||||
| 0 -> {7: 5, 8: 103, 9: 863, 10: 6189, 11: 32410, 12: 85591, 13: 111607, 14: 69424, 15: 16369} |  | ||||
| 1 -> {9: 748, 10: 8866, 11: 31440, 12: 47690, 13: 32576, 14: 8178} |  | ||||
| 2 -> {8: 154, 9: 812, 10: 1164, 11: 648, 12: 150, 13: 12} |  | ||||
| 3 -> {7: 25, 8: 110, 9: 138, 10: 68, 11: 14, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 69, 9: 2233, 10: 11058, 11: 20007, 12: 15195, 13: 4083} |  | ||||
| 10 -> {7: 25, 8: 330, 9: 690, 10: 476, 11: 126, 12: 11} |  | ||||
| 15 -> {8: 440, 9: 3588, 10: 8160, 11: 7028, 12: 2036} |  | ||||
| 16 -> {6: 6, 7: 52, 8: 93, 9: 56, 10: 13, 11: 1} |  | ||||
| 32 -> {7: 104, 8: 372, 9: 336, 10: 104, 11: 10} |  | ||||
| 43 -> {7: 52, 8: 1023, 9: 3192, 10: 3211, 11: 1013} |  | ||||
| 57 -> {6: 19, 7: 58, 8: 45, 9: 12, 10: 1} |  | ||||
| 98 -> {6: 19, 7: 174, 8: 225, 9: 84, 10: 9} |  | ||||
| 119 -> {7: 232, 8: 1170, 9: 1440, 10: 502} |  | ||||
| 190 -> {5: 8, 6: 41, 7: 37, 8: 11, 9: 1} |  | ||||
| 284 -> {6: 82, 7: 148, 8: 66, 9: 8} |  | ||||
| 326 -> {6: 2} |  | ||||
| 327 -> {6: 39, 7: 407, 8: 627, 9: 247} |  | ||||
| 591 -> {5: 26, 6: 35, 7: 11, 8: 1} |  | ||||
| 806 -> {5: 2} |  | ||||
| 810 -> {5: 24, 6: 105, 7: 55, 8: 7} |  | ||||
| 895 -> {6: 140, 7: 286, 8: 120} |  | ||||
| 1784 -> {4: 5, 5: 20, 6: 10, 7: 1} |  | ||||
| 2276 -> {5: 40, 6: 40, 7: 6} |  | ||||
| 2446 -> {5: 3} |  | ||||
| 2447 -> {5: 17, 6: 110, 7: 57} |  | ||||
| 5245 -> {4: 7, 5: 5, 6: 1} |  | ||||
| 6346 -> {4: 7, 5: 15, 6: 5} |  | ||||
| 6687 -> {5: 20, 6: 26} |  | ||||
| 15162 -> {3: 2, 4: 3} |  | ||||
| 17588 -> {4: 6} |  | ||||
| 18271 -> {4: 3} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 
 |  | ||||
| head = 10 |  | ||||
| 0 -> {7: 18, 8: 222, 9: 1694, 10: 10423, 11: 48002, 12: 115822, 13: 137978, 14: 77590, 15: 16369} |  | ||||
| 1 -> {9: 1536, 10: 16406, 11: 51120, 12: 66766, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 320, 9: 1368, 10: 1698, 11: 832, 12: 170, 13: 12} |  | ||||
| 3 -> {7: 30, 8: 133, 9: 163, 10: 77, 11: 15, 12: 1} |  | ||||
| 4 -> {8: 8} |  | ||||
| 5 -> {8: 152, 9: 3762, 10: 16131, 11: 25688, 12: 17221, 13: 4083} |  | ||||
| 10 -> {7: 30, 8: 399, 9: 815, 10: 539, 11: 135, 12: 11} |  | ||||
| 15 -> {8: 532, 9: 4238, 10: 9240, 11: 7530, 12: 2036} |  | ||||
| 16 -> {6: 5, 7: 26, 8: 29, 9: 10, 10: 1} |  | ||||
| 32 -> {7: 52, 8: 116, 9: 60, 10: 8} |  | ||||
| 43 -> {7: 26, 8: 319, 9: 570, 10: 247} |  | ||||
| 57 -> {6: 26, 7: 65, 8: 46, 9: 12, 10: 1} |  | ||||
| 98 -> {6: 26, 7: 195, 8: 230, 9: 84, 10: 9} |  | ||||
| 119 -> {7: 260, 8: 1196, 9: 1440, 10: 502} |  | ||||
| 190 -> {5: 6, 6: 40, 7: 27, 8: 4} |  | ||||
| 284 -> {6: 80, 7: 108, 8: 24} |  | ||||
| 326 -> {6: 4} |  | ||||
| 327 -> {6: 36, 7: 297, 8: 228} |  | ||||
| 591 -> {5: 31, 6: 52, 7: 20, 8: 2} |  | ||||
| 806 -> {5: 2} |  | ||||
| 810 -> {5: 29, 6: 156, 7: 100, 8: 14} |  | ||||
| 895 -> {6: 208, 7: 520, 8: 240} |  | ||||
| 1784 -> {4: 3, 5: 12, 6: 7, 7: 1} |  | ||||
| 2276 -> {5: 24, 6: 28, 7: 6} |  | ||||
| 2446 -> {5: 1} |  | ||||
| 2447 -> {5: 11, 6: 77, 7: 57} |  | ||||
| 5245 -> {4: 4, 5: 1} |  | ||||
| 6346 -> {4: 4, 5: 3} |  | ||||
| 6687 -> {5: 4} |  | ||||
| 15162 -> {3: 2, 4: 3} |  | ||||
| 17588 -> {4: 6} |  | ||||
| 18271 -> {4: 3} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 
 |  | ||||
| head = 12 |  | ||||
| 0 -> {7: 7, 8: 109, 9: 1467, 10: 14381, 11: 69851, 12: 155802, 13: 168367, 14: 85756, 15: 16369} |  | ||||
| 1 -> {9: 1368, 10: 15236, 11: 49080, 12: 65762, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 104, 9: 360, 10: 330, 11: 104, 12: 10} |  | ||||
| 3 -> {7: 53, 8: 199, 9: 210, 10: 89, 11: 16, 12: 1} |  | ||||
| 5 -> {8: 52, 9: 990, 10: 3135, 11: 3211, 12: 1013} |  | ||||
| 10 -> {7: 53, 8: 597, 9: 1050, 10: 623, 11: 144, 12: 11} |  | ||||
| 15 -> {8: 796, 9: 5460, 10: 10680, 11: 8032, 12: 2036} |  | ||||
| 16 -> {6: 6, 7: 69, 8: 85, 9: 30, 10: 3} |  | ||||
| 32 -> {7: 138, 8: 340, 9: 180, 10: 24} |  | ||||
| 42 -> {7: 7} |  | ||||
| 43 -> {7: 62, 8: 935, 9: 1710, 10: 741} |  | ||||
| 57 -> {6: 46, 7: 110, 8: 69, 9: 15, 10: 1} |  | ||||
| 95 -> {6: 5} |  | ||||
| 98 -> {6: 41, 7: 330, 8: 345, 9: 105, 10: 9} |  | ||||
| 119 -> {7: 440, 8: 1794, 9: 1800, 10: 502} |  | ||||
| 184 -> {5: 1} |  | ||||
| 190 -> {5: 9, 6: 53, 7: 48, 8: 13, 9: 1} |  | ||||
| 284 -> {6: 106, 7: 192, 8: 78, 9: 8} |  | ||||
| 326 -> {6: 4} |  | ||||
| 327 -> {6: 49, 7: 528, 8: 741, 9: 247} |  | ||||
| 591 -> {5: 15, 6: 23, 7: 9, 8: 1} |  | ||||
| 810 -> {5: 15, 6: 69, 7: 45, 8: 7} |  | ||||
| 895 -> {6: 92, 7: 234, 8: 120} |  | ||||
| 1784 -> {4: 1, 5: 4, 6: 1} |  | ||||
| 2276 -> {5: 8, 6: 4} |  | ||||
| 2447 -> {5: 4, 6: 11} |  | ||||
| 5245 -> {4: 4, 5: 1} |  | ||||
| 6346 -> {4: 4, 5: 3} |  | ||||
| 6687 -> {5: 4} |  | ||||
| 15162 -> {3: 2, 4: 3} |  | ||||
| 17588 -> {4: 6} |  | ||||
| 18271 -> {4: 3} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 
 |  | ||||
| head = 13 |  | ||||
| 0 -> {7: 21, 8: 281, 9: 1934, 10: 16983, 11: 94877, 12: 239808, 13: 286889, 14: 159250, 15: 32738} |  | ||||
| 1 -> {9: 1516, 10: 16068, 11: 50280, 12: 66264, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 424, 9: 1768, 10: 2046, 11: 936, 12: 180, 13: 12} |  | ||||
| 3 -> {7: 90, 8: 315, 9: 303, 10: 114, 11: 18, 12: 1} |  | ||||
| 4 -> {8: 3} |  | ||||
| 5 -> {8: 209, 9: 4862, 10: 19437, 11: 28899, 12: 18234, 13: 4083} |  | ||||
| 8 -> {7: 4} |  | ||||
| 10 -> {7: 86, 8: 945, 9: 1515, 10: 798, 11: 162, 12: 11} |  | ||||
| 13 -> {6: 1} |  | ||||
| 15 -> {8: 1260, 9: 7878, 10: 13680, 11: 9036, 12: 2036} |  | ||||
| 16 -> {6: 14, 7: 128, 8: 188, 9: 92, 10: 17, 11: 1} |  | ||||
| 32 -> {7: 256, 8: 752, 9: 552, 10: 136, 11: 10} |  | ||||
| 42 -> {7: 12} |  | ||||
| 43 -> {7: 116, 8: 2068, 9: 5244, 10: 4199, 11: 1013} |  | ||||
| 57 -> {6: 27, 7: 68, 8: 47, 9: 12, 10: 1} |  | ||||
| 95 -> {6: 2} |  | ||||
| 98 -> {6: 25, 7: 204, 8: 235, 9: 84, 10: 9} |  | ||||
| 119 -> {7: 272, 8: 1222, 9: 1440, 10: 502} |  | ||||
| 190 -> {5: 5, 6: 27, 7: 19, 8: 3} |  | ||||
| 284 -> {6: 54, 7: 76, 8: 18} |  | ||||
| 327 -> {6: 27, 7: 209, 8: 171} |  | ||||
| 591 -> {5: 15, 6: 23, 7: 9, 8: 1} |  | ||||
| 810 -> {5: 15, 6: 69, 7: 45, 8: 7} |  | ||||
| 895 -> {6: 92, 7: 234, 8: 120} |  | ||||
| 1784 -> {4: 1, 5: 4, 6: 1} |  | ||||
| 2276 -> {5: 8, 6: 4} |  | ||||
| 2447 -> {5: 4, 6: 11} |  | ||||
| 5245 -> {4: 4, 5: 1} |  | ||||
| 6346 -> {4: 4, 5: 3} |  | ||||
| 6687 -> {5: 4} |  | ||||
| 15162 -> {3: 2, 4: 3} |  | ||||
| 17588 -> {4: 6} |  | ||||
| 18271 -> {4: 3} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| 
 |  | ||||
| head = 14 |  | ||||
| 0 -> {7: 20, 8: 320, 9: 2120, 10: 15011, 11: 70061, 12: 155823, 13: 168367, 14: 85756, 15: 16369} |  | ||||
| 1 -> {9: 1808, 10: 17524, 11: 51960, 12: 66766, 13: 38684, 14: 8178} |  | ||||
| 2 -> {8: 460, 9: 1652, 10: 1470, 11: 440, 12: 40} |  | ||||
| 3 -> {7: 114, 8: 444, 9: 476, 10: 198, 11: 34, 12: 2} |  | ||||
| 4 -> {8: 16} |  | ||||
| 5 -> {8: 214, 9: 4543, 10: 13965, 11: 13585, 12: 4052} |  | ||||
| 8 -> {7: 4} |  | ||||
| 10 -> {7: 110, 8: 1332, 9: 2380, 10: 1386, 11: 306, 12: 22} |  | ||||
| 15 -> {8: 1776, 9: 12376, 10: 23760, 11: 17068, 12: 4072} |  | ||||
| 16 -> {6: 9, 7: 77, 8: 119, 9: 65, 10: 14, 11: 1} |  | ||||
| 32 -> {7: 154, 8: 476, 9: 390, 10: 112, 11: 10} |  | ||||
| 42 -> {7: 4} |  | ||||
| 43 -> {7: 73, 8: 1309, 9: 3705, 10: 3458, 11: 1013} |  | ||||
| 57 -> {6: 15, 7: 26, 8: 10, 9: 1} |  | ||||
| 98 -> {6: 15, 7: 78, 8: 50, 9: 7} |  | ||||
| 119 -> {7: 104, 8: 260, 9: 120} |  | ||||
| 190 -> {5: 5, 6: 27, 7: 19, 8: 3} |  | ||||
| 284 -> {6: 54, 7: 76, 8: 18} |  | ||||
| 327 -> {6: 27, 7: 209, 8: 171} |  | ||||
| 591 -> {5: 15, 6: 23, 7: 9, 8: 1} |  | ||||
| 810 -> {5: 15, 6: 69, 7: 45, 8: 7} |  | ||||
| 895 -> {6: 92, 7: 234, 8: 120} |  | ||||
| 1784 -> {4: 1, 5: 4, 6: 1} |  | ||||
| 2276 -> {5: 8, 6: 4} |  | ||||
| 2447 -> {5: 4, 6: 11} |  | ||||
| 5245 -> {4: 4, 5: 1} |  | ||||
| 6346 -> {4: 4, 5: 3} |  | ||||
| 6687 -> {5: 4} |  | ||||
| 15162 -> {3: 2, 4: 3} |  | ||||
| 17588 -> {4: 6} |  | ||||
| 18271 -> {4: 3} |  | ||||
| 43243 -> {3: 2, 4: 1} |  | ||||
| 48554 -> {3: 2, 4: 3} |  | ||||
| 49919 -> {4: 4} |  | ||||
| """ |  | ||||
| @ -1,9 +1,13 @@ | |||||
| #pragma once | #pragma once | ||||
| 
 | 
 | ||||
|  | #include <algorithm> | ||||
|  | #include <gtest/gtest.h> | ||||
|  | 
 | ||||
| #include "exposer.h" | #include "exposer.h" | ||||
| #include "all_cases.h" |  | ||||
| #include "concurrent.h" | #include "concurrent.h" | ||||
| #include "gtest/gtest.h" | #include "all_cases/all_cases.h" | ||||
|  | 
 | ||||
|  | using klotski::array_sum; | ||||
| 
 | 
 | ||||
| using klotski::cases::AllCases; | using klotski::cases::AllCases; | ||||
| using klotski::cases::BasicRanges; | using klotski::cases::BasicRanges; | ||||
| @ -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; | ||||
|  | } | ||||
| @ -0,0 +1,76 @@ | |||||
|  | #pragma once | ||||
|  | 
 | ||||
|  | #include <array> | ||||
|  | #include <algorithm> | ||||
|  | 
 | ||||
|  | #include "group/group.h" | ||||
|  | #include "all_cases/all_cases.h" | ||||
|  | 
 | ||||
|  | using klotski::cases::Ranges; | ||||
|  | using klotski::cases::AllCases; | ||||
|  | using klotski::codec::CommonCode; | ||||
|  | using klotski::cases::BasicRanges; | ||||
|  | using klotski::cases::RangesUnion; | ||||
|  | 
 | ||||
|  | using klotski::array_sum; | ||||
|  | using klotski::range_reverse; | ||||
|  | 
 | ||||
|  | using klotski::cases::BLOCK_NUM; | ||||
|  | using klotski::cases::ALL_CASES_NUM; | ||||
|  | using klotski::cases::ALL_CASES_NUM; | ||||
|  | using klotski::cases::BASIC_RANGES_NUM; | ||||
|  | using klotski::cases::BASIC_RANGES_NUM_; | ||||
|  | 
 | ||||
|  | /// All valid klotski heads.
 | ||||
|  | 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())); \ | ||||
|  |     EXPECT_EQ(std::ranges::adjacent_find(R.begin(), R.end()), R.end()) // no duplicates
 | ||||
|  | 
 | ||||
|  | /// Assert that two ordered arrays are in a containment relationship.
 | ||||
|  | #define EXPECT_SUBSET(R1, R2) \ | ||||
|  |     EXPECT_TRUE(std::ranges::includes(R1.begin(), R1.end(), R2.begin(), R2.end())) | ||||
|  | 
 | ||||
|  | /// Assert that all CommonCodes generated from head and Ranges are valid.
 | ||||
|  | #define EXPECT_COMMON_CODES(head, ranges) \ | ||||
|  |     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; | ||||
|  | }; | ||||
|  | 
 | ||||
|  | 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(); | ||||
| @ -0,0 +1,111 @@ | |||||
|  | #include <gtest/gtest.h> | ||||
|  | 
 | ||||
|  | #include "group/group.h" | ||||
|  | #include "helper/cases.h" | ||||
|  | #include "ranges/ranges.h" | ||||
|  | 
 | ||||
|  | static_assert(std::is_base_of_v<std::vector<uint32_t>, Ranges>); | ||||
|  | 
 | ||||
|  | TEST(Ranges, check) { | ||||
|  |     RangesUnion all_cases; | ||||
|  |     for (const auto head : Heads) { | ||||
|  |         for (auto range : BasicRanges::instance().fetch()) { | ||||
|  |             if (Ranges::check(head, range_reverse(range)) == 0) { | ||||
|  |                 all_cases[head].emplace_back(range); // found valid cases
 | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  |     EXPECT_EQ(all_cases, AllCases::instance().fetch()); | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(Ranges, spawn) { | ||||
|  |     for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) { | ||||
|  |         Ranges ranges; | ||||
|  |         ranges.spawn(n, n_2x1, n_1x1); | ||||
|  |         EXPECT_SORTED_AND_UNIQUE(ranges); // sorted and unique
 | ||||
|  | 
 | ||||
|  |         for (const auto range : ranges) { | ||||
|  |             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); // verify block nums
 | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(Ranges, derive) { | ||||
|  |     for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) { | ||||
|  |         Ranges ranges; | ||||
|  |         ranges.spawn(n, n_2x1, n_1x1); | ||||
|  |         ranges.reverse(); // reverse ranges for derive
 | ||||
|  | 
 | ||||
|  |         RangesUnion cases; | ||||
|  |         for (const auto head : Heads) { | ||||
|  |             ranges.derive(head, cases[head]); | ||||
|  |             EXPECT_SORTED_AND_UNIQUE(cases[head]); // sorted and unique
 | ||||
|  |             EXPECT_COMMON_CODES(head, cases[head]); // verify common codes
 | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         ranges.reverse(); | ||||
|  |         for (const auto head : Heads) { | ||||
|  |             EXPECT_SUBSET(ranges, cases[head]); // derive ranges is subset
 | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(Ranges, reverse) { | ||||
|  |     auto ranges = BasicRanges::instance().fetch(); | ||||
|  |     Ranges reverse {ranges}; | ||||
|  | 
 | ||||
|  |     for (auto &x : reverse) { | ||||
|  |         x = range_reverse(x); // manual reverse
 | ||||
|  |     } | ||||
|  |     ranges.reverse(); | ||||
|  |     EXPECT_EQ(ranges, reverse); | ||||
|  | 
 | ||||
|  |     ranges.reverse(); | ||||
|  |     EXPECT_EQ(ranges, BasicRanges::instance().fetch()); | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(Ranges, combine) { | ||||
|  |     Ranges all_ranges; | ||||
|  |     RangesUnion all_cases; | ||||
|  | 
 | ||||
|  |     all_ranges.reserve(BASIC_RANGES_NUM_); // pre reserve
 | ||||
|  |     for (const auto head : Heads) { | ||||
|  |         all_cases[head].reserve(ALL_CASES_NUM[head]); // pre reserve
 | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) { | ||||
|  |         Ranges ranges; | ||||
|  |         ranges.spawn(n, n_2x1, n_1x1); | ||||
|  |         all_ranges += ranges; | ||||
|  |         ranges.reverse(); // reverse ranges for derive
 | ||||
|  |         for (const auto head : Heads) { | ||||
|  |             ranges.derive(head, all_cases[head]); // derive from sub ranges
 | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     std::ranges::stable_sort(all_ranges.begin(), all_ranges.end()); | ||||
|  |     for (const auto head : Heads) { | ||||
|  |         std::ranges::stable_sort(all_cases[head].begin(), all_cases[head].end()); | ||||
|  |     } | ||||
|  |     EXPECT_EQ(all_ranges, BasicRanges::instance().fetch()); // verify content
 | ||||
|  |     EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify content
 | ||||
|  | 
 | ||||
|  |     all_ranges.reverse(); // reverse ranges for derive
 | ||||
|  |     for (const auto head : Heads) { | ||||
|  |         all_cases[head].clear(); | ||||
|  |         all_ranges.derive(head, all_cases[head]); // derive from all ranges
 | ||||
|  |     } | ||||
|  |     EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify content
 | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(Ranges, operator) { | ||||
|  |     Ranges r, r1, r2; | ||||
|  |     r.spawn(5, 3, 4); | ||||
|  |     r.spawn(5, 4, 4); | ||||
|  |     r1.spawn(5, 3, 4); | ||||
|  |     r2.spawn(5, 4, 4); | ||||
|  |     EXPECT_EQ(r, r1 += r2); | ||||
|  | } | ||||
| @ -0,0 +1,35 @@ | |||||
|  | #include <gtest/gtest.h> | ||||
|  | 
 | ||||
|  | #include <format> | ||||
|  | 
 | ||||
|  | #include "hash.h" | ||||
|  | #include "helper/cases.h" | ||||
|  | #include "ranges/ranges.h" | ||||
|  | 
 | ||||
|  | static_assert(std::is_base_of_v<std::array<Ranges, 16>, RangesUnion>); | ||||
|  | 
 | ||||
|  | constexpr std::string_view ALL_CASES_MD5 = "3888e9fab8d3cbb50908b12b147cfb23"; | ||||
|  | 
 | ||||
|  | TEST(RangesUnion, export) { | ||||
|  |     std::string buffer; | ||||
|  |     for (auto code : AllCases::instance().fetch().codes()) { | ||||
|  |         buffer += std::format("{:09X}\n", code.unwrap()); | ||||
|  |     } | ||||
|  |     EXPECT_EQ(hash::md5(buffer), ALL_CASES_MD5); | ||||
|  | } | ||||
|  | 
 | ||||
|  | TEST(RangesUnion, operator) { | ||||
|  |     Ranges r, r1, r2; | ||||
|  |     r.spawn(5, 3, 4); | ||||
|  |     r.spawn(5, 4, 4); | ||||
|  |     r1.spawn(5, 3, 4); | ||||
|  |     r2.spawn(5, 4, 4); | ||||
|  | 
 | ||||
|  |     RangesUnion r_, r1_, r2_; | ||||
|  |     for (const auto head : Heads) { | ||||
|  |         r.derive(head, r_[head]); | ||||
|  |         r1.derive(head, r1_[head]); | ||||
|  |         r2.derive(head, r2_[head]); | ||||
|  |     } | ||||
|  |     EXPECT_EQ(r_, r1_ += r2_); | ||||
|  | } | ||||
					Loading…
					
					
				
		Reference in new issue