Browse Source

refactor: interfaces of Group module

master
Dnomd343 2 months ago
parent
commit
ffe34cdb63
  1. 156
      src/core/group/group.h
  2. 18
      src/core/group/internal/group.cc
  3. 23
      src/core/group/internal/group.inl
  4. 18
      src/core/main.cc

156
src/core/group/group.h

@ -23,21 +23,21 @@
/// can also be reversed to get the number of blocks, which are one by one
/// corresponding.
///
/// flag => | 0xxx | 0xxx | xxxx |
/// (12-bit) | (n_1x2 + n_2x1) | (n_2x1) | (n_1x1) |
/// flag => | xxx | xxx | xxxx |
/// (10-bit) | (n_1x2 + n_2x1) | (n_2x1) | (n_1x1) |
/// | (0 ~ 7) | (0 ~ 7) | (0 ~ 14) |
///
/// flag => ((n_1x2 + n_2x1) << 8) | (n_2x1 << 4) | (n_1x1)
/// flag => ((n_1x2 + n_2x1) << 7) | (n_2x1 << 3) | (n_1x1)
///
/// Using the table lookup method, the `type_id` of any case can be obtained
/// within O(1), which is encapsulated in `GroupType`.
/// within O(1), which is encapsulated in `GroupUnion`.
/// Since the `type_id` cannot change when moving, all cases belonging to the
/// same `type_id` must be divided into different groups (of course there may
/// be only one). For a group, list the CommonCodes of all its cases, the
/// smallest of which is called the group's `seed`. List all the groups under
/// the same `type_id`, and arrange them from large to small, and arrange the
/// groups of the same size from small to large according to the `seed`, and
/// groups of the same size from small to large according to the `seed`, then
/// start numbering from 0 to get the `group_id`.
/// All cases of the same group will have the same `type_id` and `group_id`,
@ -51,14 +51,14 @@
///
/// Eg1: 1A9BF0C00 -> `169-1-7472`
/// Eg2: 4FEA13400 -> `164-0-30833`
///
/// The range of `type_id` is [0, 203), the maximum `group_id` is 2652 (there
/// are 2653 groups when `type_id` is 164), the maximum `case_id` is 964655
/// (there are 964656 cases when `type_id` is 58 and `group_id` is 0).
/// Therefore, these three numbers meet the following range requirements.
/// are 2653 groups when `type_id = 164`), the maximum `case_id` is 964655
/// (there are 964656 cases when `type_id = 58` & `group_id = 0`). Therefore,
/// these three numbers meet the following range requirements.
///
/// type_id < 203 | group_id < 2653 | case_id < 964656
/// (8-bit ~ 256) | (12-bit ~ 4096) | (20-bit ~ 1048576)
/// | type_id: [0, 203) | group_id: [0, 2653) | case_id: [0, 964656) |
/// | (8-bit ~ 256) | (12-bit ~ 4096) | (20-bit ~ 1048576) |
///
/// Typically, these three variables are generally recorded in decimal and
/// displayed in the form of strings. They can facilitate the relationship
@ -67,103 +67,117 @@
#pragma once
#include "raw_code/raw_code.h"
#include "short_code/short_code.h"
#include "common_code/common_code.h"
static_assert(sizeof(int) == 4);
namespace klotski::cases {
class Group;
// TODO: should we expose block_num_t ?
class GroupUnion {
public:
GroupUnion() = delete;
// TODO: flat_iter for Groups ?
// ------------------------------------------------------------------------------------- //
// TODO: should we make sure the thread safe of GroupUnion / Group ?
/// Get the original type id.
[[nodiscard]] int type_id() const;
/// RSC -> block_num_t <-> type_id -> group_num
/// |-----> max_size
/// Get the number of cases contained.
[[nodiscard]] uint32_t size() const;
/// RSC -> seed <-> type_id + group_id -> cases
/// Get the number of groups contained.
[[nodiscard]] uint32_t group_num() const;
/// info_t <-> RSC
/// Get the upper limit of the group size.
[[nodiscard]] uint32_t max_group_size() const;
class GroupUnion {
public:
/// 1. n_1x1 + (n_1x2 + n_2x1) * 2 <= 14
/// 2. (n_1x1 != 0) && (n_2x1 != 7)
struct block_num_t {
uint8_t n_1x1 = 0; /// [0, 14]
uint8_t n_1x2 = 0; /// [0, 7]
uint8_t n_2x1 = 0; /// [0, 7]
};
/// n_space = 16 - n_1x1 - (n_1x2 + n_2x1) * 2
/// Get all group instances under the current type id.
[[nodiscard]] std::vector<Group> groups() const;
GroupUnion() = delete;
// TODO: disallow copy or move
/// Get the group instance with the specified group id.
[[nodiscard]] std::optional<Group> group(int group_id) const;
private:
// TODO: only store type_id_
int type_id_ {};
// ------------------------------------------------------------------------------------- //
// TODO: only allow private build (std::bit_cast directly)
explicit GroupUnion(const int type_id) : type_id_(type_id) {}
// TODO: fast convert from RawCode / CommonCode -> block_num_t
static block_num_t block_num(codec::RawCode raw_code);
static block_num_t block_num(codec::CommonCode common_code);
// TODO: should we impl type_id -> block_num ?
/// Create GroupUnion from type id.
static std::optional<GroupUnion> from_id(int type_id);
// TODO: convert from block_num -> type_id
static int type_id(block_num_t block_num);
public:
// TODO: allow convert from RawCode / ShortCode / CommonCode
// TODO: GroupUnion will fetch from static singleton (203 instances)
/// Create GroupUnion from RawCode.
static GroupUnion from_raw_code(codec::RawCode raw_code);
/// Create GroupUnion from ShortCode.
static GroupUnion from_short_code(codec::RawCode short_code);
/// Create GroupUnion from CommonCode.
static GroupUnion from_common_code(codec::CommonCode common_code);
// TODO: fetch singleton from type_id
static std::optional<GroupUnion> from_type_id(int type_id);
// ------------------------------------------------------------------------------------- //
// TODO: get Group from local (init by seed)
[[nodiscard]] Group group(int group_id);
private:
int type_id_ {};
// TODO: GroupUnion do not storage cases (new version)
// TODO: only allow private build (std::bit_cast directly)
// explicit GroupUnion(const int type_id) : type_id_(type_id) {}
};
class Group {
private:
// TODO: Group init by `seed`
// TODO: Group will also storage parent's type_id (or maybe not)
public:
Group() = delete;
// TODO: fetch group size directly
[[nodiscard]] uint32_t size() const;
void build();
// TODO: maybe define CommonCodes here
// TODO: get all cases from current Group
const std::vector<codec::CommonCode>& cases();
static Group from_raw_code(codec::RawCode raw_code);
static Group from_common_code(codec::CommonCode common_code);
private:
int type_id_;
int group_id_; // -> seed / size
int group_id_;
explicit Group(int type_id, int group_id) : type_id_(type_id), group_id_(group_id) {}
// TODO: only allow cast from struct directly.
// explicit Group(int type_id, int group_id) : type_id_(type_id), group_id_(group_id) {}
// TODO: add mutex on the build process
// TODO: mutex only in inner impl class.
// bool available_;
// std::mutex building_;
};
class GroupCase {
public:
// TODO: iter all Groups like a flat array ?
struct info_t {
uint16_t type_id; // TODO: int or uint ?
uint16_t group_id;
uint32_t group_index;
};
Group() = delete;
// TODO: mark as instance.
// TODO: maybe define CommonCodes here
// TODO: get all cases from current Group
const std::vector<codec::CommonCode>& cases();
/// Build group cases accelerated index.
static void speed_up();
// TODO: can we fetch Group directly from here ?
// args: type_id & group_id
/// Get the CommonCode using the group info.
static codec::CommonCode parse(const info_t &info);
// TODO: fetch group size directly
[[nodiscard]] uint32_t size() const;
};
/// Get group info according to specified case.
static info_t encode(const codec::RawCode &raw_code);
static info_t encode(const codec::CommonCode &common_code);
private:
static bool available_;
static std::mutex building_;
static codec::CommonCode fast_decode(const info_t &info);
static codec::CommonCode tiny_decode(const info_t &info);
// TODO: fast convert from info_t <--> CommonCode / RawCode
static info_t fast_encode(const codec::CommonCode &common_code);
static info_t tiny_encode(const codec::CommonCode &common_code);
};
} // namespace klotski::cases

18
src/core/group/internal/group.cc

@ -1 +1,19 @@
#include "group/group.h"
/// 1. n_1x1 + (n_1x2 + n_2x1) * 2 <= 14
/// 2. (n_1x1 != 0) && (n_2x1 != 7)
struct block_num_t {
uint8_t n_1x1 = 0; /// [0, 14]
uint8_t n_1x2 = 0; /// [0, 7]
uint8_t n_2x1 = 0; /// [0, 7]
};
/// n_space = 16 - n_1x1 - (n_1x2 + n_2x1) * 2
// TODO: fast convert from RawCode / CommonCode -> block_num_t
static block_num_t block_num(klotski::codec::RawCode raw_code);
static block_num_t block_num(klotski::codec::CommonCode common_code);
// TODO: should we impl type_id -> block_num ?
// TODO: convert from block_num -> type_id
static int type_id(block_num_t block_num);

23
src/core/group/internal/group.inl

@ -0,0 +1,23 @@
#pragma once
// namespace internal {
//
// class GroupImpl {
// public:
// explicit GroupImpl(int flat_id) : flat_id_(flat_id) {}
//
// const std::vector<codec::CommonCode>& cases();
//
// int flat_id_;
//
// static constexpr std::array<GroupImpl, 6> ins() {
// return std::array<GroupImpl, 6> {};
// }
// };
//
// } // namespace internal
//
// inline const std::vector<codec::CommonCode>& Group::cases() {
// static auto kk = internal::GroupImpl::ins();
// return kk[0].cases();
// }

18
src/core/main.cc

@ -2,6 +2,7 @@
#include <iostream>
#include "core/core.h"
#include "group/group.h"
#include "raw_code/raw_code.h"
#include "fast_cal/fast_cal.h"
#include "all_cases/all_cases.h"
@ -16,6 +17,7 @@ using klotski::cases::BasicRanges;
using klotski::codec::RawCode;
using klotski::codec::ShortCode;
using klotski::codec::CommonCode;
using klotski::cases::GroupUnion;
using klotski::codec::SHORT_CODE_LIMIT;
@ -29,7 +31,7 @@ int main() {
// core.next_cases(RawCode::from_common_code(0x1A9BF0C00).value().unwrap(), 0x0);
// auto cal = FastCal(RawCode::from_common_code(0x1A9BF0C00).value());
auto cal = FastCal(RawCode::from_common_code("25EEF04").value());
// auto cal = FastCal(RawCode::from_common_code("25EEF04").value());
// auto ret = cal.solve();
//
@ -37,13 +39,13 @@ int main() {
// std::cout << kk.to_common_code() << "," << kk.to_common_code().to_short_code() << std::endl;
// }
for (const auto solve : cal.solve_multi()) {
for (const auto raw_code : cal.backtrack(solve)) {
const auto common_code = raw_code.to_common_code();
std::cout << common_code << "/" << common_code.to_short_code() << std::endl;
}
std::cout << "----" << std::endl;
}
// for (const auto solve : cal.solve_multi()) {
// for (const auto raw_code : cal.backtrack(solve)) {
// const auto common_code = raw_code.to_common_code();
// std::cout << common_code << "/" << common_code.to_short_code() << std::endl;
// }
// std::cout << "----" << std::endl;
// }
std::cerr << ((clock() - start) * 1000 / CLOCKS_PER_SEC) << "ms" << std::endl;

Loading…
Cancel
Save