diff --git a/src/klotski_core/common_code/common_code.cc b/src/klotski_core/common_code/common_code.cc index 5230c4f..198a8d6 100644 --- a/src/klotski_core/common_code/common_code.cc +++ b/src/klotski_core/common_code/common_code.cc @@ -1,6 +1,8 @@ #include "common.h" #include "common_code.h" +using klotski::CommonCode; + namespace std { template<> struct hash { @@ -18,6 +20,10 @@ namespace std { } namespace klotski { + bool CommonCode::operator==(uint64_t common_code) const { + return this->code == common_code; + } + bool CommonCode::operator==(const CommonCode &common_code) const { return this->code == common_code.code; } @@ -53,7 +59,7 @@ namespace klotski { } } -bool klotski::CommonCode::check(uint64_t common_code) { // whether common code is valid +bool CommonCode::check(uint64_t common_code) { // whether common code is valid /// M_1x1 M_1x2 M_2x1 M_2x2 /// 1 0 0 0 1 1 0 0 1 0 0 0 1 1 0 0 /// 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 diff --git a/src/klotski_core/common_code/common_code.h b/src/klotski_core/common_code/common_code.h index 6bf2f3c..e82dca3 100644 --- a/src/klotski_core/common_code/common_code.h +++ b/src/klotski_core/common_code/common_code.h @@ -59,8 +59,7 @@ #include "short_code.h" namespace klotski { - // import for convert interface - class RawCode; + class RawCode; // import for convert interface class ShortCode; class CommonCodeException : public std::runtime_error { @@ -71,11 +70,19 @@ namespace klotski { }; class CommonCode { + uint64_t code; + CommonCode() = default; // unsafe initialize + + static inline uint64_t string_decode(const std::string &common_code); + static inline std::string string_encode(uint64_t common_code, bool shorten); + public: + /// CommonCode validity check bool valid() const; static bool check(uint64_t common_code); /// Operators of CommonCode + bool operator==(uint64_t common_code) const; bool operator==(const CommonCode &common_code) const; constexpr explicit operator uint64_t() const { return code; } friend std::ostream& operator<<(std::ostream &out, const CommonCode &self); @@ -88,24 +95,28 @@ namespace klotski { /// CommonCode constructors explicit CommonCode(uint64_t common_code); + explicit CommonCode(RawCode &&raw_code); + explicit CommonCode(ShortCode &&short_code); + explicit CommonCode(std::string &&common_code); explicit CommonCode(const RawCode &raw_code); explicit CommonCode(const ShortCode &short_code); explicit CommonCode(const std::string &common_code); - /// Rust-style initialization + /// Static initialization static CommonCode create(uint64_t common_code); static CommonCode unsafe_create(uint64_t common_code); + + static CommonCode from_string(std::string &&common_code); static CommonCode from_string(const std::string &common_code); static CommonCode from_raw_code(uint64_t raw_code); + static CommonCode from_raw_code(RawCode &&raw_code); static CommonCode from_raw_code(const RawCode &raw_code); static CommonCode from_short_code(uint32_t short_code); + static CommonCode from_short_code(ShortCode &&short_code); + static CommonCode from_short_code(std::string &&short_code); static CommonCode from_short_code(const ShortCode &short_code); static CommonCode from_short_code(const std::string &short_code); - - private: - uint64_t code; - CommonCode() = default; // unsafe initialize }; } diff --git a/src/klotski_core/common_code/convert.cc b/src/klotski_core/common_code/convert.cc index 7675688..28d023c 100644 --- a/src/klotski_core/common_code/convert.cc +++ b/src/klotski_core/common_code/convert.cc @@ -4,34 +4,62 @@ using klotski::RawCode; using klotski::ShortCode; using klotski::CommonCode; -/// CommonCode to RawCode +/// -------------------------- CommonCode to RawCode -------------------------- + RawCode CommonCode::to_raw_code() const { return RawCode(*this); // convert to raw code } -/// CommonCode to ShortCode +/// ------------------------- CommonCode to ShortCode ------------------------- + ShortCode CommonCode::to_short_code() const { return ShortCode(*this); // convert to short code } -/// RawCode to CommonCode +/// -------------------------- RawCode to CommonCode -------------------------- + CommonCode CommonCode::from_raw_code(uint64_t raw_code) { return RawCode(raw_code).to_common_code(); } +CommonCode CommonCode::from_raw_code(RawCode &&raw_code) { + return raw_code.to_common_code(); +} + CommonCode CommonCode::from_raw_code(const RawCode &raw_code) { return raw_code.to_common_code(); } +CommonCode::CommonCode(RawCode &&raw_code) { + code = raw_code.to_common_code().code; // convert from raw code +} + CommonCode::CommonCode(const RawCode &raw_code) { code = raw_code.to_common_code().code; // convert from raw code } -/// ShortCode to CommonCode +/// ------------------------- ShortCode to CommonCode ------------------------- + +CommonCode::CommonCode(ShortCode &&short_code) { + code = short_code.to_common_code().code; // convert from short code +} + +CommonCode::CommonCode(const ShortCode &short_code) { + code = short_code.to_common_code().code; // convert from short code +} + CommonCode CommonCode::from_short_code(uint32_t short_code) { return ShortCode(short_code).to_common_code(); } +CommonCode CommonCode::from_short_code(ShortCode &&short_code) { + return short_code.to_common_code(); +} + +CommonCode CommonCode::from_short_code(std::string &&short_code) { + return ShortCode(std::forward(short_code)).to_common_code(); +} + CommonCode CommonCode::from_short_code(const ShortCode &short_code) { return short_code.to_common_code(); } @@ -39,7 +67,3 @@ CommonCode CommonCode::from_short_code(const ShortCode &short_code) { CommonCode CommonCode::from_short_code(const std::string &short_code) { return ShortCode(short_code).to_common_code(); } - -CommonCode::CommonCode(const ShortCode &short_code) { - code = short_code.to_common_code().code; // convert from short code -} diff --git a/src/klotski_core/common_code/serialize.cc b/src/klotski_core/common_code/serialize.cc index 81bf169..7bee4b9 100644 --- a/src/klotski_core/common_code/serialize.cc +++ b/src/klotski_core/common_code/serialize.cc @@ -3,6 +3,32 @@ using klotski::CommonCode; using klotski::CommonCodeException; +/// -------------------------- CommonCode to String --------------------------- + +std::string CommonCode::to_string(bool shorten) const { + return string_encode(code, shorten); +} + +/// -------------------------- String to CommonCode --------------------------- + +CommonCode::CommonCode(std::string &&common_code) { + code = string_decode(common_code); // load from string +} + +CommonCode::CommonCode(const std::string &common_code) { + code = string_decode(common_code); // load from string +} + +CommonCode CommonCode::from_string(std::string &&common_code) { + return CommonCode(std::forward(common_code)); +} + +CommonCode CommonCode::from_string(const std::string &common_code) { + return CommonCode(common_code); +} + +/// ----------------------------- Basic Functions ----------------------------- + inline uint8_t binary_count(uint32_t bin) { // get number of non-zero bits bin -= (bin >> 1) & 0x55'55'55'55; bin = (bin & 0x33'33'33'33) + ((bin >> 2) & 0x33'33'33'33); @@ -18,28 +44,25 @@ inline uint8_t last_zero_num(uint32_t bin) { // get last zero number return binary_count(bin >> 1); } -CommonCode CommonCode::from_string(const std::string &common_code) { - return CommonCode(common_code); // load from string -} - -std::string CommonCode::to_string(bool shorten) const { // convert uint64_t code to string +std::string CommonCode::string_encode(uint64_t common_code, bool shorten) { // convert uint64_t code to string char result[10]; // max length 9-bits - sprintf(result, "%09lX", code); + sprintf(result, "%09lX", common_code); if (shorten) { // remove `0` after common code - if ((uint32_t)code == 0x00'00'00'00) { // low 32-bits are zero + if ((uint32_t)common_code == 0x00'00'00'00) { // low 32-bits are zero result[1] = '\0'; // only keep first character return result; } - result[9 - last_zero_num(code) / 4] = '\0'; // truncate string + result[9 - last_zero_num(common_code) / 4] = '\0'; // truncate string } return result; // char* -> std::string } -CommonCode::CommonCode(const std::string &common_code) { // convert from 1 ~ 9 bits string +uint64_t CommonCode::string_decode(const std::string &common_code) { // convert from 1 ~ 9 bits string /// check string length if (common_code.length() > 9 || common_code.empty()) { // check string length throw CommonCodeException("common code should length 1 ~ 9"); } + /// check every characters uint64_t result = 0; for (auto const &bit : common_code) { @@ -55,9 +78,10 @@ CommonCode::CommonCode(const std::string &common_code) { // convert from 1 ~ 9 b } } result <<= (9 - common_code.length()) * 4; // low-bits fill with zero + /// check whether common code is valid if (!CommonCode::check(result)) { // check converted common code throw CommonCodeException("common code invalid"); } - code = result; + return result; } diff --git a/src/klotski_core/raw_code/convert.cc b/src/klotski_core/raw_code/convert.cc index a0434e2..cd5c841 100644 --- a/src/klotski_core/raw_code/convert.cc +++ b/src/klotski_core/raw_code/convert.cc @@ -5,18 +5,20 @@ using klotski::RawCode; using klotski::CommonCode; using klotski::RawCodeException; -/// RawCode to CommonCode +/// -------------------------- RawCode to CommonCode -------------------------- + CommonCode RawCode::to_common_code() const { return CommonCode::unsafe_create(RawCode::compact(code)); } -/// CommonCode to RawCode +/// -------------------------- CommonCode to RawCode -------------------------- + RawCode::RawCode(CommonCode &&common_code) { - code = RawCode::extract(common_code.unwrap()); + code = RawCode::extract(common_code.unwrap()); // convert from common code } RawCode::RawCode(const CommonCode &common_code) { - code = RawCode::extract(common_code.unwrap()); + code = RawCode::extract(common_code.unwrap()); // convert from common code } RawCode RawCode::from_common_code(uint64_t common_code) { @@ -39,6 +41,8 @@ RawCode RawCode::from_common_code(const std::string &common_code) { return RawCode(CommonCode(common_code)); } +/// ----------------------------- Basic Functions ----------------------------- + /// NOTE: ensure that input raw code is valid! uint64_t RawCode::compact(uint64_t raw_code) { // raw code --> common code int unfilled = 16; diff --git a/src/klotski_core/raw_code/mirror.cc b/src/klotski_core/raw_code/mirror.cc index 76173bd..46b5d1f 100644 --- a/src/klotski_core/raw_code/mirror.cc +++ b/src/klotski_core/raw_code/mirror.cc @@ -4,15 +4,11 @@ using klotski::RawCode; /// Mirror convert functions RawCode RawCode::to_vertical_mirror() const { - - // TODO: vertical mirror convert - + return RawCode::unsafe_create(vertical_mirror(code)); } RawCode RawCode::to_horizontal_mirror() const { - - // TODO: horizontal mirror convert - + return RawCode::unsafe_create(horizontal_mirror(code)); } /// Mirror check functions @@ -20,34 +16,55 @@ bool RawCode::is_vertical_mirror() const { // TODO: vertical mirror check + return false; } bool RawCode::is_horizontal_mirror() const { // TODO: horizontal mirror check + return false; } bool RawCode::is_vertical_mirror(RawCode &&raw_code) const { // TODO: vertical mirror check + return false; } bool RawCode::is_vertical_mirror(const RawCode &raw_code) const { // TODO: vertical mirror check + return false; } bool RawCode::is_horizontal_mirror(RawCode &&raw_code) const { // TODO: horizontal mirror check + return false; } bool RawCode::is_horizontal_mirror(const RawCode &raw_code) const { // TODO: horizontal mirror check + return false; +} + +/// Basic mirror convert +uint64_t RawCode::vertical_mirror(uint64_t raw_code) { + + // TODO: vertical mirror convert + + return 0; +} + +uint64_t RawCode::horizontal_mirror(uint64_t raw_code) { + + // TODO: horizontal mirror convert + + return 0; } diff --git a/src/klotski_core/raw_code/raw_code.h b/src/klotski_core/raw_code/raw_code.h index 230eff1..b17c65d 100644 --- a/src/klotski_core/raw_code/raw_code.h +++ b/src/klotski_core/raw_code/raw_code.h @@ -60,6 +60,9 @@ namespace klotski { static uint64_t compact(uint64_t raw_code); // raw code -> common code static uint64_t extract(uint64_t common_code); // common code -> raw code + static uint64_t vertical_mirror(uint64_t raw_code); // to vertical mirror + static uint64_t horizontal_mirror(uint64_t raw_code); // to horizontal mirror + public: /// RawCode validity check bool valid() const; diff --git a/src/klotski_core/short_code/convert.cc b/src/klotski_core/short_code/convert.cc index 598e28a..2a4e234 100644 --- a/src/klotski_core/short_code/convert.cc +++ b/src/klotski_core/short_code/convert.cc @@ -9,7 +9,8 @@ using klotski::ShortCode; using klotski::CommonCode; -/// ShortCode to CommonCode +/// ------------------------- ShortCode to CommonCode ------------------------- + CommonCode ShortCode::to_common_code() const { if (ShortCode::mode() == ShortCode::NORMAL) { return CommonCode::unsafe_create(tiny_decode(code)); // normal mode @@ -17,7 +18,8 @@ CommonCode ShortCode::to_common_code() const { return CommonCode::unsafe_create(fast_decode(code)); // fast mode } -/// CommonCode to ShortCode +/// ------------------------- ShortCode to CommonCode ------------------------- + ShortCode::ShortCode(CommonCode &&common_code) { if (ShortCode::mode() == ShortCode::NORMAL) { code = tiny_encode(common_code.unwrap()); // normal mode @@ -54,6 +56,8 @@ ShortCode ShortCode::from_common_code(const std::string &common_code) { return ShortCode(CommonCode(common_code)); } +/// ----------------------------- Basic Functions ----------------------------- + /// NOTE: ensure that input common code is valid! uint32_t ShortCode::fast_encode(uint64_t common_code) { // common code --> short code auto head = common_code >> 32; // head index diff --git a/src/klotski_core/short_code/serialize.cc b/src/klotski_core/short_code/serialize.cc index 428ff99..23519c1 100644 --- a/src/klotski_core/short_code/serialize.cc +++ b/src/klotski_core/short_code/serialize.cc @@ -4,19 +4,14 @@ using klotski::ShortCode; using klotski::ShortCodeException; -/// ShortCode to String +/// --------------------------- ShortCode to String --------------------------- + std::string ShortCode::to_string() const { // encode as 5-bits string - uint32_t short_code = code; - char result[6]; // short code length 5 - result[5] = '\0'; // string ending flag - for (int n = 0; n < 5; ++n) { - result[4 - n] = SHORT_CODE_TABLE[short_code & 0b11111]; // aka _ % 32 - short_code >>= 5; // aka _ / 32 - } - return result; + return string_encode(code); } -/// String to ShortCode +/// --------------------------- String to ShortCode --------------------------- + ShortCode::ShortCode(std::string &&short_code) { code = string_decode(short_code); } @@ -33,6 +28,18 @@ ShortCode ShortCode::from_string(const std::string &short_code) { return ShortCode(short_code); } +/// ----------------------------- Basic Functions ----------------------------- + +std::string klotski::ShortCode::string_encode(uint32_t short_code) { // encode as 5-bits string + char result[6]; // short code length 5 + result[5] = '\0'; // string ending flag + for (int n = 0; n < 5; ++n) { + result[4 - n] = SHORT_CODE_TABLE[short_code & 0b11111]; // aka _ % 32 + short_code >>= 5; // aka _ / 32 + } + return result; +} + uint32_t ShortCode::string_decode(const std::string &short_code) { // 5-bits string decode if (short_code.length() != 5) { // check string length throw ShortCodeException("short code should length 5"); diff --git a/src/klotski_core/short_code/short_code.cc b/src/klotski_core/short_code/short_code.cc index fcb67d0..711253d 100644 --- a/src/klotski_core/short_code/short_code.cc +++ b/src/klotski_core/short_code/short_code.cc @@ -1,6 +1,11 @@ #include "all_cases.h" #include "short_code.h" +using klotski::ShortCode; + +bool ShortCode::fast_mode_available = false; +bool ShortCode::normal_mode_available = false; + namespace std { template<> struct hash { @@ -55,11 +60,6 @@ namespace klotski { } } -using klotski::ShortCode; - -bool ShortCode::fast_mode_available = false; -bool ShortCode::normal_mode_available = false; - bool ShortCode::check(uint32_t short_code) { return short_code < klotski::SHORT_CODE_LIMIT; // 0 ~ (SHORT_CODE_LIMIT - 1) } diff --git a/src/klotski_core/short_code/short_code.h b/src/klotski_core/short_code/short_code.h index 9ba17ea..67c959c 100644 --- a/src/klotski_core/short_code/short_code.h +++ b/src/klotski_core/short_code/short_code.h @@ -85,7 +85,8 @@ namespace klotski { static uint64_t tiny_decode(uint32_t short_code); // short code -> common code static uint32_t tiny_encode(uint64_t common_code); // common code -> short code - static uint32_t string_decode(const std::string &short_code); // string -> short code + static inline std::string string_encode(uint32_t short_code); // short code -> string + static inline uint32_t string_decode(const std::string &short_code); // string -> short code public: /// ShortCode validity check