Browse Source

refactor: enhance BasicRanges and AllCases module

master
Dnomd343 4 weeks ago
parent
commit
9c07f56c21
  1. 10
      src/core/all_cases/all_cases.h
  2. 12
      src/core/all_cases/all_cases_fwd.h
  3. 24
      src/core/all_cases/internal/all_cases.cc
  4. 30
      src/core/all_cases/internal/basic_ranges.cc

10
src/core/all_cases/all_cases.h

@ -13,7 +13,7 @@
/// situations. Therefore, each combination can produce different permutations, /// situations. Therefore, each combination can produce different permutations,
/// after mathematical calculations, there are a total of `7311885` possible /// after mathematical calculations, there are a total of `7311885` possible
/// permutations. The goal of BasicRanges is to find these permutations, sort /// permutations. The goal of BasicRanges is to find these permutations, sort
/// them and store in a uint32_t array. /// them and store in an uint32_t array.
/// AllCases is used to generate all valid CommonCodes, its works based on all /// AllCases is used to generate all valid CommonCodes, its works based on all
/// permutations generated by BasicRanges, which will use different 2x2 block /// permutations generated by BasicRanges, which will use different 2x2 block
@ -29,7 +29,7 @@
/// 16 17 18 19 12 13 14 /// 16 17 18 19 12 13 14
/// After all the work is done, we will have 29334498 cases, distributed in 16 /// After all the work is done, we will have 29334498 cases, distributed in 16
/// arrays. Each of them is a uint32_t array storing the ranges, which can be /// arrays. Each of them is an uint32_t array storing the ranges, which can be
/// used to save memory, otherwise the 64-bit length must be consumed. /// used to save memory, otherwise the 64-bit length must be consumed.
/// By the way, due to the performance considerations of the checking process, /// By the way, due to the performance considerations of the checking process,
@ -42,13 +42,9 @@
#include <mutex> #include <mutex>
#include "utils/utility.h" #include "utils/utility.h"
#include "ranges/ranges_fwd.h"
#include "internal/constant.inl" #include "internal/constant.inl"
namespace klotski::cases {
class Ranges;
class RangesUnion;
} // namespace klotski::cases
namespace klotski::cases { namespace klotski::cases {
// ----------------------------------------------------------------------------------------- // // ----------------------------------------------------------------------------------------- //

12
src/core/all_cases/all_cases_fwd.h

@ -0,0 +1,12 @@
/// Klotski Engine by Dnomd343 @2024
#pragma once
#include "internal/constant.inl"
namespace klotski::cases {
class AllCases;
class BasicRanges;
} // namespace klotski::cases

24
src/core/all_cases/internal/all_cases.cc

@ -1,27 +1,21 @@
#include "ranges/ranges.h"
#include "all_cases/all_cases.h" #include "all_cases/all_cases.h"
using klotski::range_reverse;
using klotski::cases::Ranges; using klotski::cases::Ranges;
using klotski::cases::AllCases; using klotski::cases::AllCases;
using klotski::cases::BasicRanges; using klotski::cases::BasicRanges;
using klotski::cases::ALL_CASES_NUM;
typedef std::array<int, 12> Heads; using klotski::range_reverse;
using klotski::cases::ALL_CASES_NUM;
/// Generate all possible klotski heads. /// Generate all possible klotski heads.
static consteval Heads get_heads() { static consteval std::array<int, 12> get_heads() {
Heads heads {}; // TODO: why faster than using `constexpr` directly
for (int i = 0, head = 0; head < 15; ++head) { return {0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE};
if (head % 4 != 3) {
heads[i++] = head;
}
}
return heads;
} }
/// Build all valid ranges of the specified head. /// Build all valid ranges of the specified head.
static void build_cases(const std::vector<uint32_t> &ranges, static void build_cases(const Ranges &ranges, const Ranges &reversed, Ranges &release, const int head) {
const std::vector<uint32_t> &reversed, Ranges &release, const int head) {
release.clear(); release.clear();
release.reserve(ALL_CASES_NUM[head]); release.reserve(ALL_CASES_NUM[head]);
@ -60,7 +54,7 @@ void AllCases::build() {
} }
const auto &ranges = BasicRanges::instance().fetch(); const auto &ranges = BasicRanges::instance().fetch();
std::vector reversed {ranges}; Ranges reversed {ranges};
for (auto &x : reversed) { for (auto &x : reversed) {
x = range_reverse(x); x = range_reverse(x);
} }
@ -84,7 +78,7 @@ void AllCases::build_async(Executor &&executor, Notifier &&callback) {
} }
auto &ranges = BasicRanges::instance().fetch(); auto &ranges = BasicRanges::instance().fetch();
auto reversed = std::make_shared<std::vector<uint32_t>>(ranges); auto reversed = std::make_shared<Ranges>(ranges);
for (auto &x : *reversed) { for (auto &x : *reversed) {
x = range_reverse(x); x = range_reverse(x);
} }

30
src/core/all_cases/internal/basic_ranges.cc

@ -6,31 +6,15 @@
using klotski::cases::Ranges; using klotski::cases::Ranges;
using klotski::cases::BasicRanges; using klotski::cases::BasicRanges;
using klotski::group::BLOCK_NUM;
using klotski::group::TYPE_ID_LIMIT; using klotski::group::TYPE_ID_LIMIT;
using RangesIter = Ranges::iterator ; using RangesIter = Ranges::iterator;
using RangeType = std::tuple<int, int, int> ;
using RangeTypeUnion = std::array<RangeType, TYPE_ID_LIMIT>;
/// Generate all possible basic-ranges permutations.
consteval static RangeTypeUnion range_types() {
RangeTypeUnion data;
for (int i = 0, n = 0; n <= 7; ++n) { // 1x2 + 2x1 -> 0 ~ 7
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) { // 2x1 -> 0 ~ n
if (n_2x1 == 7) {
break;
}
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // 1x1 -> 0 ~ (14 - 2n)
data[i++] = {n, n_2x1, n_1x1};
}
}
}
return data;
}
/// Combine two consecutive sorted arrays into one sorted arrays. /// Combine two consecutive sorted arrays into one sorted arrays.
static void inplace_merge(RangesIter begin, RangesIter mid, const RangesIter end) { static void inplace_merge(RangesIter begin, RangesIter mid, const RangesIter end) {
std::vector<uint32_t> tmp {begin, mid}; // left array backup std::vector<Ranges::value_type> tmp {begin, mid}; // left array backup
for (auto p = tmp.begin();;) { for (auto p = tmp.begin();;) {
if (*p <= *mid) { if (*p <= *mid) {
*(begin++) = *(p++); // stored in original span *(begin++) = *(p++); // stored in original span
@ -59,7 +43,7 @@ void BasicRanges::build() {
auto &ranges = get_ranges(); auto &ranges = get_ranges();
ranges.clear(); ranges.clear();
ranges.reserve(BASIC_RANGES_NUM_); ranges.reserve(BASIC_RANGES_NUM_);
for (auto [n, n_2x1, n_1x1] : range_types()) { for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) {
ranges.spawn(n, n_2x1, n_1x1); ranges.spawn(n, n_2x1, n_1x1);
} }
@ -106,7 +90,7 @@ void BasicRanges::build_async(Executor &&executor, Notifier &&callback) {
for (uint32_t i = 0; i < TYPE_ID_LIMIT; ++i) { for (uint32_t i = 0; i < TYPE_ID_LIMIT; ++i) {
(*cache)[i].reserve(BASIC_RANGES_NUM[i]); (*cache)[i].reserve(BASIC_RANGES_NUM[i]);
worker.post([cache, i] { worker.post([cache, i] {
auto [n, n_2x1, n_1x1] = range_types()[i]; auto [n, n_2x1, n_1x1] = BLOCK_NUM[i];
(*cache)[i].spawn(n, n_2x1, n_1x1); (*cache)[i].spawn(n, n_2x1, n_1x1);
}); });
} }
@ -146,6 +130,6 @@ void BasicRanges::build_async(Executor &&executor, Notifier &&callback) {
self(self); // next sort round self(self); // next sort round
}); });
}; };
inner_sort(inner_sort); // TODO: using `this auto &&self` in new version inner_sort(inner_sort); // TODO: using `this auto &&self` in new compiler
}); });
} }

Loading…
Cancel
Save