diff --git a/src/klotski_core/raw_code/convert.cc b/src/klotski_core/raw_code/convert.cc index 8c26aeb..20f3d89 100644 --- a/src/klotski_core/raw_code/convert.cc +++ b/src/klotski_core/raw_code/convert.cc @@ -8,17 +8,17 @@ using klotski::RawCodeException; /// -------------------------- RawCode to CommonCode -------------------------- CommonCode RawCode::to_common_code() const noexcept { - return CommonCode::unsafe_create(RawCode::compact(code)); + return CommonCode::unsafe_create(RawCode::compact(code_)); } /// -------------------------- CommonCode to RawCode -------------------------- 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 { - 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) { diff --git a/src/klotski_core/raw_code/mirror.cc b/src/klotski_core/raw_code/mirror.cc index af42727..77a92bc 100644 --- a/src/klotski_core/raw_code/mirror.cc +++ b/src/klotski_core/raw_code/mirror.cc @@ -6,37 +6,37 @@ using klotski::RawCode; /// ----------------------------- Mirror Convert ------------------------------ 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 { - return RawCode::unsafe_create(horizontal_mirror(code)); + return RawCode::unsafe_create(get_horizontal_mirror(code_)); } /// ------------------------------ Mirror Check ------------------------------- bool RawCode::is_vertical_mirror() const noexcept { - return vertical_mirror_check(code); + return check_vertical_mirror(code_); } 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 { - 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 { - 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 { - 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 { - return raw_code.unwrap() == horizontal_mirror(code); + return raw_code.unwrap() == get_horizontal_mirror(code_); } /// ----------------------------- 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) { 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) { case B_2x1: case B_2x2: 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) { case B_2x1: 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) { - 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) { case B_1x2: 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) { - 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) { case B_2x1: case B_2x2: @@ -109,7 +109,7 @@ inline void vertical_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) { case B_1x2: 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); raw_code = (raw_code & MASK_MIRROR_V3) | ((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; } -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); 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 @@ -135,13 +135,13 @@ uint64_t RawCode::horizontal_mirror(uint64_t raw_code) noexcept { 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); return !(MASK_MIRROR_V1 & ((raw_code >> 48) ^ 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); return !(MASK_MIRROR_H1 & ((raw_code >> 9) ^ raw_code)) && !(MASK_MIRROR_H2 & ((raw_code >> 3) ^ raw_code)); diff --git a/src/klotski_core/raw_code/raw_code.cc b/src/klotski_core/raw_code/raw_code.cc index 58170d9..2c87a1c 100644 --- a/src/klotski_core/raw_code/raw_code.cc +++ b/src/klotski_core/raw_code/raw_code.cc @@ -1,70 +1,42 @@ #include "common.h" #include "raw_code.h" -using klotski::RawCode; - -namespace std { - template<> - struct hash { - std::size_t operator()(const klotski::RawCode &c) const { - return std::hash()(c.unwrap()); - } - }; - - template<> - struct equal_to { - bool operator()(const klotski::RawCode &c1, const klotski::RawCode &c2) const { - return c1.unwrap() == c2.unwrap(); - } - }; -} - namespace klotski { - bool RawCode::operator==(const RawCode &raw_code) const noexcept { - return this->code == raw_code.code; - } - - bool RawCode::operator!=(const RawCode &raw_code) const noexcept { - return this->code != raw_code.code; - } - std::ostream& operator<<(std::ostream &out, const RawCode &self) { - char code[16]; - char dump_map[] = { - /// 0x0 1x2 2x1 1x1 2x2 b101 b110 fill - '.', '~', '|', '*', '@', '?', '?', '+' - }; - sprintf(code, "%015lX", self.code); // code length -> 15 - out << code << '\n'; - for (int addr = 0; addr < 60; addr += 3) { - out << dump_map[(self.code >> addr) & 0b111]; - out << " " << &"\n"[(addr & 0b11) != 0b01]; - } - return out; - } +bool RawCode::valid() const noexcept { + return RawCode::check(code_); } -namespace klotski { - bool RawCode::valid() const noexcept { - return RawCode::check(code); - } +RawCode RawCode::create(uint64_t raw_code) { + return RawCode(raw_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::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; +} - RawCode::RawCode(uint64_t raw_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) { + char code[16]; + char dump_map[] = { + /// 0x0 1x2 2x1 1x1 2x2 b101 b110 fill + '.', '~', '|', '*', '@', '?', '?', '+' + }; + sprintf(code, "%015lX", self.code_); // code length -> 15 + out << code << '\n'; + for (int addr = 0; addr < 60; addr += 3) { + out << dump_map[(self.code_ >> addr) & 0b111]; + out << " " << &"\n"[(addr & 0b11) != 0b01]; } + return out; } bool RawCode::check(uint64_t raw_code) noexcept { // check whether raw code is valid @@ -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_2x2 = MASK_1x1 << 3 | MASK_1x1 << 12 | MASK_1x1 << 15; 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 for (int addr = 0; addr < 20; ++addr, raw_code >>= 3) { 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 } + +} // namespace klotski diff --git a/src/klotski_core/raw_code/raw_code.h b/src/klotski_core/raw_code/raw_code.h index 18bc520..7dbd306 100644 --- a/src/klotski_core/raw_code/raw_code.h +++ b/src/klotski_core/raw_code/raw_code.h @@ -1,14 +1,14 @@ #pragma once /// 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, -/// occupying a total of 60-bits, and stored in a `uint64_t` variable. Among them, the -/// upper 4-bits are reserved and filled with `0`. +/// encodes a `5x4` chessboard as `0 ~ 19`, and uses 3-bit to represent each position, +/// occupying a total of 60-bit, and stored in a `uint64_t` variable. Among them, the +/// upper 4-bit are reserved and filled with `0`. /// /// 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) -/// 12 13 14 15 (4b) + (3b) * 20 => 64-bits +/// 12 13 14 15 (4b) + (3b) * 20 => 64-bit /// 16 17 18 19 /// /// Eg1: @@ -44,73 +44,75 @@ #include "common_code.h" namespace klotski { - class CommonCode; // import for convert interface - - class RawCodeException : public std::runtime_error { - public: - RawCodeException() : std::runtime_error("invalid raw code") {} - explicit RawCodeException(const std::string &msg) : std::runtime_error(msg) {} - ~RawCodeException() noexcept override = default; - }; - - class RawCode { - uint64_t code; - RawCode() = default; // unsafe initialize - - 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 vertical_mirror(uint64_t raw_code) noexcept; // to vertical mirror - static inline uint64_t horizontal_mirror(uint64_t raw_code) noexcept; // to horizontal mirror - - static inline bool vertical_mirror_check(uint64_t raw_code) noexcept; // check vertical mirror - static inline bool horizontal_mirror_check(uint64_t raw_code) noexcept; // check horizontal mirror - - public: - /// RawCode validity check - bool valid() const noexcept; - static bool check(uint64_t raw_code) noexcept; - - /// Operators of RawCode - bool operator==(const RawCode &raw_code) const noexcept; - 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); - - /// Export functions - CommonCode to_common_code() const noexcept; - constexpr uint64_t unwrap() const noexcept { return code; } - - /// RawCode constructors - explicit RawCode(uint64_t raw_code); - explicit RawCode(CommonCode &&common_code) noexcept; - explicit RawCode(const CommonCode &common_code) noexcept; - - /// Static initialization - static RawCode create(uint64_t raw_code); - static RawCode unsafe_create(uint64_t raw_code) noexcept; - - static RawCode from_common_code(uint64_t common_code); - static RawCode from_common_code(CommonCode &&common_code) noexcept; - static RawCode from_common_code(std::string &&common_code); - static RawCode from_common_code(const CommonCode &common_code) noexcept; - static RawCode from_common_code(const std::string &common_code); - - /// Mirror functions - RawCode to_vertical_mirror() const noexcept; - RawCode to_horizontal_mirror() const noexcept; - - bool is_vertical_mirror() const noexcept; // whether vertically symmetrical - bool is_horizontal_mirror() const noexcept; // whether horizontally symmetrical - - bool is_vertical_mirror(RawCode &&raw_code) const noexcept; // whether vertically symmetric to another - bool is_vertical_mirror(const RawCode &raw_code) const noexcept; - bool is_horizontal_mirror(RawCode &&raw_code) const noexcept; // whether horizontally symmetric to another - bool is_horizontal_mirror(const RawCode &raw_code) const noexcept; - }; - - 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; } -} + +class CommonCode; + +class RawCodeException : public std::runtime_error { +public: + RawCodeException() : std::runtime_error("invalid raw code") {} + explicit RawCodeException(const std::string &msg) : std::runtime_error(msg) {} + ~RawCodeException() noexcept override = default; +}; + +class RawCode { + uint64_t code_; + RawCode() = default; // unsafe initialize + + 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 get_vertical_mirror(uint64_t raw_code) noexcept; + static inline uint64_t get_horizontal_mirror(uint64_t raw_code) noexcept; + + static inline bool check_vertical_mirror(uint64_t raw_code) noexcept; + static inline bool check_horizontal_mirror(uint64_t raw_code) noexcept; + +public: + /// Validity check + bool valid() const noexcept; + static bool check(uint64_t raw_code) noexcept; + + /// Operators of RawCode + constexpr explicit operator uint64_t() const noexcept { return code_; } + friend std::ostream& operator<<(std::ostream &out, const RawCode &self); + + /// Export functions + CommonCode to_common_code() const noexcept; + constexpr uint64_t unwrap() const noexcept { return code_; } + + /// RawCode constructors + explicit RawCode(uint64_t raw_code); + explicit RawCode(CommonCode &&common_code) noexcept; + explicit RawCode(const CommonCode &common_code) noexcept; + + /// Static initialization + static RawCode create(uint64_t raw_code); + static RawCode unsafe_create(uint64_t raw_code) noexcept; + + static RawCode from_common_code(uint64_t common_code); + static RawCode from_common_code(CommonCode &&common_code) noexcept; + static RawCode from_common_code(std::string &&common_code); + static RawCode from_common_code(const CommonCode &common_code) noexcept; + static RawCode from_common_code(const std::string &common_code); + + /// Mirror functions + RawCode to_vertical_mirror() const noexcept; + RawCode to_horizontal_mirror() const noexcept; + + bool is_vertical_mirror() const noexcept; // whether vertically symmetrical + bool is_horizontal_mirror() const noexcept; // whether horizontally symmetrical + + bool is_vertical_mirror(RawCode &&raw_code) const noexcept; // whether vertically symmetric to another + bool is_vertical_mirror(const RawCode &raw_code) const noexcept; + bool is_horizontal_mirror(RawCode &&raw_code) const noexcept; // whether horizontally symmetric to another + bool is_horizontal_mirror(const RawCode &raw_code) const noexcept; +}; + +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, 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