Browse Source

update: enhance RawCode module

legacy
Dnomd343 2 years ago
parent
commit
eb1967dec0
  1. 6
      src/klotski_core/raw_code/convert.cc
  2. 34
      src/klotski_core/raw_code/mirror.cc
  3. 65
      src/klotski_core/raw_code/raw_code.cc
  4. 36
      src/klotski_core/raw_code/raw_code.h

6
src/klotski_core/raw_code/convert.cc

@ -8,17 +8,17 @@ using klotski::RawCodeException;
/// -------------------------- RawCode to CommonCode -------------------------- /// -------------------------- RawCode to CommonCode --------------------------
CommonCode RawCode::to_common_code() const noexcept { CommonCode RawCode::to_common_code() const noexcept {
return CommonCode::unsafe_create(RawCode::compact(code)); return CommonCode::unsafe_create(RawCode::compact(code_));
} }
/// -------------------------- CommonCode to RawCode -------------------------- /// -------------------------- CommonCode to RawCode --------------------------
RawCode::RawCode(CommonCode &&common_code) noexcept { RawCode::RawCode(CommonCode &&common_code) noexcept {
code = RawCode::extract(common_code.unwrap()); // convert from common code code_ = RawCode::extract(common_code.unwrap()); // convert from common code
} }
RawCode::RawCode(const CommonCode &common_code) noexcept { RawCode::RawCode(const CommonCode &common_code) noexcept {
code = RawCode::extract(common_code.unwrap()); // convert from common code code_ = RawCode::extract(common_code.unwrap()); // convert from common code
} }
RawCode RawCode::from_common_code(uint64_t common_code) { RawCode RawCode::from_common_code(uint64_t common_code) {

34
src/klotski_core/raw_code/mirror.cc

@ -6,37 +6,37 @@ using klotski::RawCode;
/// ----------------------------- Mirror Convert ------------------------------ /// ----------------------------- Mirror Convert ------------------------------
RawCode RawCode::to_vertical_mirror() const noexcept { RawCode RawCode::to_vertical_mirror() const noexcept {
return RawCode::unsafe_create(vertical_mirror(code)); return RawCode::unsafe_create(get_vertical_mirror(code_));
} }
RawCode RawCode::to_horizontal_mirror() const noexcept { RawCode RawCode::to_horizontal_mirror() const noexcept {
return RawCode::unsafe_create(horizontal_mirror(code)); return RawCode::unsafe_create(get_horizontal_mirror(code_));
} }
/// ------------------------------ Mirror Check ------------------------------- /// ------------------------------ Mirror Check -------------------------------
bool RawCode::is_vertical_mirror() const noexcept { bool RawCode::is_vertical_mirror() const noexcept {
return vertical_mirror_check(code); return check_vertical_mirror(code_);
} }
bool RawCode::is_horizontal_mirror() const noexcept { bool RawCode::is_horizontal_mirror() const noexcept {
return horizontal_mirror_check(code); return check_horizontal_mirror(code_);
} }
bool RawCode::is_vertical_mirror(RawCode &&raw_code) const noexcept { bool RawCode::is_vertical_mirror(RawCode &&raw_code) const noexcept {
return raw_code.unwrap() == vertical_mirror(code); return raw_code.unwrap() == get_vertical_mirror(code_);
} }
bool RawCode::is_horizontal_mirror(RawCode &&raw_code) const noexcept { bool RawCode::is_horizontal_mirror(RawCode &&raw_code) const noexcept {
return raw_code.unwrap() == horizontal_mirror(code); return raw_code.unwrap() == get_horizontal_mirror(code_);
} }
bool RawCode::is_vertical_mirror(const RawCode &raw_code) const noexcept { bool RawCode::is_vertical_mirror(const RawCode &raw_code) const noexcept {
return raw_code.unwrap() == vertical_mirror(code); return raw_code.unwrap() == get_vertical_mirror(code_);
} }
bool RawCode::is_horizontal_mirror(const RawCode &raw_code) const noexcept { bool RawCode::is_horizontal_mirror(const RawCode &raw_code) const noexcept {
return raw_code.unwrap() == horizontal_mirror(code); return raw_code.unwrap() == get_horizontal_mirror(code_);
} }
/// ----------------------------- Basic Functions ----------------------------- /// ----------------------------- Basic Functions -----------------------------
@ -64,14 +64,14 @@ constexpr uint64_t MASK_MIRROR_V3 = 0x0'000'000'FFF'000'000;
inline void vertical_fill(uint64_t &raw_code) { inline void vertical_fill(uint64_t &raw_code) {
uint64_t mask = 0; uint64_t mask = 0;
for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bits for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bit
switch ((raw_code >> addr) & 0b111) { switch ((raw_code >> addr) & 0b111) {
case B_2x1: case B_2x1:
case B_2x2: case B_2x2:
mask |= (uint64_t)0b111 << (addr + 12); // generate fill mask mask |= (uint64_t)0b111 << (addr + 12); // generate fill mask
} }
} }
for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bits for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bit
switch ((raw_code | mask) >> addr & 0b111) { switch ((raw_code | mask) >> addr & 0b111) {
case B_2x1: case B_2x1:
raw_code &= ~(uint64_t(~B_2x1 & 0b111) << (addr + 12)); // fill vertical mirror raw_code &= ~(uint64_t(~B_2x1 & 0b111) << (addr + 12)); // fill vertical mirror
@ -84,7 +84,7 @@ inline void vertical_fill(uint64_t &raw_code) {
} }
inline void horizontal_fill(uint64_t &raw_code) { inline void horizontal_fill(uint64_t &raw_code) {
for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bits for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bit
switch ((raw_code >> addr) & 0b111) { switch ((raw_code >> addr) & 0b111) {
case B_1x2: case B_1x2:
raw_code &= ~(uint64_t(~B_1x2 & 0b111) << (addr + 3)); // fill horizontal mirror raw_code &= ~(uint64_t(~B_1x2 & 0b111) << (addr + 3)); // fill horizontal mirror
@ -99,7 +99,7 @@ inline void horizontal_fill(uint64_t &raw_code) {
} }
inline void vertical_clear(uint64_t &raw_code) { inline void vertical_clear(uint64_t &raw_code) {
for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bits for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bit
switch ((raw_code >> addr) & 0b111) { switch ((raw_code >> addr) & 0b111) {
case B_2x1: case B_2x1:
case B_2x2: case B_2x2:
@ -109,7 +109,7 @@ inline void vertical_clear(uint64_t &raw_code) {
} }
inline void horizontal_clear(uint64_t &raw_code) { inline void horizontal_clear(uint64_t &raw_code) {
for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bits for (int addr = 0; addr < 60; addr += 3) { // traverse every 3-bit
switch ((raw_code >> addr) & 0b111) { switch ((raw_code >> addr) & 0b111) {
case B_1x2: case B_1x2:
case B_2x2: case B_2x2:
@ -118,7 +118,7 @@ inline void horizontal_clear(uint64_t &raw_code) {
} }
} }
uint64_t RawCode::vertical_mirror(uint64_t raw_code) noexcept { uint64_t RawCode::get_vertical_mirror(uint64_t raw_code) noexcept {
vertical_fill(raw_code); vertical_fill(raw_code);
raw_code = (raw_code & MASK_MIRROR_V3) raw_code = (raw_code & MASK_MIRROR_V3)
| ((raw_code >> 48) & MASK_MIRROR_V1) | ((raw_code >> 24) & MASK_MIRROR_V2) | ((raw_code >> 48) & MASK_MIRROR_V1) | ((raw_code >> 24) & MASK_MIRROR_V2)
@ -127,7 +127,7 @@ uint64_t RawCode::vertical_mirror(uint64_t raw_code) noexcept {
return raw_code; return raw_code;
} }
uint64_t RawCode::horizontal_mirror(uint64_t raw_code) noexcept { uint64_t RawCode::get_horizontal_mirror(uint64_t raw_code) noexcept {
horizontal_fill(raw_code); horizontal_fill(raw_code);
raw_code = ((raw_code >> 9) & MASK_MIRROR_H1) | ((raw_code >> 3) & MASK_MIRROR_H2) raw_code = ((raw_code >> 9) & MASK_MIRROR_H1) | ((raw_code >> 3) & MASK_MIRROR_H2)
| ((raw_code & MASK_MIRROR_H2) << 3) | ((raw_code & MASK_MIRROR_H1) << 9); // flip raw code | ((raw_code & MASK_MIRROR_H2) << 3) | ((raw_code & MASK_MIRROR_H1) << 9); // flip raw code
@ -135,13 +135,13 @@ uint64_t RawCode::horizontal_mirror(uint64_t raw_code) noexcept {
return raw_code; return raw_code;
} }
bool RawCode::vertical_mirror_check(uint64_t raw_code) noexcept { bool RawCode::check_vertical_mirror(uint64_t raw_code) noexcept {
vertical_fill(raw_code); vertical_fill(raw_code);
return !(MASK_MIRROR_V1 & ((raw_code >> 48) ^ raw_code)) return !(MASK_MIRROR_V1 & ((raw_code >> 48) ^ raw_code))
&& !(MASK_MIRROR_V2 & ((raw_code >> 24) ^ raw_code)); && !(MASK_MIRROR_V2 & ((raw_code >> 24) ^ raw_code));
} }
bool RawCode::horizontal_mirror_check(uint64_t raw_code) noexcept { bool RawCode::check_horizontal_mirror(uint64_t raw_code) noexcept {
horizontal_fill(raw_code); horizontal_fill(raw_code);
return !(MASK_MIRROR_H1 & ((raw_code >> 9) ^ raw_code)) return !(MASK_MIRROR_H1 & ((raw_code >> 9) ^ raw_code))
&& !(MASK_MIRROR_H2 & ((raw_code >> 3) ^ raw_code)); && !(MASK_MIRROR_H2 & ((raw_code >> 3) ^ raw_code));

65
src/klotski_core/raw_code/raw_code.cc

@ -1,31 +1,27 @@
#include "common.h" #include "common.h"
#include "raw_code.h" #include "raw_code.h"
using klotski::RawCode; namespace klotski {
namespace std { bool RawCode::valid() const noexcept {
template<> return RawCode::check(code_);
struct hash<klotski::RawCode> {
std::size_t operator()(const klotski::RawCode &c) const {
return std::hash<uint64_t>()(c.unwrap());
} }
};
template<> RawCode RawCode::create(uint64_t raw_code) {
struct equal_to<klotski::RawCode> { return RawCode(raw_code);
bool operator()(const klotski::RawCode &c1, const klotski::RawCode &c2) const {
return c1.unwrap() == c2.unwrap();
}
};
} }
namespace klotski { RawCode RawCode::unsafe_create(uint64_t raw_code) noexcept { // create without check
bool RawCode::operator==(const RawCode &raw_code) const noexcept { auto tmp = RawCode(); // init directly
return this->code == raw_code.code; tmp.code_ = raw_code;
return tmp;
} }
bool RawCode::operator!=(const RawCode &raw_code) const noexcept { RawCode::RawCode(uint64_t raw_code) {
return this->code != raw_code.code; if (!RawCode::check(raw_code)) { // check input raw code
throw klotski::RawCodeException("raw code invalid");
}
code_ = raw_code;
} }
std::ostream& operator<<(std::ostream &out, const RawCode &self) { std::ostream& operator<<(std::ostream &out, const RawCode &self) {
@ -34,38 +30,14 @@ namespace klotski {
/// 0x0 1x2 2x1 1x1 2x2 b101 b110 fill /// 0x0 1x2 2x1 1x1 2x2 b101 b110 fill
'.', '~', '|', '*', '@', '?', '?', '+' '.', '~', '|', '*', '@', '?', '?', '+'
}; };
sprintf(code, "%015lX", self.code); // code length -> 15 sprintf(code, "%015lX", self.code_); // code length -> 15
out << code << '\n'; out << code << '\n';
for (int addr = 0; addr < 60; addr += 3) { for (int addr = 0; addr < 60; addr += 3) {
out << dump_map[(self.code >> addr) & 0b111]; out << dump_map[(self.code_ >> addr) & 0b111];
out << " " << &"\n"[(addr & 0b11) != 0b01]; out << " " << &"\n"[(addr & 0b11) != 0b01];
} }
return out; return out;
} }
}
namespace klotski {
bool RawCode::valid() const noexcept {
return RawCode::check(code);
}
RawCode RawCode::create(uint64_t raw_code) {
return RawCode(raw_code);
}
RawCode RawCode::unsafe_create(uint64_t raw_code) noexcept { // create without check
auto tmp = RawCode(); // init directly
tmp.code = raw_code;
return tmp;
}
RawCode::RawCode(uint64_t raw_code) {
if (!RawCode::check(raw_code)) { // check input raw code
throw klotski::RawCodeException("raw code invalid");
}
code = raw_code;
}
}
bool RawCode::check(uint64_t raw_code) noexcept { // check whether raw code is valid bool RawCode::check(uint64_t raw_code) noexcept { // check whether raw code is valid
/// MASK_1x1 | MASK_1x2 | MASK_2x1 | MASK_2x2 /// MASK_1x1 | MASK_1x2 | MASK_2x1 | MASK_2x2
@ -78,10 +50,9 @@ bool RawCode::check(uint64_t raw_code) noexcept { // check whether raw code is v
constexpr uint64_t MASK_2x1 = MASK_1x1 << 12; constexpr uint64_t MASK_2x1 = MASK_1x1 << 12;
constexpr uint64_t MASK_2x2 = MASK_1x1 << 3 | MASK_1x1 << 12 | MASK_1x1 << 15; constexpr uint64_t MASK_2x2 = MASK_1x1 << 3 | MASK_1x1 << 12 | MASK_1x1 << 15;
if (raw_code >> 60) { if (raw_code >> 60) {
return false; // high 4-bits must be zero return false; // high 4-bit must be zero
} }
/// check each block
int head_num = 0, space_num = 0; // statistics for space and 2x2 number int head_num = 0, space_num = 0; // statistics for space and 2x2 number
for (int addr = 0; addr < 20; ++addr, raw_code >>= 3) { for (int addr = 0; addr < 20; ++addr, raw_code >>= 3) {
switch (raw_code & 0b111) { switch (raw_code & 0b111) {
@ -116,3 +87,5 @@ bool RawCode::check(uint64_t raw_code) noexcept { // check whether raw code is v
} }
return head_num == 1 && space_num >= 2; // one head and at least 2 space return head_num == 1 && space_num >= 2; // one head and at least 2 space
} }
} // namespace klotski

36
src/klotski_core/raw_code/raw_code.h

@ -1,14 +1,14 @@
#pragma once #pragma once
/// RawCode is an uncompressed coding scheme, which is used for program calculation. It /// RawCode is an uncompressed coding scheme, which is used for program calculation. It
/// encodes a `5x4` chessboard as `0 ~ 19`, and uses 3-bits to represent each position, /// encodes a `5x4` chessboard as `0 ~ 19`, and uses 3-bit to represent each position,
/// occupying a total of 60-bits, and stored in a `uint64_t` variable. Among them, the /// occupying a total of 60-bit, and stored in a `uint64_t` variable. Among them, the
/// upper 4-bits are reserved and filled with `0`. /// upper 4-bit are reserved and filled with `0`.
/// ///
/// 00 01 02 03 /// 00 01 02 03
/// 04 05 06 07 fill 20-slots /// 04 05 06 07 fill 20 slots
/// 08 09 10 11 0000 (19) (18) (17) (16) ... (03) (02) (01) (00) /// 08 09 10 11 0000 (19) (18) (17) (16) ... (03) (02) (01) (00)
/// 12 13 14 15 (4b) + (3b) * 20 => 64-bits /// 12 13 14 15 (4b) + (3b) * 20 => 64-bit
/// 16 17 18 19 /// 16 17 18 19
/// ///
/// Eg1: /// Eg1:
@ -44,7 +44,8 @@
#include "common_code.h" #include "common_code.h"
namespace klotski { namespace klotski {
class CommonCode; // import for convert interface
class CommonCode;
class RawCodeException : public std::runtime_error { class RawCodeException : public std::runtime_error {
public: public:
@ -54,32 +55,30 @@ namespace klotski {
}; };
class RawCode { class RawCode {
uint64_t code; uint64_t code_;
RawCode() = default; // unsafe initialize RawCode() = default; // unsafe initialize
static inline uint64_t compact(uint64_t raw_code) noexcept; // raw code -> common code static inline uint64_t compact(uint64_t raw_code) noexcept; // raw code -> common code
static inline uint64_t extract(uint64_t common_code) noexcept; // common code -> raw code static inline uint64_t extract(uint64_t common_code) noexcept; // common code -> raw code
static inline uint64_t vertical_mirror(uint64_t raw_code) noexcept; // to vertical mirror static inline uint64_t get_vertical_mirror(uint64_t raw_code) noexcept;
static inline uint64_t horizontal_mirror(uint64_t raw_code) noexcept; // to horizontal mirror static inline uint64_t get_horizontal_mirror(uint64_t raw_code) noexcept;
static inline bool vertical_mirror_check(uint64_t raw_code) noexcept; // check vertical mirror static inline bool check_vertical_mirror(uint64_t raw_code) noexcept;
static inline bool horizontal_mirror_check(uint64_t raw_code) noexcept; // check horizontal mirror static inline bool check_horizontal_mirror(uint64_t raw_code) noexcept;
public: public:
/// RawCode validity check /// Validity check
bool valid() const noexcept; bool valid() const noexcept;
static bool check(uint64_t raw_code) noexcept; static bool check(uint64_t raw_code) noexcept;
/// Operators of RawCode /// Operators of RawCode
bool operator==(const RawCode &raw_code) const noexcept; constexpr explicit operator uint64_t() const noexcept { return code_; }
bool operator!=(const RawCode &raw_code) const noexcept;
constexpr explicit operator uint64_t() const noexcept { return code; }
friend std::ostream& operator<<(std::ostream &out, const RawCode &self); friend std::ostream& operator<<(std::ostream &out, const RawCode &self);
/// Export functions /// Export functions
CommonCode to_common_code() const noexcept; CommonCode to_common_code() const noexcept;
constexpr uint64_t unwrap() const noexcept { return code; } constexpr uint64_t unwrap() const noexcept { return code_; }
/// RawCode constructors /// RawCode constructors
explicit RawCode(uint64_t raw_code); explicit RawCode(uint64_t raw_code);
@ -113,4 +112,7 @@ namespace klotski {
inline bool operator!=(uint64_t r1, const RawCode &r2) noexcept { return r1 != r2.unwrap(); } inline bool operator!=(uint64_t r1, const RawCode &r2) noexcept { return r1 != r2.unwrap(); }
inline bool operator==(const RawCode &r1, uint64_t r2) noexcept { return r1.unwrap() == r2; } inline bool operator==(const RawCode &r1, uint64_t r2) noexcept { return r1.unwrap() == r2; }
inline bool operator!=(const RawCode &r1, uint64_t r2) noexcept { return r1.unwrap() != r2; } inline bool operator!=(const RawCode &r1, uint64_t r2) noexcept { return r1.unwrap() != r2; }
} inline bool operator==(const RawCode &r1, const RawCode &r2) noexcept { return r1.unwrap() == r2.unwrap(); }
inline bool operator!=(const RawCode &r1, const RawCode &r2) noexcept { return r1.unwrap() != r2.unwrap(); }
} // namespace klotski

Loading…
Cancel
Save